Merged PR 496: ワークタイプ削除画面処理実装

## 概要
[Task2612: ワークタイプ削除画面処理実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2612)

- ワークタイプ削除の画面実装です。

## レビューポイント
- エラー処理に問題はないか

## UIの変更
- [Task2612](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/Task2612?csf=1&web=1&e=IgC7j3)

## 動作確認状況
- ローカルで確認
This commit is contained in:
makabe.t 2023-10-17 06:29:25 +00:00
parent 58674f7773
commit 74bf434786
8 changed files with 185 additions and 14 deletions

View File

@ -2561,6 +2561,44 @@ export const AccountsApiAxiosParamCreator = function (configuration?: Configurat
options: localVarRequestOptions,
};
},
/**
*
* @summary
* @param {number} id Worktypeの内部ID
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
deleteWorktype: async (id: number, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('deleteWorktype', 'id', id)
const localVarPath = `/accounts/worktypes/{id}/delete`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication bearer required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @summary
@ -3340,6 +3378,17 @@ export const AccountsApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.deleteAccountAndData(deleteAccountRequest, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @summary
* @param {number} id Worktypeの内部ID
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async deleteWorktype(id: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<object>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.deleteWorktype(id, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @summary
@ -3616,6 +3665,16 @@ export const AccountsApiFactory = function (configuration?: Configuration, baseP
deleteAccountAndData(deleteAccountRequest: DeleteAccountRequest, options?: any): AxiosPromise<object> {
return localVarFp.deleteAccountAndData(deleteAccountRequest, options).then((request) => request(axios, basePath));
},
/**
*
* @summary
* @param {number} id Worktypeの内部ID
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
deleteWorktype(id: number, options?: any): AxiosPromise<object> {
return localVarFp.deleteWorktype(id, options).then((request) => request(axios, basePath));
},
/**
*
* @summary
@ -3888,6 +3947,18 @@ export class AccountsApi extends BaseAPI {
return AccountsApiFp(this.configuration).deleteAccountAndData(deleteAccountRequest, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary
* @param {number} id Worktypeの内部ID
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof AccountsApi
*/
public deleteWorktype(id: number, options?: AxiosRequestConfig) {
return AccountsApiFp(this.configuration).deleteWorktype(id, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary

View File

@ -56,6 +56,7 @@ export const errorCodes = [
"E011001", // ワークタイプ重複エラー
"E011002", // ワークタイプ登録上限超過エラー
"E011003", // ワークタイプ不在エラー
"E011004", // ワークタイプ使用中エラー
"E013001", // ワークフローのAuthorIDとWorktypeIDのペア重複エラー
"E013002", // ワークフロー不在エラー
] as const;

View File

@ -342,3 +342,75 @@ export const updateActiveWorktypeAsync = createAsyncThunk<
return thunkApi.rejectWithValue({ error });
}
});
export const deleteWorktypeAsync = createAsyncThunk<
{
/* Empty Object */
},
{ worktypeId: number },
{
// rejectした時の返却値の型
rejectValue: {
error: ErrorObject;
};
}
>("workflow/deleteWorktypeAsync", async (args, thunkApi) => {
const { worktypeId } = args;
// apiのConfigurationを取得する
const { getState } = thunkApi;
const state = getState() as RootState;
const { configuration, accessToken } = state.auth;
const config = new Configuration(configuration);
const accountsApi = new AccountsApi(config);
try {
await accountsApi.deleteWorktype(worktypeId, {
headers: { authorization: `Bearer ${accessToken}` },
});
thunkApi.dispatch(
openSnackbar({
level: "info",
message: getTranslationID("common.message.success"),
})
);
return {};
} catch (e) {
// e ⇒ errorObjectに変換"
const error = createErrorObject(e);
if (error.statusCode === 400) {
if (error.code === "E011003") {
// ワークタイプが削除済みの場合は成功扱いとする
thunkApi.dispatch(
openSnackbar({
level: "info",
message: getTranslationID("common.message.success"),
})
);
return {};
}
if (error.code === "E011004") {
// ワークタイプがワークフローで使用中の場合は削除できない
thunkApi.dispatch(
openSnackbar({
level: "error",
message: getTranslationID(
"worktypeIdSetting.message.worktypeInUseError"
),
})
);
return {};
}
}
thunkApi.dispatch(
openSnackbar({
level: "error",
message: getTranslationID("common.message.internalServerError"),
})
);
return thunkApi.rejectWithValue({ error });
}
});

View File

@ -1,7 +1,7 @@
import { UpdateTokenTimer } from "components/auth/updateTokenTimer";
import Footer from "components/footer";
import Header from "components/header";
import React, { useEffect, useState } from "react";
import React, { useCallback, useEffect, useState } from "react";
import { getTranslationID } from "translation";
import styles from "styles/app.module.scss";
import undo from "assets/images/undo.svg";
@ -18,6 +18,7 @@ import {
selectIsLoading,
selectWorktypes,
selectActiveWorktypeId,
deleteWorktypeAsync,
} from "features/workflow/worktype";
import { AppDispatch } from "app/store";
import { AddWorktypeIdPopup } from "./addWorktypeIdPopup";
@ -86,6 +87,23 @@ const WorktypeIdSettingPage: React.FC = (): JSX.Element => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedActiveWorktypeId]);
// 削除ボタン押下時の処理
const onDeleteWoktype = useCallback(
async (worktypeId: number) => {
if (
/* eslint-disable-next-line no-alert */
!window.confirm(t(getTranslationID("common.message.dialogConfirm")))
) {
return;
}
const { meta } = await dispatch(deleteWorktypeAsync({ worktypeId }));
if (meta.requestStatus === "fulfilled") {
dispatch(listWorktypesAsync());
}
},
[dispatch, t]
);
return (
<>
<AddWorktypeIdPopup
@ -253,9 +271,10 @@ const WorktypeIdSettingPage: React.FC = (): JSX.Element => {
</a>
</li>
<li>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
<a
className={`${styles.menuLink} ${styles.isActive}`}
// onClick={}
onClick={() => onDeleteWoktype(worktype.id)}
>
{t(getTranslationID("common.label.delete"))}
</a>

View File

@ -429,7 +429,8 @@
"optionItemInvalidError": "(de)Default valueがDefaultに設定されている場合、Initial valueは入力が必須です。",
"optionItemSaveFailedError": "(de)オプションアイテムの保存に失敗しました。画面を更新し、再度実行してください",
"optionItemIncorrectError": "(de)入力されたItem labelまたはInitial valueがルールを満たしていません。下記のルールを満たす値を入力してください",
"updateActiveWorktypeFailedError": "(de)Active WorktypeIDの保存に失敗しました。画面を更新し、再度実行してください"
"updateActiveWorktypeFailedError": "(de)Active WorktypeIDの保存に失敗しました。画面を更新し、再度実行してください",
"worktypeInUseError": "(de)このWorktype IDはルーティングルールで使用されているため削除できません。"
}
},
"templateFilePage": {
@ -499,13 +500,14 @@
"backToTopPageLink": "(de)Back to TOP Page"
}
},
"AgreeToUsePage": {
"acceptToUsePage": {
"label": {
"title": "(de)Terms of Use has updated. Please confirm again.",
"linkOfEula": "(de)Click here to read the terms of use.",
"linkOfDpa": "(de)Click here to read the terms of use.",
"checkBoxForConsent": "(de)Yes, I agree to the terms of use.",
"forOdds": "(de)for ODDS."
"forOdds": "(de)for ODDS.",
"button": "(de)Continue"
}
}
}

View File

@ -429,7 +429,8 @@
"optionItemInvalidError": "Default valueがDefaultに設定されている場合、Initial valueは入力が必須です。",
"optionItemSaveFailedError": "オプションアイテムの保存に失敗しました。画面を更新し、再度実行してください",
"optionItemIncorrectError": "入力されたItem labelまたはInitial valueがルールを満たしていません。下記のルールを満たす値を入力してください",
"updateActiveWorktypeFailedError": "Active WorktypeIDの保存に失敗しました。画面を更新し、再度実行してください"
"updateActiveWorktypeFailedError": "Active WorktypeIDの保存に失敗しました。画面を更新し、再度実行してください",
"worktypeInUseError": "このWorktype IDはルーティングルールで使用されているため削除できません。"
}
},
"templateFilePage": {
@ -499,13 +500,14 @@
"backToTopPageLink": "Back to TOP Page"
}
},
"AgreeToUsePage": {
"acceptToUsePage": {
"label": {
"title": "Terms of Use has updated. Please confirm again.",
"linkOfEula": "Click here to read the terms of use.",
"linkOfDpa": "Click here to read the terms of use.",
"checkBoxForConsent": "Yes, I agree to the terms of use.",
"forOdds": "for ODDS."
"forOdds": "for ODDS.",
"button": "Continue"
}
}
}

View File

@ -429,7 +429,8 @@
"optionItemInvalidError": "(es)Default valueがDefaultに設定されている場合、Initial valueは入力が必須です。",
"optionItemSaveFailedError": "(es)オプションアイテムの保存に失敗しました。画面を更新し、再度実行してください",
"optionItemIncorrectError": "(es)入力されたItem labelまたはInitial valueがルールを満たしていません。下記のルールを満たす値を入力してください",
"updateActiveWorktypeFailedError": "(es)Active WorktypeIDの保存に失敗しました。画面を更新し、再度実行してください"
"updateActiveWorktypeFailedError": "(es)Active WorktypeIDの保存に失敗しました。画面を更新し、再度実行してください",
"worktypeInUseError": "(es)このWorktype IDはルーティングルールで使用されているため削除できません。"
}
},
"templateFilePage": {
@ -499,13 +500,14 @@
"backToTopPageLink": "(es)Back to TOP Page"
}
},
"AgreeToUsePage": {
"acceptToUsePage": {
"label": {
"title": "(es)Terms of Use has updated. Please confirm again.",
"linkOfEula": "(es)Click here to read the terms of use.",
"linkOfDpa": "(es)Click here to read the terms of use.",
"checkBoxForConsent": "(es)Yes, I agree to the terms of use.",
"forOdds": "(es)for ODDS."
"forOdds": "(es)for ODDS.",
"button": "(es)Continue"
}
}
}

View File

@ -429,7 +429,8 @@
"optionItemInvalidError": "(fr)Default valueがDefaultに設定されている場合、Initial valueは入力が必須です。",
"optionItemSaveFailedError": "(fr)オプションアイテムの保存に失敗しました。画面を更新し、再度実行してください",
"optionItemIncorrectError": "(fr)入力されたItem labelまたはInitial valueがルールを満たしていません。下記のルールを満たす値を入力してください",
"updateActiveWorktypeFailedError": "(fr)Active WorktypeIDの保存に失敗しました。画面を更新し、再度実行してください"
"updateActiveWorktypeFailedError": "(fr)Active WorktypeIDの保存に失敗しました。画面を更新し、再度実行してください",
"worktypeInUseError": "(fr)このWorktype IDはルーティングルールで使用されているため削除できません。"
}
},
"templateFilePage": {
@ -499,13 +500,14 @@
"backToTopPageLink": "(fr)Back to TOP Page"
}
},
"AgreeToUsePage": {
"acceptToUsePage": {
"label": {
"title": "(fr)Terms of Use has updated. Please confirm again.",
"linkOfEula": "(fr)Click here to read the terms of use.",
"linkOfDpa": "(fr)Click here to read the terms of use.",
"checkBoxForConsent": "(fr)Yes, I agree to the terms of use.",
"forOdds": "(fr)for ODDS."
"forOdds": "(fr)for ODDS.",
"button": "(fr)Continue"
}
}
}