From 501fc5a15dfd9a1f874d3660cac83f1a5c490e6e Mon Sep 17 00:00:00 2001 From: masaaki Date: Wed, 22 Nov 2023 01:13:03 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20588:=20=E7=94=BB=E9=9D=A2?= =?UTF-8?q?=E5=AE=9F=E8=A3=85=EF=BC=88=E3=82=BF=E3=82=B9=E3=82=AF=E4=B8=80?= =?UTF-8?q?=E8=A6=A7=E7=94=BB=E9=9D=A2=EF=BC=9A=E3=82=BF=E3=82=B9=E3=82=AF?= =?UTF-8?q?=E3=82=AD=E3=83=A3=E3=83=B3=E3=82=BB=E3=83=AB=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3131: 画面実装(タスク一覧画面:タスクキャンセル操作追加)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3131) - タスク 3131: 画面実装(タスク一覧画面:タスクキャンセル操作追加) - タスク一覧に対してCancel Dictationボタンを実装しました ## レビューポイント - タスク関連のほかの処理で実施しているものについて、キャンセルで実施必要か確認いただきたいです。 - キャンセル後のデスクトップアプリ起動 - 不要の認識 - キャンセル前のソート条件保存 - ステータスが変わるため、必要な認識 - ログイン名を取得するためにloginのselectorを使用していますが問題ないか確認いただきたいです (他フィーチャと余計な関連を作るのはあまりよくないと思いつつ、同じような取得処理を作るのも嫌だと思いつつ。。) ## UIの変更 - https://ndstokyo.sharepoint.com/:f:/r/sites/Piranha/Shared%20Documents/General/OMDS/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88/Task3131?csf=1&web=1&e=EdWfPJ ## 動作確認状況 - ローカルで確認実施 ## 補足 - 相談、参考資料などがあれば --- .../src/features/dictation/dictationSlice.ts | 10 +++ .../src/features/dictation/operations.ts | 72 +++++++++++++++++ .../src/pages/DictationPage/index.tsx | 77 +++++++++++++++++++ dictation_client/src/translation/de.json | 7 +- dictation_client/src/translation/en.json | 7 +- dictation_client/src/translation/es.json | 7 +- dictation_client/src/translation/fr.json | 7 +- 7 files changed, 179 insertions(+), 8 deletions(-) diff --git a/dictation_client/src/features/dictation/dictationSlice.ts b/dictation_client/src/features/dictation/dictationSlice.ts index 0775825..66559fb 100644 --- a/dictation_client/src/features/dictation/dictationSlice.ts +++ b/dictation_client/src/features/dictation/dictationSlice.ts @@ -9,6 +9,7 @@ import { listTypistsAsync, playbackAsync, updateAssigneeAsync, + cancelAsync, } from "./operations"; import { SORTABLE_COLUMN, @@ -176,6 +177,15 @@ export const dictationSlice = createSlice({ builder.addCase(playbackAsync.rejected, (state) => { state.apps.isLoading = false; }); + builder.addCase(cancelAsync.pending, (state) => { + state.apps.isLoading = true; + }); + builder.addCase(cancelAsync.fulfilled, (state) => { + state.apps.isLoading = false; + }); + builder.addCase(cancelAsync.rejected, (state) => { + state.apps.isLoading = false; + }); builder.addCase(listBackupPopupTasksAsync.pending, (state) => { state.apps.isBackupListLoading = true; }); diff --git a/dictation_client/src/features/dictation/operations.ts b/dictation_client/src/features/dictation/operations.ts index e7ff81d..b78e67f 100644 --- a/dictation_client/src/features/dictation/operations.ts +++ b/dictation_client/src/features/dictation/operations.ts @@ -355,6 +355,78 @@ export const playbackAsync = createAsyncThunk< } }); +export const cancelAsync = createAsyncThunk< + { + /** empty */ + }, + { + direction: DirectionType; + paramName: SortableColumnType; + audioFileId: number; + isTypist: boolean; + }, + { + // rejectした時の返却値の型 + rejectValue: { + error: ErrorObject; + }; + } +>("dictations/cancelAsync", async (args, thunkApi) => { + const { audioFileId, direction, paramName, isTypist } = args; + + // apiのConfigurationを取得する + const { getState } = thunkApi; + const state = getState() as RootState; + const { configuration } = state.auth; + const accessToken = getAccessToken(state.auth); + const config = new Configuration(configuration); + const tasksApi = new TasksApi(config); + const usersApi = new UsersApi(config); + try { + // ユーザーがタイピストである場合に、ソート条件を保存する + if (isTypist) { + await usersApi.updateSortCriteria( + { direction, paramName }, + { + headers: { authorization: `Bearer ${accessToken}` }, + } + ); + } + await tasksApi.cancel(audioFileId, { + headers: { authorization: `Bearer ${accessToken}` }, + }); + thunkApi.dispatch( + openSnackbar({ + level: "info", + message: getTranslationID("common.message.success"), + }) + ); + return {}; + } catch (e) { + // e ⇒ errorObjectに変換" + const error = createErrorObject(e); + + // ステータスが[Inprogress,Pending]以外、またはタスクが存在しない場合、またはtypistで自分のタスクでない場合 + if (error.code === "E010601" || error.code === "E010603") { + thunkApi.dispatch( + openSnackbar({ + level: "error", + message: getTranslationID("dictationPage.message.cancelFailedError"), + }) + ); + return thunkApi.rejectWithValue({ error }); + } + + thunkApi.dispatch( + openSnackbar({ + level: "error", + message: getTranslationID("common.message.internalServerError"), + }) + ); + return thunkApi.rejectWithValue({ error }); + } +}); + export const listBackupPopupTasksAsync = createAsyncThunk< TasksResponse, { diff --git a/dictation_client/src/pages/DictationPage/index.tsx b/dictation_client/src/pages/DictationPage/index.tsx index 34df912..ce0d896 100644 --- a/dictation_client/src/pages/DictationPage/index.tsx +++ b/dictation_client/src/pages/DictationPage/index.tsx @@ -30,7 +30,9 @@ import { DirectionType, selectIsLoading, playbackAsync, + cancelAsync, } from "features/dictation"; +import { selectUserName } from "features/login/index"; import { getTranslationID } from "translation"; import { Task } from "api/api"; import { isAdminUser, isAuthorUser, isTypistUser } from "features/auth"; @@ -73,6 +75,9 @@ const DictationPage: React.FC = (): JSX.Element => { [dispatch, setIsChangeTranscriptionistPopupOpen] ); + // ログイン中のユーザ名 + const myName = useSelector(selectUserName); + // 各カラムの表示/非表示 const displayColumn = useSelector(selectDisplayInfo); @@ -417,6 +422,57 @@ const DictationPage: React.FC = (): JSX.Element => { ] ); + const onCancel = useCallback( + async (audioFileId: number) => { + if ( + /* eslint-disable-next-line no-alert */ + !window.confirm(t(getTranslationID("common.message.dialogConfirm"))) + ) { + return; + } + const { meta } = await dispatch( + cancelAsync({ + audioFileId, + direction: sortDirection, + paramName: sortableParamName, + isTypist, + }) + ); + if (meta.requestStatus === "fulfilled") { + const filter = getFilter( + filterUploaded, + filterInProgress, + filterPending, + filterFinished, + filterBackup + ); + dispatch( + listTasksAsync({ + limit: LIMIT_TASK_NUM, + offset: 0, + filter, + direction: sortDirection, + paramName: sortableParamName, + }) + ); + dispatch(listTypistsAsync()); + dispatch(listTypistGroupsAsync()); + } + }, + [ + dispatch, + filterBackup, + filterFinished, + filterInProgress, + filterPending, + filterUploaded, + isTypist, + sortDirection, + sortableParamName, + t, + ] + ); + const onCloseBackupPopup = useCallback(() => { setIsBackupPopupOpen(false); }, []); @@ -1056,6 +1112,27 @@ const DictationPage: React.FC = (): JSX.Element => { )} +
  • + {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */} + { + onCancel(x.audioFileId); + }} + > + {t( + getTranslationID( + "dictationPage.label.cancelDictation" + ) + )} + +
  • {t( diff --git a/dictation_client/src/translation/de.json b/dictation_client/src/translation/de.json index b08ae0a..d9594e9 100644 --- a/dictation_client/src/translation/de.json +++ b/dictation_client/src/translation/de.json @@ -203,7 +203,9 @@ "message": { "noPlaybackAuthorization": "Sie haben keine Berechtigung zum Abspielen dieser Datei.", "taskToPlaybackNoExists": "Die Datei kann nicht abgespielt werden, da sie bereits transkribiert wurde oder nicht existiert.", - "taskNotEditable": "Der Transkriptionist kann nicht geändert werden, da die Transkription bereits ausgeführt wird oder die Datei nicht vorhanden ist. Bitte aktualisieren Sie den Bildschirm und prüfen Sie den aktuellen Status." + "taskNotEditable": "Der Transkriptionist kann nicht geändert werden, da die Transkription bereits ausgeführt wird oder die Datei nicht vorhanden ist. Bitte aktualisieren Sie den Bildschirm und prüfen Sie den aktuellen Status.", + "backupFailedError": "(de)ファイルのバックアップに失敗したため処理を中断しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。", + "cancelFailedError": "(de)タスクのキャンセルに失敗しました。画面を更新し、再度ご確認ください。" }, "label": { "title": "Diktate", @@ -247,7 +249,8 @@ "selectedTranscriptionist": "Ausgewählter transkriptionist", "poolTranscriptionist": "Transkriptionsliste", "fileBackup": "(de)File Backup", - "downloadForBackup": "(de)Download for backup" + "downloadForBackup": "(de)Download for backup", + "cancelDictation": "(de)Cancel Dictation" } }, "cardLicenseIssuePopupPage": { diff --git a/dictation_client/src/translation/en.json b/dictation_client/src/translation/en.json index e4426cf..7d9fe63 100644 --- a/dictation_client/src/translation/en.json +++ b/dictation_client/src/translation/en.json @@ -203,7 +203,9 @@ "message": { "noPlaybackAuthorization": "You do not have permission to playback this file.", "taskToPlaybackNoExists": "The file cannot be played because it has already been transcribed or does not exist.", - "taskNotEditable": "The transcriptionist cannot be changed because the transcription is already in progress or the file does not exist. Please refresh the screen and check the latest status." + "taskNotEditable": "The transcriptionist cannot be changed because the transcription is already in progress or the file does not exist. Please refresh the screen and check the latest status.", + "backupFailedError": "ファイルのバックアップに失敗したため処理を中断しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。", + "cancelFailedError": "タスクのキャンセルに失敗しました。画面を更新し、再度ご確認ください。" }, "label": { "title": "Dictations", @@ -247,7 +249,8 @@ "selectedTranscriptionist": "Selected Transcriptionist", "poolTranscriptionist": "Transcription List", "fileBackup": "File Backup", - "downloadForBackup": "Download for backup" + "downloadForBackup": "Download for backup", + "cancelDictation": "Cancel Dictation" } }, "cardLicenseIssuePopupPage": { diff --git a/dictation_client/src/translation/es.json b/dictation_client/src/translation/es.json index ada310b..0cf0ebe 100644 --- a/dictation_client/src/translation/es.json +++ b/dictation_client/src/translation/es.json @@ -203,7 +203,9 @@ "message": { "noPlaybackAuthorization": "No tienes permiso para reproducir este archivo.", "taskToPlaybackNoExists": "El archivo no se puede reproducir porque ya ha sido transcrito o no existe.", - "taskNotEditable": "No se puede cambiar el transcriptor porque la transcripción ya está en curso o el archivo no existe. Actualice la pantalla y verifique el estado más reciente." + "taskNotEditable": "No se puede cambiar el transcriptor porque la transcripción ya está en curso o el archivo no existe. Actualice la pantalla y verifique el estado más reciente.", + "backupFailedError": "(es)ファイルのバックアップに失敗したため処理を中断しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。", + "cancelFailedError": "(es)タスクのキャンセルに失敗しました。画面を更新し、再度ご確認ください。" }, "label": { "title": "Dictado", @@ -247,7 +249,8 @@ "selectedTranscriptionist": "Transcriptor seleccionado", "poolTranscriptionist": "Lista de transcriptor", "fileBackup": "(es)File Backup", - "downloadForBackup": "(es)Download for backup" + "downloadForBackup": "(es)Download for backup", + "cancelDictation": "(es)Cancel Dictation" } }, "cardLicenseIssuePopupPage": { diff --git a/dictation_client/src/translation/fr.json b/dictation_client/src/translation/fr.json index 8285a52..623936d 100644 --- a/dictation_client/src/translation/fr.json +++ b/dictation_client/src/translation/fr.json @@ -203,7 +203,9 @@ "message": { "noPlaybackAuthorization": "Vous n'êtes pas autorisé à lire ce fichier.", "taskToPlaybackNoExists": "Le fichier ne peut pas être lu car il a déjà été transcrit ou n'existe pas.", - "taskNotEditable": "Le transcripteur ne peut pas être changé car la transcription est déjà en cours ou le fichier n'existe pas. Veuillez actualiser l'écran et vérifier le dernier statut." + "taskNotEditable": "Le transcripteur ne peut pas être changé car la transcription est déjà en cours ou le fichier n'existe pas. Veuillez actualiser l'écran et vérifier le dernier statut.", + "backupFailedError": "(fr)ファイルのバックアップに失敗したため処理を中断しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。", + "cancelFailedError": "(fr)タスクのキャンセルに失敗しました。画面を更新し、再度ご確認ください。" }, "label": { "title": "Dictées", @@ -247,7 +249,8 @@ "selectedTranscriptionist": "Transcriptionniste sélectionné", "poolTranscriptionist": "Liste de transcriptionniste", "fileBackup": "(fr)File Backup", - "downloadForBackup": "(fr)Download for backup" + "downloadForBackup": "(fr)Download for backup", + "cancelDictation": "(fr)Cancel Dictation" } }, "cardLicenseIssuePopupPage": {