feat: impl grpcweb in frontend

This commit is contained in:
Steven
2023-09-20 21:49:13 +08:00
parent 9e8de4644a
commit ebe54d1131
11 changed files with 469 additions and 26 deletions

View File

@ -19,6 +19,7 @@
"i18next": "^23.5.1",
"lodash-es": "^4.17.21",
"lucide-react": "^0.263.1",
"nice-grpc-web": "^3.3.1",
"qrcode.react": "^3.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",

View File

@ -38,6 +38,9 @@ dependencies:
lucide-react:
specifier: ^0.263.1
version: 0.263.1(react@18.2.0)
nice-grpc-web:
specifier: ^3.3.1
version: 3.3.1(ws@8.14.2)
qrcode.react:
specifier: ^3.1.0
version: 3.1.0(react@18.2.0)
@ -1259,6 +1262,10 @@ packages:
resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==}
dev: false
/abort-controller-x@0.4.3:
resolution: {integrity: sha512-VtUwTNU8fpMwvWGn4xE93ywbogTYsuT+AUxAXOeelbXuQVIwNmC5YLeho9sH4vZ4ITW8414TTAOG1nW6uIVHCA==}
dev: false
/acorn-jsx@5.3.2(acorn@8.10.0):
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@ -2490,6 +2497,14 @@ packages:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
/isomorphic-ws@5.0.0(ws@8.14.2):
resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==}
peerDependencies:
ws: '*'
dependencies:
ws: 8.14.2
dev: false
/iterator.prototype@1.1.2:
resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==}
dependencies:
@ -2509,6 +2524,10 @@ packages:
hasBin: true
dev: false
/js-base64@3.7.5:
resolution: {integrity: sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==}
dev: false
/js-cookie@2.2.1:
resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==}
dev: false
@ -2693,6 +2712,23 @@ packages:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: true
/nice-grpc-common@2.0.2:
resolution: {integrity: sha512-7RNWbls5kAL1QVUOXvBsv1uO0wPQK3lHv+cY1gwkTzirnG1Nop4cBJZubpgziNbaVc/bl9QJcyvsf/NQxa3rjQ==}
dependencies:
ts-error: 1.0.6
dev: false
/nice-grpc-web@3.3.1(ws@8.14.2):
resolution: {integrity: sha512-KXListAFLjJ7L/GsrRW5YWT+2oZDaF8Lu19ms7+HMykDGtIksqvZwR6+EzVmunFJciiNDShJ4EXr1W6eaiZoDQ==}
dependencies:
abort-controller-x: 0.4.3
isomorphic-ws: 5.0.0(ws@8.14.2)
js-base64: 3.7.5
nice-grpc-common: 2.0.2
transitivePeerDependencies:
- ws
dev: false
/node-releases@2.0.13:
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
dev: true
@ -3542,6 +3578,10 @@ packages:
resolution: {integrity: sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==}
dev: false
/ts-error@1.0.6:
resolution: {integrity: sha512-tLJxacIQUM82IR7JO1UUkKlYuUTmoY9HBJAmNWFzheSlDS5SPMcNIepejHJa4BpPQLAcbRhRf3GDJzyj6rbKvA==}
dev: false
/ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
dev: false
@ -3743,6 +3783,19 @@ packages:
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
/ws@8.14.2:
resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
dev: false
/yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: true

View File

@ -1,8 +1,8 @@
import { Button, Input, Modal, ModalDialog, Radio, RadioGroup } from "@mui/joy";
import axios from "axios";
import { useState } from "react";
import { toast } from "react-hot-toast";
import { useTranslation } from "react-i18next";
import { userServiceClient } from "@/grpcweb";
import useLoading from "../hooks/useLoading";
import useUserStore from "../stores/v1/user";
import Icon from "./Icon";
@ -68,9 +68,12 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
}
try {
await axios.post(`/api/v2/users/${currentUser.id}/access_tokens`, {
description: state.description,
expiresAt: new Date(Date.now() + state.expiration * 1000),
await userServiceClient.createUserAccessToken({
id: currentUser.id,
userAccessToken: {
description: state.description,
expiresAt: new Date(Date.now() + state.expiration * 1000),
},
});
if (onConfirm) {

View File

@ -1,18 +1,20 @@
import { Button, IconButton } from "@mui/joy";
import axios from "axios";
import copy from "copy-to-clipboard";
import { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import { useTranslation } from "react-i18next";
import { ListUserAccessTokensResponse, UserAccessToken } from "@/types/proto/api/v2/user_service";
import { userServiceClient } from "@/grpcweb";
import { UserAccessToken } from "@/types/proto/api/v2/user_service";
import useUserStore from "../../stores/v1/user";
import { showCommonDialog } from "../Alert";
import CreateAccessTokenDialog from "../CreateAccessTokenDialog";
import Icon from "../Icon";
const listAccessTokens = async (userId: number) => {
const { data } = await axios.get<ListUserAccessTokensResponse>(`/api/v2/users/${userId}/access_tokens`);
return data.accessTokens;
const { accessTokens } = await userServiceClient.listUserAccessTokens({
id: userId,
});
return accessTokens;
};
const AccessTokenSection = () => {
@ -43,7 +45,10 @@ const AccessTokenSection = () => {
content: `Are you sure to delete access token \`${getFormatedAccessToken(accessToken)}\`? You cannot undo this action.`,
style: "danger",
onConfirm: async () => {
await axios.delete(`/api/v2/users/${currentUser.id}/access_tokens/${accessToken}`);
await userServiceClient.deleteUserAccessToken({
id: currentUser.id,
accessToken: accessToken,
});
setUserAccessTokens(userAccessTokens.filter((token) => token.accessToken !== accessToken));
},
});

View File

@ -7,20 +7,20 @@ const WorkspaceSection: React.FC = () => {
const [workspaceSetting, setWorkspaceSetting] = useState<WorkspaceSetting>();
useEffect(() => {
getWorkspaceSetting().then(({ data }) => {
setWorkspaceSetting(data.setting);
getWorkspaceSetting().then(({ setting }) => {
setWorkspaceSetting(setting);
});
}, []);
const handleDisallowSignUpChange = async (value: boolean) => {
const { data } = await updateWorkspaceSetting(
const { setting } = await updateWorkspaceSetting(
{
...workspaceSetting,
enableSignup: value,
} as WorkspaceSetting,
["enable_signup"]
);
setWorkspaceSetting(data.setting);
setWorkspaceSetting(setting);
};
if (!workspaceSetting) return <></>;

View File

@ -0,0 +1,18 @@
import { createChannel, createClientFactory, FetchTransport } from "nice-grpc-web";
import { UserServiceDefinition } from "./types/proto/api/v2/user_service";
import { WorkspaceSettingServiceDefinition } from "./types/proto/api/v2/workspace_setting_service";
const address = import.meta.env.MODE === "development" ? "http://localhost:8082" : window.location.origin;
const channel = createChannel(
address,
FetchTransport({
credentials: "include",
})
);
const clientFactory = createClientFactory();
export const userServiceClient = clientFactory.create(UserServiceDefinition, channel);
export const workspaceSettingServiceClient = clientFactory.create(WorkspaceSettingServiceDefinition, channel);

View File

@ -1,9 +1,6 @@
import axios from "axios";
import {
GetWorkspaceSettingResponse,
UpdateWorkspaceSettingResponse,
WorkspaceSetting,
} from "@/types/proto/api/v2/workspace_setting_service";
import { userServiceClient, workspaceSettingServiceClient } from "@/grpcweb";
import { WorkspaceSetting } from "@/types/proto/api/v2/workspace_setting_service";
export function getWorkspaceProfile() {
return axios.get<WorkspaceProfile>("/api/v1/workspace/profile");
@ -49,7 +46,7 @@ export function patchUser(userPatch: UserPatch) {
}
export function deleteUser(userId: UserId) {
return axios.delete(`/api/v2/users/${userId}`);
return userServiceClient.deleteUser({ id: userId });
}
export function getShortcutList(shortcutFind?: ShortcutFind) {
@ -81,11 +78,11 @@ export function deleteShortcutById(shortcutId: ShortcutId) {
}
export function getWorkspaceSetting() {
return axios.get<GetWorkspaceSettingResponse>(`/api/v2/workspace/settings`);
return workspaceSettingServiceClient.getWorkspaceSetting({});
}
export function updateWorkspaceSetting(setting: WorkspaceSetting, updateMask: string[]) {
return axios.post<UpdateWorkspaceSettingResponse>(`/api/v2/workspace/settings`, {
return workspaceSettingServiceClient.updateWorkspaceSetting({
setting,
updateMask,
});