diff --git a/frontend/src/components/workspaces/Dashboard/Dashboard.tsx b/frontend/src/components/workspaces/Dashboard/Dashboard.tsx index 20c5ddbef..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)); @@ -33,6 +39,18 @@ const Dashboard: FC = ({ ...props }) => { }))} onClick={setSelectedWs} /> + {candidatesButton?.show && ( +
+ +
+ )} = ({ ...props }) => { tenantNamespace={tenantNamespace} workspace={workspaces[selectedWsId]} /> + ) : selectedWsId === -2 ? ( + ) : ( )} diff --git a/frontend/src/components/workspaces/DashboardLogic/DashboardLogic.tsx b/frontend/src/components/workspaces/DashboardLogic/DashboardLogic.tsx index baca58481..f8b0ed78f 100644 --- a/frontend/src/components/workspaces/DashboardLogic/DashboardLogic.tsx +++ b/frontend/src/components/workspaces/DashboardLogic/DashboardLogic.tsx @@ -1,13 +1,23 @@ import { Spin } from 'antd'; -import { FC, useContext, useEffect, useState } from 'react'; +import { FC, useCallback, useContext, useEffect, useState } from 'react'; import { TenantContext } from '../../../contexts/TenantContext'; import { makeWorkspace } from '../../../utilsLogic'; import Dashboard from '../Dashboard/Dashboard'; -import { Role } from '../../../generated-types'; +import { + Role, + TenantsDocument, + useWorkspacesQuery, +} from '../../../generated-types'; import { Workspace, WorkspaceRole } from '../../../utils'; -import { gql, useApolloClient } from '@apollo/client'; +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, @@ -18,6 +28,29 @@ const DashboardLogic: FC<{}> = () => { const [viewWs, setViewWs] = useState([]); 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(() => { let wsList = tenantData?.tenant?.spec?.workspaces @@ -28,41 +61,66 @@ const DashboardLogic: FC<{}> = () => { }, [tenantData?.tenant?.spec?.workspaces]); useEffect(() => { - ws?.filter(w => w?.role === WorkspaceRole.manager).forEach(w => { - client - .query({ - query: gql` - query tenants($labels: String) { - tenants: itPolitoCrownlabsV1alpha2TenantList( - labelSelector: $labels - ) { - items { - metadata { - name - } - } + if (loadCandidates) { + const workspaceQueue: Workspace[] = []; + const executeNext = () => { + if (workspaceQueue.length > 0) { + 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]); } - } - `, - 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]); - } - }); - }); - }, [ws, client]); + 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/WorkspaceGridItem/WorkspaceGridItem.less b/frontend/src/components/workspaces/Grid/WorkspaceGridItem/WorkspaceGridItem.less index b3807db1b..d3c0971e1 100644 --- a/frontend/src/components/workspaces/Grid/WorkspaceGridItem/WorkspaceGridItem.less +++ b/frontend/src/components/workspaces/Grid/WorkspaceGridItem/WorkspaceGridItem.less @@ -14,9 +14,3 @@ border: solid @primary-color; border-width: 4px; } - -.grid-badge { - position: absolute; - right: 0; - top: 0; -} diff --git a/frontend/src/components/workspaces/Grid/WorkspaceGridItem/WorkspaceGridItem.tsx b/frontend/src/components/workspaces/Grid/WorkspaceGridItem/WorkspaceGridItem.tsx index 3be2d50de..40938e9e4 100644 --- a/frontend/src/components/workspaces/Grid/WorkspaceGridItem/WorkspaceGridItem.tsx +++ b/frontend/src/components/workspaces/Grid/WorkspaceGridItem/WorkspaceGridItem.tsx @@ -37,7 +37,11 @@ const WorkspaceGridItem: FC = ({ ...props }) => { {preview} {badgeValue && ( - + )} diff --git a/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesListLogic/WorkspacesListLogic.tsx b/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesListLogic/WorkspacesListLogic.tsx index c5447ff6c..144d8b328 100644 --- a/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesListLogic/WorkspacesListLogic.tsx +++ b/frontend/src/components/workspaces/WorkspaceAdd/WorkspacesListLogic/WorkspacesListLogic.tsx @@ -28,7 +28,7 @@ const WorkspaceListLogic: FC = ({ ...args }) => { const { data: tenantData } = useContext(TenantContext); const [workspaces, setWorkspaces] = useState(null); - const [aw, setAw] = useState([]); + const [availableWs, setAvailableWs] = useState([]); const { data, loading, error } = useWorkspacesQuery({ variables: { @@ -46,7 +46,9 @@ const WorkspaceListLogic: FC = ({ ...args }) => { }, [tenantData?.tenant?.spec?.workspaces]); useEffect(() => { - setAw(availableWorkspaces(data?.workspaces?.items ?? [], workspaces ?? [])); + setAvailableWs( + availableWorkspaces(data?.workspaces?.items ?? [], workspaces ?? []) + ); }, [workspaces, data]); const applyWorkspaces = async (w: { name: string; role: Role }[]) => { @@ -102,7 +104,10 @@ const WorkspaceListLogic: FC = ({ ...args }) => { return !loading && data && !error ? (
- +
) : (
diff --git a/frontend/src/components/workspaces/WorkspaceContainer/WorkspaceContainer.less b/frontend/src/components/workspaces/WorkspaceContainer/WorkspaceContainer.less deleted file mode 100644 index c69bc7224..000000000 --- a/frontend/src/components/workspaces/WorkspaceContainer/WorkspaceContainer.less +++ /dev/null @@ -1,11 +0,0 @@ -.tenant-button { - position: relative; -} -.candidate-badge { - position: absolute; - top: -10px; - right: -10px; -} -.tenant-button:active .candidate-badge, .tenant-button:focus .candidate-badge { - position: absolute!important; -} diff --git a/frontend/src/components/workspaces/WorkspaceContainer/WorkspaceContainer.tsx b/frontend/src/components/workspaces/WorkspaceContainer/WorkspaceContainer.tsx index 007163a77..8308e8acc 100644 --- a/frontend/src/components/workspaces/WorkspaceContainer/WorkspaceContainer.tsx +++ b/frontend/src/components/workspaces/WorkspaceContainer/WorkspaceContainer.tsx @@ -17,8 +17,6 @@ import { Image, Template } from '../ModalCreateTemplate/ModalCreateTemplate'; import { TemplatesTableLogic } from '../Templates/TemplatesTableLogic'; import Badge from '../../common/Badge'; -import './WorkspaceContainer.less'; - export interface IWorkspaceContainerProps { tenantNamespace: string; workspace: Workspace; @@ -126,7 +124,7 @@ const WorkspaceContainer: FC = ({ ...props }) => { ), left: workspace.role === 'manager' && (
- + diff --git a/frontend/src/utilsStorage.ts b/frontend/src/utilsStorage.ts index db92c4445..d588d94e3 100644 --- a/frontend/src/utilsStorage.ts +++ b/frontend/src/utilsStorage.ts @@ -7,6 +7,7 @@ export enum StorageKeys { // Dashboard Keys Dashboard_View = 'DashboardPageView', Dashboard_ID_T = 'DashboardPageTemplate', + Dashboard_LoadCandidates = 'DashboardPageLoadCandidates', } class StorageValue {