diff --git a/.changeset/pr-808-2100756531.md b/.changeset/pr-808-2100756531.md new file mode 100644 index 000000000..82e3ec560 --- /dev/null +++ b/.changeset/pr-808-2100756531.md @@ -0,0 +1,5 @@ + +--- +"fusion-project-portal": patch +--- +Fix errors and add data owner on milestones diff --git a/client/packages/components/src/components/my-roles-tab/hooks/use-update-my-roles-query.ts b/client/packages/components/src/components/my-roles-tab/hooks/use-update-my-roles-query.ts index f00167dbc..dee948cbf 100644 --- a/client/packages/components/src/components/my-roles-tab/hooks/use-update-my-roles-query.ts +++ b/client/packages/components/src/components/my-roles-tab/hooks/use-update-my-roles-query.ts @@ -35,7 +35,7 @@ export const useUpdateUserRoleQuery = (roles?: Role[], userId?: string) => { const data = await ( await client ).json(`/persons/${userId}/roles/${roleName}`, { - method: 'Patch', + method: 'PATCH', body: JSON.stringify({ isActive }), }); diff --git a/client/packages/portal-pages/src/pages/project-page/components/milestones/LoadingSection.tsx b/client/packages/portal-pages/src/pages/project-page/components/milestones/LoadingSection.tsx index 502976a25..b8d13ec8c 100644 --- a/client/packages/portal-pages/src/pages/project-page/components/milestones/LoadingSection.tsx +++ b/client/packages/portal-pages/src/pages/project-page/components/milestones/LoadingSection.tsx @@ -16,6 +16,9 @@ export const LoadingSkeleton = () => ( + + + @@ -30,6 +33,9 @@ export const LoadingSkeleton = () => ( + + + @@ -44,6 +50,9 @@ export const LoadingSkeleton = () => ( + + + @@ -58,6 +67,9 @@ export const LoadingSkeleton = () => ( + + + ); diff --git a/client/packages/portal-pages/src/pages/project-page/components/milestones/Milestones.tsx b/client/packages/portal-pages/src/pages/project-page/components/milestones/Milestones.tsx index 0dc9ef905..182f5c535 100644 --- a/client/packages/portal-pages/src/pages/project-page/components/milestones/Milestones.tsx +++ b/client/packages/portal-pages/src/pages/project-page/components/milestones/Milestones.tsx @@ -1,4 +1,4 @@ -import { EdsProvider, Table, Typography } from '@equinor/eds-core-react'; +import { Card, EdsProvider, Table, Typography } from '@equinor/eds-core-react'; import { DateTime } from 'luxon'; import { StyledCardWrapper, StyledContent, StyledHeader } from '../project-cards/styles'; import { LoadingSkeleton } from './LoadingSection'; @@ -7,6 +7,8 @@ import { css } from '@emotion/css'; import { Message } from '@portal/ui'; import { sortByDate, sortMilestones } from './utils'; import { useMemo } from 'react'; +import { DataInfo } from '../../../sheared/components/data-info/DataInfo'; +import styled from 'styled-components'; function verifyDate(date?: string | null): string { return new Date(date || '').toString() !== 'Invalid Date' @@ -14,22 +16,19 @@ function verifyDate(date?: string | null): string { : '-'; } -const styles = { - fullWidth: css` - width: 100%; - `, - noContent: css` - width: 100%; - height: 200px; - display: flex; - justify-content: center; +const Styled = { + Wrapper: styled.div` + max-height: 350px; + overflow: auto; + display: 'grid'; `, - noWrap: css` - width: 1000px; + NoWrap: styled(Table.Cell)` overflow: hidden; text-overflow: ellipsis; `, - table: css` + Table: styled(Table)` + width: 100%; + white-space: nowrap; min-width: fit-content; table-layout: fixed; @@ -39,69 +38,85 @@ const styles = { export const Milestones = () => { const { data, isLoading, error } = useMilestoneQuery(); - const componentError = error as Error | undefined; - const milestones = useMemo(() => { return data?.sort(sortMilestones).sort(sortByDate) || []; }, [data]); return ( - - + + Milestones - - {componentError ? ( - componentError.message.toLowerCase() === 'No Access'.toLowerCase() ? ( - + + + {error ? ( + error.error.code === 'NoDataAccess' ? ( + `${a.code} - ${a.description}`) + : [] + } + > + ) : error.error.exceptionType === 'NotFoundError' ? ( + ) : ( - - {componentError.message} - + ) ) : ( - + - - - - Milestone - Description - Planned - Forecast - - - - {isLoading ? ( - - ) : milestones.length > 0 ? ( - milestones.map((milestone) => { - const datePlanned = verifyDate(milestone.datePlanned); - const dateForecast = verifyDate(milestone.dateForecast); - return ( - - - {milestone.milestone} - - - {milestone.description} - - {datePlanned} - {dateForecast} - - ); - }) - ) : ( -
- - There are no milestones awaitable - -
- )} -
-
+ + + + + Milestone + Description + Planned + Forecast + Actual + + + + {isLoading ? ( + + ) : milestones.length > 0 ? ( + milestones.map((milestone) => { + const datePlanned = verifyDate(milestone.datePlanned); + const dateForecast = verifyDate(milestone.dateForecast); + const dateActual = verifyDate(milestone.dateActual); + return ( + + + {milestone.milestone} + + + {milestone.description} + + {datePlanned} + {dateForecast} + {dateActual} + + ); + }) + ) : ( + + )} + + +
-
+ )} -
+ ); }; diff --git a/client/packages/portal-pages/src/pages/project-page/components/milestones/use-presence-query.ts b/client/packages/portal-pages/src/pages/project-page/components/milestones/use-presence-query.ts index 0a428fd2b..e844bcaff 100644 --- a/client/packages/portal-pages/src/pages/project-page/components/milestones/use-presence-query.ts +++ b/client/packages/portal-pages/src/pages/project-page/components/milestones/use-presence-query.ts @@ -14,6 +14,21 @@ export type Milestones = { contractMilestone: string; }; +type MilestoneError = { + error: { + message: string; + code: string; + exceptionType?: string; + accessRequirements: { + code: string; + description: string; + }[]; + }; + title: string; + detail: string; + message: string; +}; + export async function getMilestones( client: IHttpClient, contextId?: string, @@ -23,10 +38,16 @@ export async function getMilestones( const res = await client.fetch(`/api/contexts/${contextId}/milestones`, { signal }); - if (res.status === 403) throw new Error('No access'); + if (res.status === 403) { + const error = (await res.json()) as MilestoneError; + throw error; + } + if (res.status === 404) { + const error = (await res.json()) as MilestoneError; + throw error; + } const data = (await res.json()) as Milestones[]; - if (res.status === 400 && (data as unknown as { detail: string }).detail.includes('Forbidden')) { throw new Error('No access'); } @@ -36,6 +57,7 @@ export async function getMilestones( } if (!res.ok) throw new Error('Unknown Error'); + return data; } @@ -43,8 +65,10 @@ export const useMilestoneQuery = () => { const client = useFramework().modules.serviceDiscovery.createClient('data-proxy'); const { currentContext } = useFramework().modules.context; const contextId = currentContext?.id; - return useQuery({ + + return useQuery({ queryKey: ['milestones', contextId], queryFn: async ({ signal }) => getMilestones(await client, contextId, signal), + enabled: Boolean(contextId), }); }; diff --git a/client/packages/portal-pages/src/pages/sheared/components/data-info/DataInfo.tsx b/client/packages/portal-pages/src/pages/sheared/components/data-info/DataInfo.tsx new file mode 100644 index 000000000..a417a964a --- /dev/null +++ b/client/packages/portal-pages/src/pages/sheared/components/data-info/DataInfo.tsx @@ -0,0 +1,67 @@ +import { Icon, Popover, Typography } from '@equinor/eds-core-react'; +import { info_circle, title } from '@equinor/eds-icons'; +import { tokens } from '@equinor/eds-tokens'; +import { PersonCell } from '@equinor/fusion-react-person'; +import { useRef, useState } from 'react'; +import styled from 'styled-components'; + +type DataInfoProps = { + title: string; + dataSource: string; + azureUniqueId?: string; + access: 'Internal' | 'External' | 'Restricted'; +}; + +const Style = { + Content: styled.div` + display: flex; + flex-direction: column; + gap: 1rem; + min-width: 200px; + `, +}; + +export const DataInfo = ({ dataSource, azureUniqueId, access, title }: DataInfoProps) => { + const referenceElement = useRef(null); + const [isOpen, setIsOpen] = useState(false); + + return ( +
{ + setIsOpen(true); + }} + onMouseLeave={() => { + setIsOpen(false); + }} + ref={referenceElement} + > + + + {title} + + +
+ Data source: + + {dataSource} + +
+
+ Access: + + {access} + +
+ + {azureUniqueId && ( + <> + Contact person + u.mail} /> + + )} +
+
+
+
+ ); +}; diff --git a/client/yarn.lock b/client/yarn.lock index 1558bc54d..55b7a69f5 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -1201,6 +1201,11 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.8.tgz#21a907684723bbbaa5f0974cf7730bd797eb8e62" integrity sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig== +"@floating-ui/utils@^0.2.8": + version "0.2.8" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.8.tgz#21a907684723bbbaa5f0974cf7730bd797eb8e62" + integrity sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig== + "@hirez_io/observer-spy@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@hirez_io/observer-spy/-/observer-spy-2.2.0.tgz#3b1df531ba333a9a6cbbec0333d3fbdc4c68cc3c" @@ -1417,6 +1422,13 @@ dependencies: "@lit-labs/ssr-dom-shim" "^1.0.0" +"@lit/reactive-element@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-2.0.4.tgz#8f2ed950a848016383894a26180ff06c56ae001b" + integrity sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ== + dependencies: + "@lit-labs/ssr-dom-shim" "^1.2.0" + "@lit/task@^1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/@lit/task/-/task-1.0.1.tgz#7462aeaa973766822567f5ca90fe157404e8eb81" @@ -4048,6 +4060,11 @@ csstype@^3.0.2, csstype@^3.1.3: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== +csstype@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + damerau-levenshtein@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" @@ -6526,6 +6543,15 @@ lit@3.2.0: lit-element "^4.1.0" lit-html "^3.2.0" +lit@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lit/-/lit-3.2.0.tgz#2189d72bccbc335f733a67bfbbd295f015e68e05" + integrity sha512-s6tI33Lf6VpDu7u4YqsSX78D28bYQulM+VAzsGch4fx2H0eLZnJsUBsPWmGYSGoKDNbjtRv02rio1o+UdPVwvw== + dependencies: + "@lit/reactive-element" "^2.0.4" + lit-element "^4.1.0" + lit-html "^3.2.0" + lit@^2.0.0: version "2.8.0" resolved "https://registry.yarnpkg.com/lit/-/lit-2.8.0.tgz#4d838ae03059bf9cafa06e5c61d8acc0081e974e"