From b5aba7a3baa1b5ded1747c7ee16805a1e8f37a3f Mon Sep 17 00:00:00 2001 From: Giacomo Olivero Date: Mon, 18 Dec 2023 14:13:26 +0100 Subject: [PATCH] Teanant autoenrolling frontend --- .../accountPage/UserList/UserList.tsx | 39 ++- .../UserListLogic/UserListLogic.tsx | 47 +-- .../workspaces/Dashboard/Dashboard.tsx | 27 +- .../DashboardLogic/DashboardLogic.tsx | 116 ++++++- .../Grid/WorkspaceGrid/WorkspaceGrid.tsx | 10 +- .../WorkspaceGridItem/WorkspaceGridItem.tsx | 18 +- .../workspaces/WorkspaceAdd/WorkspaceAdd.tsx | 26 ++ .../WorkspaceRow/WorkspaceRow.tsx | 44 +++ .../WorkspaceAdd/WorkspaceRow/index.ts | 2 + .../WorkspacesList/WorkspacesList.tsx | 48 +++ .../WorkspaceAdd/WorkspacesList/index.ts | 2 + .../WorkspacesListLogic.tsx | 103 +++++++ .../WorkspaceAdd/WorkspacesListLogic/index.ts | 2 + .../WorkspaceContainer/WorkspaceContainer.tsx | 49 ++- frontend/src/generated-types.tsx | 291 +++++++++++------- .../query/workspaces.query.graphql | 13 + frontend/src/utils.ts | 16 + frontend/src/utilsLogic.tsx | 44 ++- frontend/src/utilsStorage.ts | 1 + 19 files changed, 731 insertions(+), 167 deletions(-) create mode 100644 frontend/src/components/workspaces/WorkspaceAdd/WorkspaceAdd.tsx create mode 100644 frontend/src/components/workspaces/WorkspaceAdd/WorkspaceRow/WorkspaceRow.tsx create mode 100644 frontend/src/components/workspaces/WorkspaceAdd/WorkspaceRow/index.ts create mode 100644 frontend/src/components/workspaces/WorkspaceAdd/WorkspacesList/WorkspacesList.tsx create mode 100644 frontend/src/components/workspaces/WorkspaceAdd/WorkspacesList/index.ts create mode 100644 frontend/src/components/workspaces/WorkspaceAdd/WorkspacesListLogic/WorkspacesListLogic.tsx create mode 100644 frontend/src/components/workspaces/WorkspaceAdd/WorkspacesListLogic/index.ts create mode 100644 frontend/src/graphql-components/query/workspaces.query.graphql diff --git a/frontend/src/components/accountPage/UserList/UserList.tsx b/frontend/src/components/accountPage/UserList/UserList.tsx index a9634a735..39f561c55 100644 --- a/frontend/src/components/accountPage/UserList/UserList.tsx +++ b/frontend/src/components/accountPage/UserList/UserList.tsx @@ -7,6 +7,7 @@ import { DeleteOutlined, SwapOutlined, RedoOutlined, + CheckOutlined, } from '@ant-design/icons'; import Column from 'antd/lib/table/Column'; import { Role } from '../../../generated-types'; @@ -44,8 +45,21 @@ const UserList: FC = props => { }; const handleChangeCurrentRole = (record: UserAccountPage) => { - const newRole = - record.currentRole === Role.Manager ? Role.User : Role.Manager; + let newRole: Role; + switch (record.currentRole) { + case Role.Manager: + newRole = Role.User; + break; + case Role.User: + newRole = Role.Manager; + break; + case Role.Candidate: + newRole = Role.User; + break; + default: + newRole = Role.User; + break; + } props.onUpdateUser(record, newRole); }; @@ -131,12 +145,21 @@ const UserList: FC = props => { render={(_: any, record: UserAccountPage) => props.users.length >= 1 ? (
- - handleChangeCurrentRole(record)} - /> - + {record.currentRole === Role.Candidate ? ( + + handleChangeCurrentRole(record)} + /> + + ) : ( + + handleChangeCurrentRole(record)} + /> + + )}
diff --git a/frontend/src/components/accountPage/UserListLogic/UserListLogic.tsx b/frontend/src/components/accountPage/UserListLogic/UserListLogic.tsx index 36734cb29..fc0674d17 100644 --- a/frontend/src/components/accountPage/UserListLogic/UserListLogic.tsx +++ b/frontend/src/components/accountPage/UserListLogic/UserListLogic.tsx @@ -6,22 +6,21 @@ import { } from '../../../generated-types'; import { getTenantPatchJson } from '../../../graphql-components/utils'; import UserList from '../UserList/UserList'; -import { makeRandomDigits, UserAccountPage } from '../../../utils'; +import { makeRandomDigits, UserAccountPage, Workspace } from '../../../utils'; import { AuthContext } from '../../../contexts/AuthContext'; import { Role } from '../../../generated-types'; import { ErrorContext } from '../../../errorHandling/ErrorContext'; import { ErrorTypes, SupportedError } from '../../../errorHandling/utils'; export interface IUserListLogicProps { - workspaceName: string; - workspaceNamespace: string; + workspace: Workspace; } const UserListLogic: FC = props => { const { apolloErrorCatcher, makeErrorCatcher } = useContext(ErrorContext); const genericErrorCatcher = makeErrorCatcher(ErrorTypes.GenericError); const { userId } = useContext(AuthContext); - const { workspaceName, workspaceNamespace } = props; + const { workspace } = props; const [loadingSpinner, setLoadingSpinner] = useState(false); const [errors, setErrors] = useState([]); // Used to handle stop while uploading users from CSV @@ -32,7 +31,7 @@ const UserListLogic: FC = props => { const [users, setUsers] = useState([]); const { data, loading, error, refetch } = useTenantsQuery({ variables: { - labels: `crownlabs.polito.it/${workspaceNamespace}`, + labels: `crownlabs.polito.it/${workspace.namespace}`, retrieveWorkspaces: true, }, onError: apolloErrorCatcher, @@ -44,7 +43,7 @@ const UserListLogic: FC = props => { }, [abortUploading]); const getManager = () => { - return `${workspaceName}-${userId || makeRandomDigits(10)}`; + return `${workspace.name}-${userId || makeRandomDigits(10)}`; }; const refreshUserList = async () => await refetch(); @@ -59,8 +58,8 @@ const UserListLogic: FC = props => { name: user?.spec?.firstName!, surname: user?.spec?.lastName!, email: user?.spec?.email!, - currentRole: user?.spec?.workspaces?.find(roles => - workspaceName.includes(roles?.name!) + currentRole: user?.spec?.workspaces?.find( + roles => roles?.name === workspace.name )?.role!, workspaces: user?.spec?.workspaces?.map(workspace => ({ @@ -70,7 +69,7 @@ const UserListLogic: FC = props => { })) || [] ); } - }, [loading, data, workspaceName]); + }, [loading, data, workspace.name]); const [applyTenantMutation] = useApplyTenantMutation(); @@ -78,7 +77,7 @@ const UserListLogic: FC = props => { try { let workspaces = users .find(u => u.userid === user.userid)! - .workspaces?.filter(w => w.name === workspaceName) + .workspaces?.filter(w => w.name === workspace.name) .map(({ name }) => ({ name, role: newRole })); setLoadingSpinner(true); await applyTenantMutation({ @@ -90,15 +89,23 @@ const UserListLogic: FC = props => { onError: apolloErrorCatcher, }); setUsers( - users.map(u => - u.userid === user.userid - ? { - ...u, - currentRole: newRole, - workspaces, + users.map(u => { + if (u.userid === user.userid) { + if (u.currentRole === Role.Candidate && workspace.waitingTenants) { + workspace.waitingTenants--; + if (workspace.waitingTenants === 0) { + workspace.waitingTenants = undefined; } - : u - ) + } + return { + ...u, + currentRole: newRole, + workspaces, + }; + } else { + return u; + } + }) ); } catch (error) { genericErrorCatcher(error as SupportedError); @@ -164,8 +171,8 @@ const UserListLogic: FC = props => { users={users} onAddUser={addUser} onUpdateUser={updateUser} - workspaceNamespace={workspaceNamespace} - workspaceName={workspaceName} + workspaceNamespace={workspace.namespace} + workspaceName={workspace.name} uploadedNumber={uploadedNumber} uploadedUserNumber={uploadedUserNumber} setAbortUploading={handleAbort} diff --git a/frontend/src/components/workspaces/Dashboard/Dashboard.tsx b/frontend/src/components/workspaces/Dashboard/Dashboard.tsx index 7e35c4bb0..dd4b26f5b 100644 --- a/frontend/src/components/workspaces/Dashboard/Dashboard.tsx +++ b/frontend/src/components/workspaces/Dashboard/Dashboard.tsx @@ -1,20 +1,26 @@ -import { Col } from 'antd'; +import { Button, Col } from 'antd'; import { FC, useEffect, useState } from 'react'; import { Workspace } from '../../../utils'; import { SessionValue, StorageKeys } from '../../../utilsStorage'; import { WorkspaceGrid } from '../Grid/WorkspaceGrid'; import { WorkspaceContainer } from '../WorkspaceContainer'; import { WorkspaceWelcome } from '../WorkspaceWelcome'; +import WorkspaceAdd from '../WorkspaceAdd/WorkspaceAdd'; const dashboard = new SessionValue(StorageKeys.Dashboard_View, '-1'); export interface IDashboardProps { tenantNamespace: string; workspaces: Array; + candidatesButton?: { + show: boolean; + selected: boolean; + select: () => void; + }; } const Dashboard: FC = ({ ...props }) => { const [selectedWsId, setSelectedWs] = useState(parseInt(dashboard.get())); - const { tenantNamespace, workspaces } = props; + const { tenantNamespace, workspaces, candidatesButton } = props; useEffect(() => { dashboard.set(String(selectedWsId)); @@ -29,9 +35,22 @@ const Dashboard: FC = ({ ...props }) => { workspaceItems={workspaces.map((ws, idx) => ({ id: idx, title: ws.prettyName, + waitingTenants: ws.waitingTenants, }))} onClick={setSelectedWs} /> + {candidatesButton?.show && ( +
+ +
+ )} = ({ ...props }) => { xxl={12} className="lg:pl-4 lg:pr-0 px-4 flex flex-auto" > - {selectedWsId !== -1 ? ( + {selectedWsId >= 0 && selectedWsId < workspaces.length ? ( + ) : selectedWsId === -2 ? ( + ) : ( )} diff --git a/frontend/src/components/workspaces/DashboardLogic/DashboardLogic.tsx b/frontend/src/components/workspaces/DashboardLogic/DashboardLogic.tsx index 54c7e4af4..a68a3f0d5 100644 --- a/frontend/src/components/workspaces/DashboardLogic/DashboardLogic.tsx +++ b/frontend/src/components/workspaces/DashboardLogic/DashboardLogic.tsx @@ -1,23 +1,131 @@ import { Spin } from 'antd'; -import { FC, useContext } from 'react'; +import { + FC, + useCallback, + useContext, + useEffect, + useMemo, + useState, +} from 'react'; import { TenantContext } from '../../../contexts/TenantContext'; import { makeWorkspace } from '../../../utilsLogic'; import Dashboard from '../Dashboard/Dashboard'; +import { + Role, + TenantsDocument, + useWorkspacesQuery, +} from '../../../generated-types'; +import { Workspace, WorkspaceRole } from '../../../utils'; +import { useApolloClient } from '@apollo/client'; +import { ErrorContext } from '../../../errorHandling/ErrorContext'; +import { LocalValue, StorageKeys } from '../../../utilsStorage'; + +const dashboard = new LocalValue(StorageKeys.Dashboard_LoadCandidates, 'false'); const DashboardLogic: FC<{}> = () => { + const { apolloErrorCatcher } = useContext(ErrorContext); + const { data: tenantData, error: tenantError, loading: tenantLoading, } = useContext(TenantContext); + const ws = useMemo(() => { + return ( + tenantData?.tenant?.spec?.workspaces + ?.filter(w => w?.role !== Role.Candidate) + ?.map(makeWorkspace) ?? [] + ); + }, [tenantData?.tenant?.spec?.workspaces]); + + const [viewWs, setViewWs] = useState(ws); + const client = useApolloClient(); + + const { data: workspaceQueryData } = useWorkspacesQuery({ + variables: { + labels: 'crownlabs.polito.it/autoenroll=withApproval', + }, + onError: apolloErrorCatcher, + }); + + const [loadCandidates, setLoadCandidates] = useState( + dashboard.get() === 'true' + ); + + const wsIsManagedWithApproval = useCallback( + (w: Workspace): boolean => { + return ( + w?.role === WorkspaceRole.manager && + workspaceQueryData?.workspaces?.items?.find( + wq => wq?.metadata?.name === w.name + ) !== undefined + ); + }, + [workspaceQueryData?.workspaces?.items] + ); + + useEffect(() => { + if (loadCandidates) { + const workspaceQueue: Workspace[] = []; + const executeNext = () => { + if (!loadCandidates || workspaceQueue.length === 0) { + return; + } + const w = workspaceQueue.shift(); + client + .query({ + query: TenantsDocument, + variables: { + labels: `crownlabs.polito.it/workspace-${w?.name}=candidate`, + }, + }) + .then(queryResult => { + let numCandidate = queryResult.data.tenants.items.length; + if (numCandidate > 0) { + ws.find(ws => ws.name === w?.name)!.waitingTenants = numCandidate; + setViewWs([...ws]); + } + executeNext(); + }); + }; + + ws?.filter( + w => w?.role === WorkspaceRole.manager && wsIsManagedWithApproval(w) + ).forEach(w => { + workspaceQueue.push(w); + if (workspaceQueue.length === 1) { + executeNext(); + } + }); + } + }, [ + client, + ws, + workspaceQueryData?.workspaces?.items, + loadCandidates, + wsIsManagedWithApproval, + ]); + + const selectLoadCandidates = () => { + if (loadCandidates) { + ws.forEach(w => (w.waitingTenants = undefined)); + } + setViewWs([...ws]); + setLoadCandidates(!loadCandidates); + dashboard.set(String(!loadCandidates)); + }; + return !tenantLoading && tenantData && !tenantError ? ( <> wsIsManagedWithApproval(w)), + selected: loadCandidates, + select: selectLoadCandidates, + }} /> ) : ( diff --git a/frontend/src/components/workspaces/Grid/WorkspaceGrid/WorkspaceGrid.tsx b/frontend/src/components/workspaces/Grid/WorkspaceGrid/WorkspaceGrid.tsx index ca30197f2..81103b4e1 100644 --- a/frontend/src/components/workspaces/Grid/WorkspaceGrid/WorkspaceGrid.tsx +++ b/frontend/src/components/workspaces/Grid/WorkspaceGrid/WorkspaceGrid.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import { WorkspaceGridItem } from '../WorkspaceGridItem'; export interface IWorkspaceGridProps { - workspaceItems: Array<{ id: number; title: string }>; + workspaceItems: Array<{ id: number; title: string; waitingTenants?: number }>; selectedWs: number; onClick: (id: number) => void; } @@ -17,10 +17,18 @@ const WorkspaceGrid: FC = ({ ...props }) => { id={workspaceItem.id} title={workspaceItem.title} isActive={selectedWs === workspaceItem.id} + badgeValue={workspaceItem.waitingTenants} onClick={onClick} /> ))} + ); }; diff --git a/frontend/src/components/workspaces/Grid/WorkspaceGridItem/WorkspaceGridItem.tsx b/frontend/src/components/workspaces/Grid/WorkspaceGridItem/WorkspaceGridItem.tsx index 904ffd30b..40938e9e4 100644 --- a/frontend/src/components/workspaces/Grid/WorkspaceGridItem/WorkspaceGridItem.tsx +++ b/frontend/src/components/workspaces/Grid/WorkspaceGridItem/WorkspaceGridItem.tsx @@ -1,16 +1,23 @@ import { FC } from 'react'; import { Row, Col } from 'antd'; import './WorkspaceGridItem.less'; +import Badge from '../../../common/Badge'; export interface IWorkspaceGridItemProps { id: number; title: string; isActive: boolean; + badgeValue?: number; + previewName?: string; onClick: (id: number) => void; } const WorkspaceGridItem: FC = ({ ...props }) => { - const { id, title, isActive, onClick } = props; + const { id, title, isActive, badgeValue, previewName, onClick } = props; + + const preview = ( + previewName ? previewName : title[0] + title[1] + ).toUpperCase(); return ( @@ -27,8 +34,15 @@ const WorkspaceGridItem: FC = ({ ...props }) => { className="cursor-pointer font-mono font-semibold flex justify-center items-center pt-2 " style={{ fontSize: '32pt', color: '#141414' }} > - {title[0].toUpperCase() + title[1].toUpperCase()} + {preview} + {badgeValue && ( + + )} diff --git a/frontend/src/components/workspaces/WorkspaceAdd/WorkspaceAdd.tsx b/frontend/src/components/workspaces/WorkspaceAdd/WorkspaceAdd.tsx new file mode 100644 index 000000000..ea6053391 --- /dev/null +++ b/frontend/src/components/workspaces/WorkspaceAdd/WorkspaceAdd.tsx @@ -0,0 +1,26 @@ +import Box from '../../common/Box'; +import { FC } from 'react'; +import { WorkspacesListLogic } from './WorkspacesListLogic'; + +export interface IWorkspaceAddProps {} + +const WorkspaceAdd: FC = ({ ...args }) => { + return ( + +

+ Join a new Workspace +

+ + ), + }} + > + +
+ ); +}; + +export default WorkspaceAdd; diff --git a/frontend/src/components/workspaces/WorkspaceAdd/WorkspaceRow/WorkspaceRow.tsx b/frontend/src/components/workspaces/WorkspaceAdd/WorkspaceRow/WorkspaceRow.tsx new file mode 100644 index 000000000..ad2932680 --- /dev/null +++ b/frontend/src/components/workspaces/WorkspaceAdd/WorkspaceRow/WorkspaceRow.tsx @@ -0,0 +1,44 @@ +import { FC } from 'react'; +import { + WorkspacesAvailable, + WorkspacesAvailableAction, +} from '../../../../utils'; +import { Button, Space } from 'antd'; + +export interface IWorkspaceRowProps { + workspace: WorkspacesAvailable; + action: (w: WorkspacesAvailable) => void; +} + +const WorkspaceRow: FC = ({ ...args }) => { + const { workspace, action } = args; + + return ( +
+ + + + + {workspace.action === WorkspacesAvailableAction.Join || + workspace.action === WorkspacesAvailableAction.AskToJoin ? ( + + ) : ( + + )} + +
+ ); +}; + +export default WorkspaceRow; diff --git a/frontend/src/components/workspaces/WorkspaceAdd/WorkspaceRow/index.ts b/frontend/src/components/workspaces/WorkspaceAdd/WorkspaceRow/index.ts new file mode 100644 index 000000000..6ab6b11f9 --- /dev/null +++ b/frontend/src/components/workspaces/WorkspaceAdd/WorkspaceRow/index.ts @@ -0,0 +1,2 @@ +import WorkspaceRow from './WorkspaceRow'; +export { WorkspaceRow }; diff --git a/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesList/WorkspacesList.tsx b/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesList/WorkspacesList.tsx new file mode 100644 index 000000000..9078dfb11 --- /dev/null +++ b/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesList/WorkspacesList.tsx @@ -0,0 +1,48 @@ +import { FC } from 'react'; +import { WorkspacesAvailable } from '../../../../utils'; +import { Empty, Table } from 'antd'; +import { WorkspaceRow } from '../WorkspaceRow'; + +export interface IWorkspaceListProps { + workspacesAvailable: WorkspacesAvailable[]; + action: (w: WorkspacesAvailable) => void; +} + +const WorkspacesList: FC = ({ ...args }) => { + const { workspacesAvailable, action } = args; + + const columns = [ + { + title: 'Workspace', + key: 'workspace', + // eslint-disable-next-line react/no-multi-comp + render: (record: WorkspacesAvailable) => ( + + ), + }, + ]; + + return workspacesAvailable.length > 0 ? ( +
+ w.name} + columns={columns} + dataSource={workspacesAvailable} + pagination={false} + /> + + ) : ( +
+
+ +
+

+ No workspaces available +

+
+ ); +}; + +export default WorkspacesList; diff --git a/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesList/index.ts b/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesList/index.ts new file mode 100644 index 000000000..676b6d6ca --- /dev/null +++ b/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesList/index.ts @@ -0,0 +1,2 @@ +import WorkspacesList from './WorkspacesList'; +export { WorkspacesList }; diff --git a/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesListLogic/WorkspacesListLogic.tsx b/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesListLogic/WorkspacesListLogic.tsx new file mode 100644 index 000000000..e44197b07 --- /dev/null +++ b/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesListLogic/WorkspacesListLogic.tsx @@ -0,0 +1,103 @@ +import { FC, useContext } from 'react'; +import { + Role, + useApplyTenantMutation, + useWorkspacesQuery, +} from '../../../../generated-types'; +import { ErrorContext } from '../../../../errorHandling/ErrorContext'; +import { Spin } from 'antd'; +import { WorkspacesList } from '../WorkspacesList'; +import { availableWorkspaces, makeWorkspace } from '../../../../utilsLogic'; +import { TenantContext } from '../../../../contexts/TenantContext'; +import { + WorkspacesAvailable, + WorkspacesAvailableAction, +} from '../../../../utils'; +import { AuthContext } from '../../../../contexts/AuthContext'; +import { getTenantPatchJson } from '../../../../graphql-components/utils'; +import { ErrorTypes, SupportedError } from '../../../../errorHandling/utils'; + +export interface IWorkspaceListLogicProps {} + +const WorkspaceListLogic: FC = ({ ...args }) => { + const { apolloErrorCatcher, makeErrorCatcher } = useContext(ErrorContext); + const genericErrorCatcher = makeErrorCatcher(ErrorTypes.GenericError); + + const { userId } = useContext(AuthContext); + const { data: tenantData } = useContext(TenantContext); + + const { data, loading, error } = useWorkspacesQuery({ + variables: { + labels: 'crownlabs.polito.it/autoenroll in (immediate, withApproval)', + }, + onError: apolloErrorCatcher, + }); + + const [applyTenantMutation] = useApplyTenantMutation(); + + const workspaces = tenantData?.tenant?.spec?.workspaces?.map(makeWorkspace); + const availableWs = availableWorkspaces( + data?.workspaces?.items ?? [], + workspaces ?? [] + ); + + const applyWorkspaces = async (w: { name: string; role: Role }[]) => { + try { + await applyTenantMutation({ + variables: { + tenantId: userId ?? '', + patchJson: getTenantPatchJson({ + workspaces: w, + }), + manager: userId ?? '', + }, + onError: apolloErrorCatcher, + }); + } catch (error) { + genericErrorCatcher(error as SupportedError); + } + }; + + const getWorkspaces = () => { + return (tenantData?.tenant?.spec?.workspaces ?? []).map(ws => { + return { + name: ws?.name ?? '', + role: ws?.role ?? Role.User, + }; + }); + }; + + const addWorkspace = (w: WorkspacesAvailable, desiredRole: Role) => { + let workspaces = getWorkspaces(); + workspaces.push({ name: w.name, role: desiredRole }); + applyWorkspaces(workspaces); + }; + + const action = (w: WorkspacesAvailable) => { + switch (w.action) { + case WorkspacesAvailableAction.Join: + addWorkspace(w, Role.User); + break; + case WorkspacesAvailableAction.AskToJoin: + addWorkspace(w, Role.Candidate); + break; + default: + throw new Error('Action not supported'); + } + }; + + return !loading && data && !error ? ( +
+ +
+ ) : ( +
+ +
+ ); +}; + +export default WorkspaceListLogic; diff --git a/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesListLogic/index.ts b/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesListLogic/index.ts new file mode 100644 index 000000000..f537757f7 --- /dev/null +++ b/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesListLogic/index.ts @@ -0,0 +1,2 @@ +import WorkspacesListLogic from './WorkspacesListLogic'; +export { WorkspacesListLogic }; diff --git a/frontend/src/components/workspaces/WorkspaceContainer/WorkspaceContainer.tsx b/frontend/src/components/workspaces/WorkspaceContainer/WorkspaceContainer.tsx index b7f623161..8308e8acc 100644 --- a/frontend/src/components/workspaces/WorkspaceContainer/WorkspaceContainer.tsx +++ b/frontend/src/components/workspaces/WorkspaceContainer/WorkspaceContainer.tsx @@ -15,6 +15,7 @@ import Box from '../../common/Box'; import ModalCreateTemplate from '../ModalCreateTemplate'; import { Image, Template } from '../ModalCreateTemplate/ModalCreateTemplate'; import { TemplatesTableLogic } from '../Templates/TemplatesTableLogic'; +import Badge from '../../common/Badge'; export interface IWorkspaceContainerProps { tenantNamespace: string; @@ -57,15 +58,7 @@ const getImages = (dataImages: ImagesQuery) => { const WorkspaceContainer: FC = ({ ...props }) => { const [showUserListModal, setShowUserListModal] = useState(false); - const { - tenantNamespace, - workspace: { - role, - name: workspaceName, - namespace: workspaceNamespace, - prettyName: workspacePrettyName, - }, - } = props; + const { tenantNamespace, workspace } = props; const { apolloErrorCatcher } = useContext(ErrorContext); const [createTemplateMutation, { loading }] = useCreateTemplateMutation({ @@ -82,9 +75,9 @@ const WorkspaceContainer: FC = ({ ...props }) => { const submitHandler = (t: Template) => createTemplateMutation({ variables: { - workspaceId: workspaceName, - workspaceNamespace: workspaceNamespace, - templateId: `${workspaceName}-`, + workspaceId: workspace.name, + workspaceNamespace: workspace.namespace, + templateId: `${workspace.name}-`, templateName: t.name?.trim()!, descriptionTemplate: t.name?.trim()!, image: t.registry @@ -109,7 +102,7 @@ const WorkspaceContainer: FC = ({ ...props }) => { return ( <> = ({ ...props }) => { center: (

- {workspacePrettyName} + {workspace.prettyName}

), - left: role === 'manager' && ( + left: workspace.role === 'manager' && (
), - right: role === 'manager' && ( + right: workspace.role === 'manager' && (