saito.k deb3431d74 Merged PR 531: 画面実装(代行操作)
## 概要
[Task2909: 画面実装(代行操作)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2909)

- ディーラーユーザーが代行操作用トークンを取得して、第五階層ユーザーの代行操作ができる実装をしました。
  - 代行後に各対象タブが代行操作デザインで表示され、代行対象として操作できるようになっています。
    - 各APIの呼び出しについて代行操作用トークンがあればそちらを使うように実装しています。
 - 代行操作のタブ、ページ移動時に代行操作を維持するために遷移をリンクから`useNavigate`に変更しました。

## レビューポイント
- 代行操作用トークンの取り扱いについて
  - APIからのトークン取得後、`store.auth`に代行操作用トークンを保存し、利用時には関数を使って間接的に呼でいますが構成として不自然な点はないでしょうか?
    - トークン取得関数では代行操作用トークンがあればそれを、なければ通常のトークンを取得するようにしています。
      - これはAPIのトークンを設定する際にトークンを取得側では代行操作中か意識せずに一つの関数を呼べばいいようにするためです。
  - 代行操作用トークンの保存は通常のトークン保存と同様に`operation`から`Slice`に設定したSet関数を呼ぶことでstateに保存していますが、使い方として気になることはないでしょうか?

※代行操作中に表示するタブの制限と代行操作トークンの更新処理は別タスクでの実施予定です。

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

## 動作確認状況
- ローカルで確認
2023-11-06 08:28:40 +00:00

118 lines
3.2 KiB
TypeScript

import { createAsyncThunk } from "@reduxjs/toolkit";
import {
Configuration,
FilesApi,
GetTemplatesResponse,
TemplatesApi,
} from "api";
import type { RootState } from "app/store";
import { ErrorObject, createErrorObject } from "common/errors";
import { openSnackbar } from "features/ui/uiSlice";
import { getTranslationID } from "translation";
import { BlockBlobClient, ContainerClient } from "@azure/storage-blob";
import { getAccessToken } from "features/auth";
export const listTemplateAsync = createAsyncThunk<
GetTemplatesResponse,
void,
{
// rejectした時の返却値の型
rejectValue: {
error: ErrorObject;
};
}
>("workflow/listTemplateAsync", async (args, thunkApi) => {
// 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 templateApi = new TemplatesApi(config);
try {
const { data } = await templateApi.getTemplates({
headers: { authorization: `Bearer ${accessToken}` },
});
return data;
} catch (e) {
// e ⇒ errorObjectに変換"
const error = createErrorObject(e);
thunkApi.dispatch(
openSnackbar({
level: "error",
message: getTranslationID("common.message.internalServerError"),
})
);
return thunkApi.rejectWithValue({ error });
}
});
export const uploadTemplateAsync = createAsyncThunk<
{
/* Empty Object */
},
void,
{
// rejectした時の返却値の型
rejectValue: {
error: ErrorObject;
};
}
>("workflow/uploadTemplateAsync", async (args, thunkApi) => {
// apiのConfigurationを取得する
const { getState } = thunkApi;
const state = getState() as RootState;
const { configuration } = state.auth;
const accessToken = getAccessToken(state.auth);
const { uploadFile } = state.template.apps;
const config = new Configuration(configuration);
const filesApi = new FilesApi(config);
try {
if (!uploadFile) {
throw new Error("uploadFile is not found");
}
// SAS付きのURLを取得する
const { data } = await filesApi.uploadTemplateLocation({
headers: { authorization: `Bearer ${accessToken}` },
});
const { url } = data;
// ファイルをアップロードする
const containerClient = new ContainerClient(url);
const blockBlobClient: BlockBlobClient = containerClient.getBlockBlobClient(
uploadFile.name
);
await blockBlobClient.uploadData(uploadFile);
await filesApi.uploadTemplateFinished(
{
name: uploadFile.name,
url,
},
{
headers: { authorization: `Bearer ${accessToken}` },
}
);
thunkApi.dispatch(
openSnackbar({
level: "info",
message: getTranslationID("common.message.success"),
})
);
return {};
} catch (e) {
// e ⇒ errorObjectに変換"
const error = createErrorObject(e);
thunkApi.dispatch(
openSnackbar({
level: "error",
message: getTranslationID("common.message.internalServerError"),
})
);
return thunkApi.rejectWithValue({ error });
}
});