diff --git a/webapp/channels/src/actions/views/create_comment.tsx b/webapp/channels/src/actions/views/create_comment.tsx index 7f6da89f30..08268e1759 100644 --- a/webapp/channels/src/actions/views/create_comment.tsx +++ b/webapp/channels/src/actions/views/create_comment.tsx @@ -116,6 +116,40 @@ export function submitCommand(channelId: string, rootId: string, draft: PostDraf return {}; }; } +export function submitImmediateCommand(channelId: string, command: string, rootId: string): ActionFuncAsync { + return async (dispatch, getState) => { + const state = getState(); + + const teamId = getCurrentTeamId(state); + + let args = { + channel_id: channelId, + team_id: teamId, + root_id: rootId, + }; + + let message = command; + + const hookResult = await dispatch(runSlashCommandWillBePostedHooks(message, args)); + if (hookResult.error) { + return {error: hookResult.error}; + } else if (!hookResult.data!.message && !hookResult.data!.args) { + // do nothing with an empty return from a hook + return {}; + } + + message = hookResult.data!.message; + args = hookResult.data!.args; + + const {error} = await dispatch(executeCommand(message, args)); + + if (error) { + throw (error); + } + + return {}; + }; +} export function makeOnSubmit(channelId: string, rootId: string, latestPostId: string): (draft: PostDraft, options?: {ignoreSlash?: boolean}) => ActionFuncAsync { return (draft, options = {}) => async (dispatch, getState) => { diff --git a/webapp/channels/src/components/advanced_create_comment/__snapshots__/advanced_create_comment.test.tsx.snap b/webapp/channels/src/components/advanced_create_comment/__snapshots__/advanced_create_comment.test.tsx.snap index 8535d85b79..7469129f5b 100644 --- a/webapp/channels/src/components/advanced_create_comment/__snapshots__/advanced_create_comment.test.tsx.snap +++ b/webapp/channels/src/components/advanced_create_comment/__snapshots__/advanced_create_comment.test.tsx.snap @@ -9,7 +9,14 @@ exports[`components/AdvancedCreateComment should match snapshot when cannot post type={1} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={false} @@ -143,7 +150,14 @@ exports[`components/AdvancedCreateComment should match snapshot, comment with me type={1} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={true} @@ -229,7 +243,14 @@ exports[`components/AdvancedCreateComment should match snapshot, emoji picker di type={1} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={true} @@ -363,7 +384,14 @@ exports[`components/AdvancedCreateComment should match snapshot, empty comment 1 type={1} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={true} @@ -449,7 +477,14 @@ exports[`components/AdvancedCreateComment should match snapshot, non-empty messa type={1} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={true} diff --git a/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.tsx b/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.tsx index bfe59242ed..ee855dbafd 100644 --- a/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.tsx +++ b/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.tsx @@ -11,6 +11,7 @@ import type {ServerError} from '@mattermost/types/errors'; import type {FileInfo} from '@mattermost/types/files'; import {GroupSource} from '@mattermost/types/groups'; import type {Group} from '@mattermost/types/groups'; +import type {Post} from '@mattermost/types/posts'; import type {PreferenceType} from '@mattermost/types/preferences'; import {Posts} from 'mattermost-redux/constants'; @@ -26,6 +27,7 @@ import type {FilePreviewInfo} from 'components/file_preview/file_preview'; import type {FileUpload as FileUploadClass} from 'components/file_upload/file_upload'; import NotifyConfirmModal from 'components/notify_confirm_modal'; import PostDeletedModal from 'components/post_deleted_modal'; +import Poll from 'components/post_poll/'; import ScheduledIndicator, {ScheduledIndicatorType} from 'components/schedule_post/scheduled_indicator'; import type {TextboxClass, TextboxElement} from 'components/textbox'; @@ -1172,7 +1174,14 @@ class AdvancedCreateComment extends React.PureComponent { setDraftAsPostType={this.setDraftAsPostType} isSchedulable={true} handleSchedulePost={this.handleSchedulePost} - additionalControls={pluginItems.filter(Boolean)} + additionalControls={[ + , + ...(pluginItems || []), + ].filter(Boolean)} codeBlockOnCtrlEnter={this.props.codeBlockOnCtrlEnter} ctrlSend={this.props.ctrlSend} loadNextMessage={this.loadNextMessage} diff --git a/webapp/channels/src/components/advanced_create_post/__snapshots__/advanced_create_post.test.tsx.snap b/webapp/channels/src/components/advanced_create_post/__snapshots__/advanced_create_post.test.tsx.snap index 6501b57e94..d047cec32f 100644 --- a/webapp/channels/src/components/advanced_create_post/__snapshots__/advanced_create_post.test.tsx.snap +++ b/webapp/channels/src/components/advanced_create_post/__snapshots__/advanced_create_post.test.tsx.snap @@ -12,7 +12,13 @@ exports[`components/advanced_create_post Show tutorial 1`] = ` type={0} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={true} @@ -123,7 +129,13 @@ exports[`components/advanced_create_post should match snapshot for center textbo type={0} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={true} @@ -234,7 +246,13 @@ exports[`components/advanced_create_post should match snapshot when cannot post type={0} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={false} @@ -345,7 +363,13 @@ exports[`components/advanced_create_post should match snapshot when file upload type={0} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={true} @@ -456,7 +480,13 @@ exports[`components/advanced_create_post should match snapshot, can post; previe type={0} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={true} @@ -567,7 +597,13 @@ exports[`components/advanced_create_post should match snapshot, can post; previe type={0} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={true} @@ -678,7 +714,13 @@ exports[`components/advanced_create_post should match snapshot, cannot post; pre type={0} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={false} @@ -789,7 +831,13 @@ exports[`components/advanced_create_post should match snapshot, cannot post; pre type={0} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={false} @@ -900,7 +948,13 @@ exports[`components/advanced_create_post should match snapshot, init 1`] = ` type={0} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={true} @@ -1011,7 +1065,13 @@ exports[`components/advanced_create_post should match snapshot, post priority di type={0} /> , + ] + } applyMarkdown={[Function]} badConnection={false} canPost={true} @@ -1134,6 +1194,9 @@ exports[`components/advanced_create_post should match snapshot, post priority en onApply={[Function]} onClose={[Function]} />, + , ] } applyMarkdown={[Function]} @@ -1258,6 +1321,9 @@ exports[`components/advanced_create_post should match snapshot, post priority en } } />, + , ] } applyMarkdown={[Function]} diff --git a/webapp/channels/src/components/advanced_create_post/advanced_create_post.tsx b/webapp/channels/src/components/advanced_create_post/advanced_create_post.tsx index 1bbf8119cc..3412d470b4 100644 --- a/webapp/channels/src/components/advanced_create_post/advanced_create_post.tsx +++ b/webapp/channels/src/components/advanced_create_post/advanced_create_post.tsx @@ -30,6 +30,7 @@ import type {FilePreviewInfo} from 'components/file_preview/file_preview'; import type {FileUpload as FileUploadClass} from 'components/file_upload/file_upload'; import NotifyConfirmModal from 'components/notify_confirm_modal'; import PersistNotificationConfirmModal from 'components/persist_notification_confirm_modal'; +import Poll from 'components/post_poll'; import PostPriorityPickerOverlay from 'components/post_priority/post_priority_picker_overlay'; import ResetStatusModal from 'components/reset_status_modal'; import ScheduledIndicator, {ScheduledIndicatorType} from 'components/schedule_post/scheduled_indicator'; @@ -1563,6 +1564,10 @@ class AdvancedCreatePost extends React.PureComponent { disabled={this.props.shouldShowPreview} /> ), + , ...(pluginItems || []), ].filter(Boolean)} codeBlockOnCtrlEnter={this.props.codeBlockOnCtrlEnter} diff --git a/webapp/channels/src/components/post_poll/index.ts b/webapp/channels/src/components/post_poll/index.ts new file mode 100644 index 0000000000..e78a13fe13 --- /dev/null +++ b/webapp/channels/src/components/post_poll/index.ts @@ -0,0 +1,29 @@ +import {connect} from 'react-redux'; +import type {Dispatch} from 'redux'; +import {bindActionCreators} from 'redux'; + +import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels'; + +import {submitImmediateCommand} from 'actions/views/create_comment'; + +import type {GlobalState} from 'types/store'; + +import Poll from './poll'; + +function mapStateToProps(state: GlobalState) { + const currentChannelId = getCurrentChannelId(state); + + return { + currentChannelId, + }; +} + +function mapDispatchToProps(dispatch: Dispatch) { + return { + actions: bindActionCreators({ + submitImmediateCommand, + }, dispatch), + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(Poll); diff --git a/webapp/channels/src/components/post_poll/poll.tsx b/webapp/channels/src/components/post_poll/poll.tsx new file mode 100644 index 0000000000..be8c6a08c6 --- /dev/null +++ b/webapp/channels/src/components/post_poll/poll.tsx @@ -0,0 +1,64 @@ +import {ChartBarIcon} from '@infomaniak/compass-icons/components'; +import React, {memo, useCallback} from 'react'; +import {useIntl} from 'react-intl'; + +import {IconContainer} from 'components/advanced_text_editor/formatting_bar/formatting_icon'; +import useTooltip from 'components/common/hooks/useTooltip'; + +type Props = { + rootId?: string; + disabled: boolean; + currentChannelId: string; + actions: + { submitImmediateCommand: (channelId: string, command: string, rootId: string) => void}; + +}; + +function Poll({ + disabled, + currentChannelId, + actions: {submitImmediateCommand}, + rootId, +}: Props) { + const {formatMessage} = useIntl(); + + const pollMessage = formatMessage({id: 'shortcuts.msgs.formatting_bar.poll', defaultMessage: 'Lancer un sondage'}); + const { + setReference: setTooltipRef, + getReferenceProps: getTooltipReferenceProps, + tooltip, + } = useTooltip({ + placement: 'top', + message: pollMessage, + }); + + const handleClick = useCallback(() => { + submitImmediateCommand(currentChannelId, '/poll', rootId ?? ''); + }, [currentChannelId, submitImmediateCommand]); + + return ( + <> +
+ + + +
+ + {tooltip} + + ); +} + +export default memo(Poll); diff --git a/webapp/channels/src/i18n/de.json b/webapp/channels/src/i18n/de.json index f1bf5a15b8..576778de48 100644 --- a/webapp/channels/src/i18n/de.json +++ b/webapp/channels/src/i18n/de.json @@ -4424,7 +4424,7 @@ "move_thread_modal.title": "Unterhaltung verschieben", "msg_typing.areTyping": "{users} und {last} tippen gerade...", "msg_typing.isTyping": "{user} tippt...", - "msg_recording.isRecording" : "{user} nimmt auf..", + "msg_recording.isRecording" : "{user} nimmt auf..", "msg_recording.areRecording": "{users} und {last} nehmen auf...", "multiselect.add": "Hinzufügen", "multiselect.addChannelsPlaceholder": "Kanäle suchen und hinzufügen", @@ -5193,6 +5193,7 @@ "shortcuts.msgs.reprint_next.mac": "Nächste Nachricht wiederholen:\t⌘|Abwärts", "shortcuts.msgs.reprint_prev": "Vorherige Nachricht wiederholen:\tStrg|Aufwärts", "shortcuts.msgs.reprint_prev.mac": "Vorherige Nachricht wiederholen:\t⌘|Aufwärts", + "shortcuts.msgs.formatting_bar.poll": "Eine Umfrage starten", "shortcuts.msgs.search.header": "Suche", "shortcuts.msgs.search_channel": "Im Kanal:\tStrg|F", "shortcuts.msgs.search_channel.mac": "Im Kanal:\t⌘|F", diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index d7f58939b9..e8dcfe264e 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -5154,6 +5154,7 @@ "shortcuts.msgs.reprint_next.mac": "Reprint next message:\t⌘|Down", "shortcuts.msgs.reprint_prev": "Reprint previous message:\tCtrl|Up", "shortcuts.msgs.reprint_prev.mac": "Reprint previous message:\t⌘|Up", + "shortcuts.msgs.formatting_bar.poll": "Launch a poll", "shortcuts.msgs.search_channel": "In channel:\tCtrl|F", "shortcuts.msgs.search_channel.mac": "In channel:\t⌘|F", "shortcuts.msgs.search.header": "Searching", diff --git a/webapp/channels/src/i18n/es.json b/webapp/channels/src/i18n/es.json index 21a352ce13..296b86c85f 100644 --- a/webapp/channels/src/i18n/es.json +++ b/webapp/channels/src/i18n/es.json @@ -2604,8 +2604,8 @@ "apps.suggestion.no_dynamic": "No se han devuelto datos para las sugerencias dinámicas", "apps.suggestion.no_static": "No hay opciones que coincidan.", "apps.suggestion.no_suggestion": "No hay sugerencias que coincidan.", - "appstore.bar": "Su versión de la aplicación ya no es compatible. Por favor", - "appstore.bar.end": "antes del 2 de septiembre para beneficiarse de las últimas mejoras.", + "appstore.bar": "Su versión de la aplicación ya no es compatible. Por favor", + "appstore.bar.end": "antes del 2 de septiembre para beneficiarse de las últimas mejoras.", "appstore.bar.update": "instalar la nueva versión", "archivedChannelMessage": "Estás viendo un **canal archivado**. No serán publicados nuevos mensajes.", "atmos/camo": "atmos/camo", @@ -3798,7 +3798,7 @@ "more_direct_channels.title": "Mensajes Directos", "msg_typing.areTyping": "{users} y {last} están escribiendo...", "msg_typing.isTyping": "{user} está escribiendo...", - "msg_recording.isRecording" : "{user} está grabando...", + "msg_recording.isRecording" : "{user} está grabando...", "msg_recording.areRecording": "{users} et {last} están grabando...", "multiselect.add": "Agregar", "multiselect.addChannelsPlaceholder": "Buscar y agregar canales", @@ -4272,6 +4272,7 @@ "shortcuts.msgs.reprint_next.mac": "Vuelve a imprimir el siguiente mensaje:\t⌘|Abajo", "shortcuts.msgs.reprint_prev": "Vuelve a imprimir el mensaje anterior:\tCtrl|Arriba", "shortcuts.msgs.reprint_prev.mac": "Vuelve a imprimir el mensaje anterior:\t⌘|Arriba", + "shortcuts.msgs.formatting_bar.poll": "Lanzar una encuesta", "shortcuts.msgs.search.header": "Búsqueda", "shortcuts.nav.direct_messages_menu": "Menú de mensajes directos:\tCtrl|Shift|K", "shortcuts.nav.direct_messages_menu.mac": "Menú de mensajes directos:\t⌘|Shift|K", diff --git a/webapp/channels/src/i18n/fr.json b/webapp/channels/src/i18n/fr.json index b2a32f8f9b..5917df42b5 100644 --- a/webapp/channels/src/i18n/fr.json +++ b/webapp/channels/src/i18n/fr.json @@ -3737,7 +3737,7 @@ "more_direct_channels.title": "Messages personnels", "msg_typing.areTyping": "{users} et {last} sont en train d'écrire...", "msg_typing.isTyping": "{user} est en train d'écrire...", - "msg_recording.isRecording" : "{user} est en train d'enregistrer...", + "msg_recording.isRecording" : "{user} est en train d'enregistrer...", "msg_recording.areRecording": "{users} et {last} sont en train d'enregistrer...", "multiselect.add": "Ajouter", "multiselect.addChannelsPlaceholder": "Rechercher et ajouter des canaux", @@ -4204,6 +4204,7 @@ "shortcuts.msgs.reprint_next.mac": "Affiche à nouveau le message suivant :\t⌘|Bas", "shortcuts.msgs.reprint_prev": "Affiche à nouveau le message précédent :\tCtrl|Haut", "shortcuts.msgs.reprint_prev.mac": "Affiche à nouveau le message précédent :\t⌘|Haut", + "shortcuts.msgs.formatting_bar.poll": "Lancer un sondage", "shortcuts.nav.direct_messages_menu": "Menu des messages personnels :\tCtrl|Maj|K", "shortcuts.nav.direct_messages_menu.mac": "Menu des messages personnels :\t⌘|Maj|K", "shortcuts.nav.expand_sidebar": "Agrandir la barre latérale droite :\tCtrl|Shift|.", diff --git a/webapp/channels/src/i18n/it.json b/webapp/channels/src/i18n/it.json index b1869da4d8..c78797449d 100644 --- a/webapp/channels/src/i18n/it.json +++ b/webapp/channels/src/i18n/it.json @@ -2902,7 +2902,7 @@ "more_direct_channels.title": "Messaggio Privato", "msg_typing.areTyping": "{users} e {last} stanno scrivendo...", "msg_typing.isTyping": "{user} sta scrivendo...", - "msg_recording.isRecording" : "{user} sta registrando", + "msg_recording.isRecording" : "{user} sta registrando", "msg_recording.areRecording": "{users} et {last} stanno registrando...", "multiselect.add": "Aggiungi", "multiselect.addChannelsPlaceholder": "Cerca e aggiungi canali", @@ -3234,6 +3234,7 @@ "shortcuts.msgs.reprint_next.mac": "Ristampa il prossimo messaggio:\t⌘|Down", "shortcuts.msgs.reprint_prev": "Ristampa il messaggio precedente:\tCtrl|Up", "shortcuts.msgs.reprint_prev.mac": "Ristampa il messaggio precedente:\t⌘|Up", + "shortcuts.msgs.formatting_bar.poll": "Avvia un sondaggio", "shortcuts.nav.direct_messages_menu": "Menu messaggio diretto:\tCtrl|Shift|K", "shortcuts.nav.direct_messages_menu.mac": "Menu messaggio diretto:\t⌘|Shift|K", "shortcuts.nav.focus_center": "Seleziona campo di immissione:\tCtrl|Shift|L", diff --git a/webapp/channels/src/images/poll_bot_default_icon.png b/webapp/channels/src/images/poll_bot_default_icon.png new file mode 100644 index 0000000000..bcc0b3a78a Binary files /dev/null and b/webapp/channels/src/images/poll_bot_default_icon.png differ diff --git a/webapp/channels/webpack.config.js b/webapp/channels/webpack.config.js index 9c1979893c..619697e532 100644 --- a/webapp/channels/webpack.config.js +++ b/webapp/channels/webpack.config.js @@ -252,6 +252,7 @@ var config = { {from: 'src/images/only_office_slide_logo.png', to: 'images'}, {from: 'src/images/only_office_word_logo.png', to: 'images'}, {from: 'src/images/bot_default_icon.png', to: 'images'}, + {from: 'src/images/poll_bot_default_icon.png', to: 'images'}, {from: 'src/images/chat_gpt.png', to: 'images'}, {from: 'src/images/payment_processing.png', to: 'images'}, {from: 'src/images/purchase_alert.png', to: 'images'},