Merged PR 202: 画面実装(PlayBackボタン)
## 概要 [Task1997: 画面実装(PlayBackボタン)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1997) - Playbackボタン押下時の挙動を実装 - typist - 自身が割り当て候補となっているタスクをPlayBackする - 成功時、カスタムURLスキームでデスクトップアプリを起動する - author - 自身のAuthorIDと一致するタスクをPlayBackする - 成功時、カスタムURLスキームでデスクトップアプリを起動する - ログイン時の、カスタムURLスキームを実際のデスクトップアプリのスキーム名に修正 ## レビューポイント - playbackAsyncのなかでソート条件更新APIを一緒に呼び出しているが問題ないか - ソート条件を更新するタイミングはここで問題ないか - ユーザーがTypistの時のみ更新するようにしたが問題ないか ## 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/Task1997?csf=1&web=1&e=9kLaxo ## 動作確認状況 - ローカルで確認 ## 補足 - Authorの挙動はAPI側の実装が完了していないので、未確認
This commit is contained in:
parent
d6db89bc2c
commit
3a7bf60f3e
@ -2,3 +2,4 @@ VITE_STAGE=develop
|
|||||||
VITE_B2C_CLIENTID=5eb34cba-84b6-46f9-a0ea-bc5c41157d63
|
VITE_B2C_CLIENTID=5eb34cba-84b6-46f9-a0ea-bc5c41157d63
|
||||||
VITE_B2C_AUTHORITY=https://adb2codmsdev.b2clogin.com/adb2codmsdev.onmicrosoft.com/b2c_1_signin_dev
|
VITE_B2C_AUTHORITY=https://adb2codmsdev.b2clogin.com/adb2codmsdev.onmicrosoft.com/b2c_1_signin_dev
|
||||||
VITE_B2C_KNOWNAUTHORITIES=adb2codmsdev.b2clogin.com
|
VITE_B2C_KNOWNAUTHORITIES=adb2codmsdev.b2clogin.com
|
||||||
|
VITE_DESK_TOP_APP_SCHEME=odms-desktopapp
|
||||||
@ -2,3 +2,4 @@ VITE_STAGE=local
|
|||||||
VITE_B2C_CLIENTID=XXXX-XXXX-XXXXX-XXXX
|
VITE_B2C_CLIENTID=XXXX-XXXX-XXXXX-XXXX
|
||||||
VITE_B2C_AUTHORITY=https://adb2XXXX.XXXX.com/adb2XXXX.onmicrosoft.com/XXXX
|
VITE_B2C_AUTHORITY=https://adb2XXXX.XXXX.com/adb2XXXX.onmicrosoft.com/XXXX
|
||||||
VITE_B2C_KNOWNAUTHORITIES=adb2cXXXX.XXXx.com
|
VITE_B2C_KNOWNAUTHORITIES=adb2cXXXX.XXXx.com
|
||||||
|
VITE_DESK_TOP_APP_SCHEME=odms-desktopapp
|
||||||
@ -2,3 +2,4 @@ VITE_STAGE=staging
|
|||||||
VITE_B2C_CLIENTID=5d8f0db9-4506-41d6-a5bb-5ec39f6eba8d
|
VITE_B2C_CLIENTID=5d8f0db9-4506-41d6-a5bb-5ec39f6eba8d
|
||||||
VITE_B2C_AUTHORITY=https://adb2codmsstg.b2clogin.com/adb2codmsstg.onmicrosoft.com/b2c_1_signin_stg
|
VITE_B2C_AUTHORITY=https://adb2codmsstg.b2clogin.com/adb2codmsstg.onmicrosoft.com/b2c_1_signin_stg
|
||||||
VITE_B2C_KNOWNAUTHORITIES=adb2codmsstg.b2clogin.com
|
VITE_B2C_KNOWNAUTHORITIES=adb2codmsstg.b2clogin.com
|
||||||
|
VITE_DESK_TOP_APP_SCHEME=odms-desktopapp
|
||||||
@ -2408,7 +2408,7 @@ export const TasksApiAxiosParamCreator = function (configuration?: Configuration
|
|||||||
/**
|
/**
|
||||||
* 指定した文字起こしタスクのチェックアウト候補を変更します。
|
* 指定した文字起こしタスクのチェックアウト候補を変更します。
|
||||||
* @summary
|
* @summary
|
||||||
* @param {number} audioFileId
|
* @param {number} audioFileId ODMS Cloud上の音声ファイルID
|
||||||
* @param {PostCheckoutPermissionRequest} postCheckoutPermissionRequest
|
* @param {PostCheckoutPermissionRequest} postCheckoutPermissionRequest
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@ -2736,7 +2736,7 @@ export const TasksApiFp = function(configuration?: Configuration) {
|
|||||||
/**
|
/**
|
||||||
* 指定した文字起こしタスクのチェックアウト候補を変更します。
|
* 指定した文字起こしタスクのチェックアウト候補を変更します。
|
||||||
* @summary
|
* @summary
|
||||||
* @param {number} audioFileId
|
* @param {number} audioFileId ODMS Cloud上の音声ファイルID
|
||||||
* @param {PostCheckoutPermissionRequest} postCheckoutPermissionRequest
|
* @param {PostCheckoutPermissionRequest} postCheckoutPermissionRequest
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@ -2848,7 +2848,7 @@ export const TasksApiFactory = function (configuration?: Configuration, basePath
|
|||||||
/**
|
/**
|
||||||
* 指定した文字起こしタスクのチェックアウト候補を変更します。
|
* 指定した文字起こしタスクのチェックアウト候補を変更します。
|
||||||
* @summary
|
* @summary
|
||||||
* @param {number} audioFileId
|
* @param {number} audioFileId ODMS Cloud上の音声ファイルID
|
||||||
* @param {PostCheckoutPermissionRequest} postCheckoutPermissionRequest
|
* @param {PostCheckoutPermissionRequest} postCheckoutPermissionRequest
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@ -2957,7 +2957,7 @@ export class TasksApi extends BaseAPI {
|
|||||||
/**
|
/**
|
||||||
* 指定した文字起こしタスクのチェックアウト候補を変更します。
|
* 指定した文字起こしタスクのチェックアウト候補を変更します。
|
||||||
* @summary
|
* @summary
|
||||||
* @param {number} audioFileId
|
* @param {number} audioFileId ODMS Cloud上の音声ファイルID
|
||||||
* @param {PostCheckoutPermissionRequest} postCheckoutPermissionRequest
|
* @param {PostCheckoutPermissionRequest} postCheckoutPermissionRequest
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@ -3163,7 +3163,7 @@ export const UsersApiAxiosParamCreator = function (configuration?: Configuration
|
|||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
getSortCcriteria: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
getSortCriteria: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
const localVarPath = `/users/sort-criteria`;
|
const localVarPath = `/users/sort-criteria`;
|
||||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
@ -3272,9 +3272,9 @@ export const UsersApiAxiosParamCreator = function (configuration?: Configuration
|
|||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
updateSortCcriteria: async (postSortCriteriaRequest: PostSortCriteriaRequest, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
updateSortCriteria: async (postSortCriteriaRequest: PostSortCriteriaRequest, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
// verify required parameter 'postSortCriteriaRequest' is not null or undefined
|
// verify required parameter 'postSortCriteriaRequest' is not null or undefined
|
||||||
assertParamExists('updateSortCcriteria', 'postSortCriteriaRequest', postSortCriteriaRequest)
|
assertParamExists('updateSortCriteria', 'postSortCriteriaRequest', postSortCriteriaRequest)
|
||||||
const localVarPath = `/users/sort-criteria`;
|
const localVarPath = `/users/sort-criteria`;
|
||||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
@ -3353,8 +3353,8 @@ export const UsersApiFp = function(configuration?: Configuration) {
|
|||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async getSortCcriteria(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<GetSortCriteriaResponse>> {
|
async getSortCriteria(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<GetSortCriteriaResponse>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getSortCcriteria(options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.getSortCriteria(options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -3385,8 +3385,8 @@ export const UsersApiFp = function(configuration?: Configuration) {
|
|||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async updateSortCcriteria(postSortCriteriaRequest: PostSortCriteriaRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<object>> {
|
async updateSortCriteria(postSortCriteriaRequest: PostSortCriteriaRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<object>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.updateSortCcriteria(postSortCriteriaRequest, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.updateSortCriteria(postSortCriteriaRequest, options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -3434,8 +3434,8 @@ export const UsersApiFactory = function (configuration?: Configuration, basePath
|
|||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
getSortCcriteria(options?: any): AxiosPromise<GetSortCriteriaResponse> {
|
getSortCriteria(options?: any): AxiosPromise<GetSortCriteriaResponse> {
|
||||||
return localVarFp.getSortCcriteria(options).then((request) => request(axios, basePath));
|
return localVarFp.getSortCriteria(options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -3463,8 +3463,8 @@ export const UsersApiFactory = function (configuration?: Configuration, basePath
|
|||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
updateSortCcriteria(postSortCriteriaRequest: PostSortCriteriaRequest, options?: any): AxiosPromise<object> {
|
updateSortCriteria(postSortCriteriaRequest: PostSortCriteriaRequest, options?: any): AxiosPromise<object> {
|
||||||
return localVarFp.updateSortCcriteria(postSortCriteriaRequest, options).then((request) => request(axios, basePath));
|
return localVarFp.updateSortCriteria(postSortCriteriaRequest, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -3518,8 +3518,8 @@ export class UsersApi extends BaseAPI {
|
|||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
* @memberof UsersApi
|
* @memberof UsersApi
|
||||||
*/
|
*/
|
||||||
public getSortCcriteria(options?: AxiosRequestConfig) {
|
public getSortCriteria(options?: AxiosRequestConfig) {
|
||||||
return UsersApiFp(this.configuration).getSortCcriteria(options).then((request) => request(this.axios, this.basePath));
|
return UsersApiFp(this.configuration).getSortCriteria(options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3553,8 +3553,8 @@ export class UsersApi extends BaseAPI {
|
|||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
* @memberof UsersApi
|
* @memberof UsersApi
|
||||||
*/
|
*/
|
||||||
public updateSortCcriteria(postSortCriteriaRequest: PostSortCriteriaRequest, options?: AxiosRequestConfig) {
|
public updateSortCriteria(postSortCriteriaRequest: PostSortCriteriaRequest, options?: AxiosRequestConfig) {
|
||||||
return UsersApiFp(this.configuration).updateSortCcriteria(postSortCriteriaRequest, options).then((request) => request(this.axios, this.basePath));
|
return UsersApiFp(this.configuration).updateSortCriteria(postSortCriteriaRequest, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,5 +25,6 @@ export const errorCodes = [
|
|||||||
"E010301", // メールアドレス登録済みエラー
|
"E010301", // メールアドレス登録済みエラー
|
||||||
"E010302", // authorId重複エラー
|
"E010302", // authorId重複エラー
|
||||||
"E010401", // PONumber重複エラー
|
"E010401", // PONumber重複エラー
|
||||||
"E010601", // タスク変更不可エラー
|
"E010601", // タスク変更不可エラー(タスクが変更できる状態でない、またはタスクが存在しない)
|
||||||
|
"E010602", // タスク変更権限不足エラー
|
||||||
] as const;
|
] as const;
|
||||||
|
|||||||
@ -79,3 +79,16 @@ export const isAuthorUser = (): boolean => {
|
|||||||
}
|
}
|
||||||
return token.role.includes(USER_ROLES.AUTHOR);
|
return token.role.includes(USER_ROLES.AUTHOR);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is author user ログインしているユーザがAuthorかどうかを返す
|
||||||
|
* @returns bool
|
||||||
|
*/
|
||||||
|
export const isTypistUser = (): boolean => {
|
||||||
|
const jwt = loadAccessToken();
|
||||||
|
const token = jwt ? decodeToken(jwt) : null;
|
||||||
|
if (!token) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return token.role.includes(USER_ROLES.TYPIST);
|
||||||
|
};
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
listTasksAsync,
|
listTasksAsync,
|
||||||
listTypistGroupsAsync,
|
listTypistGroupsAsync,
|
||||||
listTypistsAsync,
|
listTypistsAsync,
|
||||||
|
playbackAsync,
|
||||||
updateAssigneeAsync,
|
updateAssigneeAsync,
|
||||||
} from "./operations";
|
} from "./operations";
|
||||||
import {
|
import {
|
||||||
@ -131,6 +132,15 @@ export const dictationSlice = createSlice({
|
|||||||
builder.addCase(updateAssigneeAsync.rejected, (state) => {
|
builder.addCase(updateAssigneeAsync.rejected, (state) => {
|
||||||
state.apps.isLoading = false;
|
state.apps.isLoading = false;
|
||||||
});
|
});
|
||||||
|
builder.addCase(playbackAsync.pending, (state) => {
|
||||||
|
state.apps.isLoading = true;
|
||||||
|
});
|
||||||
|
builder.addCase(playbackAsync.fulfilled, (state) => {
|
||||||
|
state.apps.isLoading = false;
|
||||||
|
});
|
||||||
|
builder.addCase(playbackAsync.rejected, (state) => {
|
||||||
|
state.apps.isLoading = false;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -94,7 +94,7 @@ export const getSortColumnAsync = createAsyncThunk<
|
|||||||
const usersApi = new UsersApi(config);
|
const usersApi = new UsersApi(config);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const sort = await usersApi.getSortCcriteria({
|
const sort = await usersApi.getSortCriteria({
|
||||||
headers: { authorization: `Bearer ${accessToken}` },
|
headers: { authorization: `Bearer ${accessToken}` },
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -125,52 +125,6 @@ export const getSortColumnAsync = createAsyncThunk<
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const updateSortColumnAsync = createAsyncThunk<
|
|
||||||
{
|
|
||||||
/** empty */
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// パラメータ
|
|
||||||
direction: DirectionType;
|
|
||||||
paramName: SortableColumnType;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// rejectした時の返却値の型
|
|
||||||
rejectValue: {
|
|
||||||
error: ErrorObject;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
>("dictations/updateSortColumnAsync", async (args, thunkApi) => {
|
|
||||||
const { direction, paramName } = args;
|
|
||||||
|
|
||||||
// apiのConfigurationを取得する
|
|
||||||
const { getState } = thunkApi;
|
|
||||||
const state = getState() as RootState;
|
|
||||||
const { configuration, accessToken } = state.auth;
|
|
||||||
const config = new Configuration(configuration);
|
|
||||||
const usersApi = new UsersApi(config);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await usersApi.updateSortCcriteria(
|
|
||||||
{ direction, paramName },
|
|
||||||
{
|
|
||||||
headers: { authorization: `Bearer ${accessToken}` },
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return {};
|
|
||||||
} catch (e) {
|
|
||||||
// e ⇒ errorObjectに変換"
|
|
||||||
const error = createErrorObject(e);
|
|
||||||
thunkApi.dispatch(
|
|
||||||
openSnackbar({
|
|
||||||
level: "error",
|
|
||||||
message: getTranslationID("common.message.internalServerError"),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
return thunkApi.rejectWithValue({ error });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const listTypistsAsync = createAsyncThunk<
|
export const listTypistsAsync = createAsyncThunk<
|
||||||
GetTypistsResponse,
|
GetTypistsResponse,
|
||||||
void,
|
void,
|
||||||
@ -275,6 +229,12 @@ export const updateAssigneeAsync = createAsyncThunk<
|
|||||||
headers: { authorization: `Bearer ${accessToken}` },
|
headers: { authorization: `Bearer ${accessToken}` },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
thunkApi.dispatch(
|
||||||
|
openSnackbar({
|
||||||
|
level: "info",
|
||||||
|
message: getTranslationID("common.message.success"),
|
||||||
|
})
|
||||||
|
);
|
||||||
return {};
|
return {};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// e ⇒ errorObjectに変換"
|
// e ⇒ errorObjectに変換"
|
||||||
@ -300,3 +260,88 @@ export const updateAssigneeAsync = createAsyncThunk<
|
|||||||
return thunkApi.rejectWithValue({ error });
|
return thunkApi.rejectWithValue({ error });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const playbackAsync = createAsyncThunk<
|
||||||
|
{
|
||||||
|
/** empty */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
direction: DirectionType;
|
||||||
|
paramName: SortableColumnType;
|
||||||
|
audioFileId: number;
|
||||||
|
isTypist: boolean;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// rejectした時の返却値の型
|
||||||
|
rejectValue: {
|
||||||
|
error: ErrorObject;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
>("dictations/playbackAsync", async (args, thunkApi) => {
|
||||||
|
const { audioFileId, direction, paramName, isTypist } = args;
|
||||||
|
|
||||||
|
// apiのConfigurationを取得する
|
||||||
|
const { getState } = thunkApi;
|
||||||
|
const state = getState() as RootState;
|
||||||
|
const { configuration, accessToken } = 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.checkout(audioFileId, {
|
||||||
|
headers: { authorization: `Bearer ${accessToken}` },
|
||||||
|
});
|
||||||
|
thunkApi.dispatch(
|
||||||
|
openSnackbar({
|
||||||
|
level: "info",
|
||||||
|
message: getTranslationID("common.message.success"),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return {};
|
||||||
|
} catch (e) {
|
||||||
|
// e ⇒ errorObjectに変換"
|
||||||
|
const error = createErrorObject(e);
|
||||||
|
|
||||||
|
// ステータスが[Uploaded,Inprogress,Pending]以外、またはタスクが存在しない場合
|
||||||
|
if (error.code === "E010601") {
|
||||||
|
thunkApi.dispatch(
|
||||||
|
openSnackbar({
|
||||||
|
level: "error",
|
||||||
|
message: getTranslationID(
|
||||||
|
"dictationPage.message.taskToPlaybackNoExists"
|
||||||
|
),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return thunkApi.rejectWithValue({ error });
|
||||||
|
}
|
||||||
|
// タスクをチェックアウトする権限がない
|
||||||
|
if (error.code === "E010602") {
|
||||||
|
thunkApi.dispatch(
|
||||||
|
openSnackbar({
|
||||||
|
level: "error",
|
||||||
|
message: getTranslationID(
|
||||||
|
"dictationPage.message.noPlaybackAuthorization"
|
||||||
|
),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return thunkApi.rejectWithValue({ error });
|
||||||
|
}
|
||||||
|
|
||||||
|
thunkApi.dispatch(
|
||||||
|
openSnackbar({
|
||||||
|
level: "error",
|
||||||
|
message: getTranslationID("common.message.internalServerError"),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return thunkApi.rejectWithValue({ error });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@ -23,17 +23,17 @@ import {
|
|||||||
changeParamName,
|
changeParamName,
|
||||||
changeDirection,
|
changeDirection,
|
||||||
changeSelectedTask,
|
changeSelectedTask,
|
||||||
updateSortColumnAsync,
|
|
||||||
SortableColumnType,
|
SortableColumnType,
|
||||||
changeAssignee,
|
changeAssignee,
|
||||||
listTypistsAsync,
|
listTypistsAsync,
|
||||||
listTypistGroupsAsync,
|
listTypistGroupsAsync,
|
||||||
DirectionType,
|
DirectionType,
|
||||||
selectIsLoading,
|
selectIsLoading,
|
||||||
|
playbackAsync,
|
||||||
} from "features/dictation";
|
} from "features/dictation";
|
||||||
import { getTranslationID } from "translation";
|
import { getTranslationID } from "translation";
|
||||||
import { Task } from "api/api";
|
import { Task } from "api/api";
|
||||||
import { isAdminUser, isAuthorUser } from "features/auth/utils";
|
import { isAdminUser, isAuthorUser, isTypistUser } from "features/auth/utils";
|
||||||
import { STATUS, LIMIT_TASK_NUM } from "../../features/dictation";
|
import { STATUS, LIMIT_TASK_NUM } from "../../features/dictation";
|
||||||
import uploaded from "../../assets/images/uploaded.svg";
|
import uploaded from "../../assets/images/uploaded.svg";
|
||||||
import pending from "../../assets/images/pending.svg";
|
import pending from "../../assets/images/pending.svg";
|
||||||
@ -51,6 +51,7 @@ const DictationPage: React.FC = (): JSX.Element => {
|
|||||||
|
|
||||||
const isAdmin = isAdminUser();
|
const isAdmin = isAdminUser();
|
||||||
const isAuthor = isAuthorUser();
|
const isAuthor = isAuthorUser();
|
||||||
|
const isTypist = isTypistUser();
|
||||||
// popup制御関係
|
// popup制御関係
|
||||||
const [
|
const [
|
||||||
isChangeTranscriptionistPopupOpen,
|
isChangeTranscriptionistPopupOpen,
|
||||||
@ -316,14 +317,65 @@ const DictationPage: React.FC = (): JSX.Element => {
|
|||||||
[dispatch, sortDirection, sortableParamName]
|
[dispatch, sortDirection, sortableParamName]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onPlayBack = useCallback(() => {
|
const onPlayBack = useCallback(
|
||||||
|
async (audioFileId: number) => {
|
||||||
|
if (
|
||||||
|
/* eslint-disable-next-line no-alert */
|
||||||
|
!window.confirm(t(getTranslationID("common.message.dialogConfirm")))
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { meta } = await dispatch(
|
||||||
|
playbackAsync({
|
||||||
|
audioFileId,
|
||||||
|
direction: sortDirection,
|
||||||
|
paramName: sortableParamName,
|
||||||
|
isTypist,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (meta.requestStatus === "fulfilled") {
|
||||||
|
const filter = getFilter(
|
||||||
|
filterUploaded,
|
||||||
|
filterInProgress,
|
||||||
|
filterPending,
|
||||||
|
filterFinished,
|
||||||
|
filterBackup
|
||||||
|
);
|
||||||
dispatch(
|
dispatch(
|
||||||
updateSortColumnAsync({
|
listTasksAsync({
|
||||||
|
limit: LIMIT_TASK_NUM,
|
||||||
|
offset: 0,
|
||||||
|
filter,
|
||||||
direction: sortDirection,
|
direction: sortDirection,
|
||||||
paramName: sortableParamName,
|
paramName: sortableParamName,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}, [dispatch, sortDirection, sortableParamName]);
|
dispatch(listTypistsAsync());
|
||||||
|
dispatch(listTypistGroupsAsync());
|
||||||
|
|
||||||
|
const url = `${
|
||||||
|
import.meta.env.VITE_DESK_TOP_APP_SCHEME
|
||||||
|
}:playback?audioId=${audioFileId}`;
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
dispatch,
|
||||||
|
filterBackup,
|
||||||
|
filterFinished,
|
||||||
|
filterInProgress,
|
||||||
|
filterPending,
|
||||||
|
filterUploaded,
|
||||||
|
isTypist,
|
||||||
|
sortDirection,
|
||||||
|
sortableParamName,
|
||||||
|
t,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
const onClosePopup = useCallback(
|
const onClosePopup = useCallback(
|
||||||
(isChanged: boolean) => {
|
(isChanged: boolean) => {
|
||||||
@ -949,7 +1001,7 @@ const DictationPage: React.FC = (): JSX.Element => {
|
|||||||
<ul className={styles.menuInTable}>
|
<ul className={styles.menuInTable}>
|
||||||
<li>
|
<li>
|
||||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||||||
<a onClick={onPlayBack}>
|
<a onClick={() => onPlayBack(x.audioFileId)}>
|
||||||
{t(
|
{t(
|
||||||
getTranslationID(
|
getTranslationID(
|
||||||
"dictationPage.label.playback"
|
"dictationPage.label.playback"
|
||||||
|
|||||||
@ -32,10 +32,11 @@ const LoginPage: React.FC = (): JSX.Element => {
|
|||||||
if (meta.requestStatus === "fulfilled") {
|
if (meta.requestStatus === "fulfilled") {
|
||||||
const accessToken = loadAccessToken();
|
const accessToken = loadAccessToken();
|
||||||
const refreshToken = loadRefreshToken();
|
const refreshToken = loadRefreshToken();
|
||||||
/* TODO 1899:デスクトップアプリが無いためメモ帳を開くようにしている
|
const url = `${
|
||||||
デスクトップアプリチームでスキーム名が決まり次第修正する
|
import.meta.env.VITE_DESK_TOP_APP_SCHEME
|
||||||
*/
|
}:login?accessToken=${accessToken}&refreshToken=${refreshToken}&language=${
|
||||||
const url = `note:login?accessToken=${accessToken}&refreshToken=${refreshToken}&language=${i18n.language}`; // カスタムURLスキーム
|
i18n.language
|
||||||
|
}`; // カスタムURLスキーム
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
a.href = url;
|
a.href = url;
|
||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
|
|||||||
1
dictation_client/src/react-app-env.d.ts
vendored
1
dictation_client/src/react-app-env.d.ts
vendored
@ -6,6 +6,7 @@ interface ImportMetaEnv {
|
|||||||
readonly VITE_B2C_CLIENTID: string;
|
readonly VITE_B2C_CLIENTID: string;
|
||||||
readonly VITE_B2C_AUTHORITY: string;
|
readonly VITE_B2C_AUTHORITY: string;
|
||||||
readonly VITE_B2C_KNOWNAUTHORITIES: string;
|
readonly VITE_B2C_KNOWNAUTHORITIES: string;
|
||||||
|
readonly VITE_DESK_TOP_APP_SCHEME: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
|
|||||||
@ -174,6 +174,8 @@
|
|||||||
},
|
},
|
||||||
"dictationPage": {
|
"dictationPage": {
|
||||||
"message": {
|
"message": {
|
||||||
|
"noPlaybackAuthorization": "(de)本タスクをPlayBackできる権限がありません。",
|
||||||
|
"taskToPlaybackNoExists": "(de)タスクがすでに文字起こし完了済みまたは存在しないため、PlayBackできません。",
|
||||||
"taskNotEditable": "(de)すでに文字起こし作業着手中またはタスクが存在しないため、タイピストを変更できません。"
|
"taskNotEditable": "(de)すでに文字起こし作業着手中またはタスクが存在しないため、タイピストを変更できません。"
|
||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
|
|||||||
@ -174,6 +174,8 @@
|
|||||||
},
|
},
|
||||||
"dictationPage": {
|
"dictationPage": {
|
||||||
"message": {
|
"message": {
|
||||||
|
"noPlaybackAuthorization": "本タスクをPlayBackできる権限がありません。",
|
||||||
|
"taskToPlaybackNoExists": "タスクがすでに文字起こし完了済みまたは存在しないため、PlayBackできません。",
|
||||||
"taskNotEditable": "すでに文字起こし作業着手中またはタスクが存在しないため、タイピストを変更できません。"
|
"taskNotEditable": "すでに文字起こし作業着手中またはタスクが存在しないため、タイピストを変更できません。"
|
||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
|
|||||||
@ -174,6 +174,8 @@
|
|||||||
},
|
},
|
||||||
"dictationPage": {
|
"dictationPage": {
|
||||||
"message": {
|
"message": {
|
||||||
|
"noPlaybackAuthorization": "(es)本タスクをPlayBackできる権限がありません。",
|
||||||
|
"taskToPlaybackNoExists": "(es)タスクがすでに文字起こし完了済みまたは存在しないため、PlayBackできません。",
|
||||||
"taskNotEditable": "(es)すでに文字起こし作業着手中またはタスクが存在しないため、タイピストを変更できません。"
|
"taskNotEditable": "(es)すでに文字起こし作業着手中またはタスクが存在しないため、タイピストを変更できません。"
|
||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
|
|||||||
@ -174,6 +174,8 @@
|
|||||||
},
|
},
|
||||||
"dictationPage": {
|
"dictationPage": {
|
||||||
"message": {
|
"message": {
|
||||||
|
"noPlaybackAuthorization": "(fr)本タスクをPlayBackできる権限がありません。",
|
||||||
|
"taskToPlaybackNoExists": "(fr)タスクがすでに文字起こし完了済みまたは存在しないため、PlayBackできません。",
|
||||||
"taskNotEditable": "(fr)すでに文字起こし作業着手中またはタスクが存在しないため、タイピストを変更できません。"
|
"taskNotEditable": "(fr)すでに文字起こし作業着手中またはタスクが存在しないため、タイピストを変更できません。"
|
||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
|
|||||||
@ -510,7 +510,7 @@
|
|||||||
},
|
},
|
||||||
"/users/sort-criteria": {
|
"/users/sort-criteria": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "updateSortCcriteria",
|
"operationId": "updateSortCriteria",
|
||||||
"summary": "",
|
"summary": "",
|
||||||
"description": "ログインしているユーザーのタスクソート条件を更新します",
|
"description": "ログインしているユーザーのタスクソート条件を更新します",
|
||||||
"parameters": [],
|
"parameters": [],
|
||||||
@ -564,7 +564,7 @@
|
|||||||
"security": [{ "bearer": [] }]
|
"security": [{ "bearer": [] }]
|
||||||
},
|
},
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "getSortCcriteria",
|
"operationId": "getSortCriteria",
|
||||||
"summary": "",
|
"summary": "",
|
||||||
"description": "ログインしているユーザーのタスクソート条件を取得します",
|
"description": "ログインしているユーザーのタスクソート条件を取得します",
|
||||||
"parameters": [],
|
"parameters": [],
|
||||||
|
|||||||
@ -249,7 +249,7 @@ export class UsersController {
|
|||||||
type: ErrorResponse,
|
type: ErrorResponse,
|
||||||
})
|
})
|
||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
operationId: 'updateSortCcriteria',
|
operationId: 'updateSortCriteria',
|
||||||
description: 'ログインしているユーザーのタスクソート条件を更新します',
|
description: 'ログインしているユーザーのタスクソート条件を更新します',
|
||||||
})
|
})
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ -297,7 +297,7 @@ export class UsersController {
|
|||||||
type: ErrorResponse,
|
type: ErrorResponse,
|
||||||
})
|
})
|
||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
operationId: 'getSortCcriteria',
|
operationId: 'getSortCriteria',
|
||||||
description: 'ログインしているユーザーのタスクソート条件を取得します',
|
description: 'ログインしているユーザーのタスクソート条件を取得します',
|
||||||
})
|
})
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
|
|||||||
@ -641,79 +641,79 @@ const makeOrder = (
|
|||||||
switch (sort_criteria) {
|
switch (sort_criteria) {
|
||||||
case 'JOB_NUMBER':
|
case 'JOB_NUMBER':
|
||||||
return {
|
return {
|
||||||
priority: 'ASC',
|
priority: 'DESC',
|
||||||
job_number: direction,
|
job_number: direction,
|
||||||
id: 'ASC',
|
id: 'ASC',
|
||||||
};
|
};
|
||||||
case 'STATUS':
|
case 'STATUS':
|
||||||
return {
|
return {
|
||||||
priority: 'ASC',
|
priority: 'DESC',
|
||||||
status: direction,
|
status: direction,
|
||||||
id: 'ASC',
|
id: 'ASC',
|
||||||
};
|
};
|
||||||
case 'TRANSCRIPTION_FINISHED_DATE':
|
case 'TRANSCRIPTION_FINISHED_DATE':
|
||||||
return {
|
return {
|
||||||
priority: 'ASC',
|
priority: 'DESC',
|
||||||
finished_at: direction,
|
finished_at: direction,
|
||||||
id: 'ASC',
|
id: 'ASC',
|
||||||
};
|
};
|
||||||
case 'TRANSCRIPTION_STARTED_DATE':
|
case 'TRANSCRIPTION_STARTED_DATE':
|
||||||
return {
|
return {
|
||||||
priority: 'ASC',
|
priority: 'DESC',
|
||||||
started_at: direction,
|
started_at: direction,
|
||||||
id: 'ASC',
|
id: 'ASC',
|
||||||
};
|
};
|
||||||
case 'AUTHOR_ID':
|
case 'AUTHOR_ID':
|
||||||
return {
|
return {
|
||||||
priority: 'ASC',
|
priority: 'DESC',
|
||||||
file: { author_id: direction },
|
file: { author_id: direction },
|
||||||
id: 'ASC',
|
id: 'ASC',
|
||||||
};
|
};
|
||||||
case 'ENCRYPTION':
|
case 'ENCRYPTION':
|
||||||
return {
|
return {
|
||||||
priority: 'ASC',
|
priority: 'DESC',
|
||||||
file: { is_encrypted: direction },
|
file: { is_encrypted: direction },
|
||||||
id: 'ASC',
|
id: 'ASC',
|
||||||
};
|
};
|
||||||
case 'FILE_LENGTH':
|
case 'FILE_LENGTH':
|
||||||
return {
|
return {
|
||||||
priority: 'ASC',
|
priority: 'DESC',
|
||||||
file: { duration: direction },
|
file: { duration: direction },
|
||||||
id: 'ASC',
|
id: 'ASC',
|
||||||
};
|
};
|
||||||
case 'FILE_NAME':
|
case 'FILE_NAME':
|
||||||
return {
|
return {
|
||||||
priority: 'ASC',
|
priority: 'DESC',
|
||||||
file: { file_name: direction },
|
file: { file_name: direction },
|
||||||
id: 'ASC',
|
id: 'ASC',
|
||||||
};
|
};
|
||||||
case 'FILE_SIZE':
|
case 'FILE_SIZE':
|
||||||
return {
|
return {
|
||||||
priority: 'ASC',
|
priority: 'DESC',
|
||||||
file: { file_size: direction },
|
file: { file_size: direction },
|
||||||
id: 'ASC',
|
id: 'ASC',
|
||||||
};
|
};
|
||||||
case 'RECORDING_FINISHED_DATE':
|
case 'RECORDING_FINISHED_DATE':
|
||||||
return {
|
return {
|
||||||
priority: 'ASC',
|
priority: 'DESC',
|
||||||
file: { finished_at: direction },
|
file: { finished_at: direction },
|
||||||
id: 'ASC',
|
id: 'ASC',
|
||||||
};
|
};
|
||||||
case 'RECORDING_STARTED_DATE':
|
case 'RECORDING_STARTED_DATE':
|
||||||
return {
|
return {
|
||||||
priority: 'ASC',
|
priority: 'DESC',
|
||||||
file: { started_at: direction },
|
file: { started_at: direction },
|
||||||
id: 'ASC',
|
id: 'ASC',
|
||||||
};
|
};
|
||||||
case 'UPLOAD_DATE':
|
case 'UPLOAD_DATE':
|
||||||
return {
|
return {
|
||||||
priority: 'ASC',
|
priority: 'DESC',
|
||||||
file: { uploaded_at: direction },
|
file: { uploaded_at: direction },
|
||||||
id: 'ASC',
|
id: 'ASC',
|
||||||
};
|
};
|
||||||
case 'WORK_TYPE':
|
case 'WORK_TYPE':
|
||||||
return {
|
return {
|
||||||
priority: 'ASC',
|
priority: 'DESC',
|
||||||
file: { work_type_id: direction },
|
file: { work_type_id: direction },
|
||||||
id: 'ASC',
|
id: 'ASC',
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user