Skip to content

Commit

Permalink
🎁 [punch]: Enable 3D in sidesheet (#951)
Browse files Browse the repository at this point in the history
Added tooltip to info button on tag overlays in ModelViewer.
Fixed bug with not clearing selectedTags state variable.
  • Loading branch information
kjellhaaland authored Apr 15, 2024
1 parent 68fe781 commit 6d6f03e
Show file tree
Hide file tree
Showing 16 changed files with 190 additions and 44 deletions.
8 changes: 8 additions & 0 deletions apps/punch/app.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ export default () => ({
environment: {
uri: 'https://backend-fusion-data-gateway-test.radix.equinor.com',
defaultScopes: ['api://ed6de162-dd30-4757-95eb-0ffc8d34fbe0/access_as_user'],
modelViewerConfig: {
hierarchyClientBaseUrl: 'https://app-echo-hierarchy-dev.azurewebsites.net',
hierarchyClientScope: 'ebc04930-bf9c-43e5-98bc-bc90865600b8/user_impersonation',
modelClientBaseUrl: 'https://app-echomodeldist-dev.azurewebsites.net',
modelClientScope: 'd484c551-acf8-45bc-b1e8-3f4373bd0d42/user_impersonation',
echoClientBaseUrl: 'https://dt-echopedia-api-dev.azurewebsites.net',
echoClientScope: 'aef35d97-53d4-4fd0-adaf-c5a514b38436/user_impersonation',
},
},
endpoints: {},
});
8 changes: 8 additions & 0 deletions apps/punch/app.config.local.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ export default () => ({
environment: {
uri: 'https://localhost:7074',
defaultScopes: ['api://ed6de162-dd30-4757-95eb-0ffc8d34fbe0/access_as_user'],
modelViewerConfig: {
hierarchyClientBaseUrl: 'https://app-echo-hierarchy-dev.azurewebsites.net',
hierarchyClientScope: 'ebc04930-bf9c-43e5-98bc-bc90865600b8/user_impersonation',
modelClientBaseUrl: 'https://app-echomodeldist-dev.azurewebsites.net',
modelClientScope: 'd484c551-acf8-45bc-b1e8-3f4373bd0d42/user_impersonation',
echoClientBaseUrl: 'https://dt-echopedia-api-dev.azurewebsites.net',
echoClientScope: 'aef35d97-53d4-4fd0-adaf-c5a514b38436/user_impersonation',
},
},
endpoints: {},
});
5 changes: 3 additions & 2 deletions apps/punch/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"types": ["node"],
"rootDir": "."
},

"exclude": [
"jest.config.ts",
"**/*.spec.ts",
Expand All @@ -16,7 +15,9 @@
"**/*.test.js",
"**/*.spec.jsx",
"**/*.test.jsx",
"dist"
"dist",
"build.js",
"vite.config.ts"
],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
}
7 changes: 7 additions & 0 deletions apps/punch/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { defineConfig } from 'vite';
import EnvironmentPlugin from 'vite-plugin-environment';
import { InjectProcessPlugin } from '../../patches/3d-patch.ts';

export default defineConfig({
plugins: [
Expand All @@ -10,6 +11,12 @@ export default defineConfig({
appType: 'custom',
build: {
emptyOutDir: true,
rollupOptions: {
plugins: [InjectProcessPlugin],
output: {
inlineDynamicImports: true,
},
},
lib: {
entry: './src/main.tsx',
fileName: 'app-bundle',
Expand Down
73 changes: 73 additions & 0 deletions libs/modelviewer/src/components/tag-info/TagInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Typography, Icon, Button, Popover } from '@equinor/eds-core-react';
import { TagOverlay } from '../../types/overlayTags';
import * as Icons from '@equinor/eds-icons';
import { useRef, useState } from 'react';
import styled from 'styled-components';

interface TagInfoProps {
tag: TagOverlay;
}

export const defaultTagColor = '#a0dd28';

Icon.add(Icons);

export const TagInfo = (props: TagInfoProps) => {
const { tag } = props;

const [isOpen, setIsOpen] = useState(false);

const ref = useRef<HTMLButtonElement>(null);

const onClose = () => {
setIsOpen(false);
};

const onOpen = () => {
setIsOpen(true);
};

return (
<>
<StyledTagInfoIcon>
<Button
ref={ref}
variant="ghost_icon"
onClick={() => {
if (tag.action) tag.action(tag);
else onOpen();
}}
>
<Icon name="info_circle" title="tag information" />
</Button>
</StyledTagInfoIcon>

<Popover
open={isOpen}
id="tag-popover"
anchorEl={ref.current}
placement="bottom-end"
onClose={onClose}
>
<Popover.Header>
<Popover.Title>Details</Popover.Title>
<Button
style={{ height: '32px', width: '32px' }}
variant="ghost_icon"
aria-label="Close"
onClick={onClose}
>
<Icon name="close" size={24} />
</Button>
</Popover.Header>
<Popover.Content>
<Typography variant="body_short">{tag.description}</Typography>
</Popover.Content>
</Popover>
</>
);
};

const StyledTagInfoIcon = styled.div`
margin: 3px;
`;
18 changes: 2 additions & 16 deletions libs/modelviewer/src/components/tag-item/TagItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { TagOverlay } from '../../types/overlayTags';
import TagIcon from '../tag-icon/TagIcon';
import TagIconShadowWrapper from '../tag-icon-shadow/TagIconShadow';
import * as Icons from '@equinor/eds-icons';
import { TagInfo } from '../tag-info/TagInfo';

interface TagProps {
iconResolver?: (type: string) => string;
Expand Down Expand Up @@ -66,10 +67,6 @@ const StyledDescriptionTypography = styled(Typography)`
text-overflow: ellipsis;
`;

const StyledTagInfoIcon = styled.div`
margin: 3px;
`;

export const defaultTagColor = '#a0dd28';

Icon.add(Icons);
Expand Down Expand Up @@ -126,18 +123,7 @@ export const TagItem = ({
</StyledDescriptionTypography>
</TagText>

<StyledTagInfoIcon>
<Button
variant="ghost_icon"
onClick={(e) => {
tag.action && tag.action(tag);
e.stopPropagation();
e.preventDefault();
}}
>
<Icon name="info_circle" title="tag information"></Icon>
</Button>
</StyledTagInfoIcon>
<TagInfo tag={tag} />
</TagInfoWrapper>
</ContextWrapper>
);
Expand Down
10 changes: 8 additions & 2 deletions libs/modelviewer/src/hooks/useModelTags.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';

import { defaultTagColor } from '../components/tag-item/TagItem';
import { TagOverlay } from '../types/overlayTags';
Expand All @@ -20,7 +20,13 @@ export const useModelTags = (tagsOverlay: TagOverlay[]) => {
return { ...tagOverlay, color };
});

const [visibleTags, setVisibleTags] = useState<string[]>(tagList.map((x) => x.tagNo));
const [visibleTags, setVisibleTags] = useState<string[]>([]);

// When the tags overlay changes, reset state.
useEffect(() => {
const defaultVisibleTags = tagList.map((x) => x.tagNo);
setVisibleTags(defaultVisibleTags);
}, [tagsOverlay]);

return {
tagList,
Expand Down
7 changes: 3 additions & 4 deletions libs/modelviewer/src/hooks/useOverlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,9 @@ export function useOverlay() {
}
}, [echoInstance]);

const overlayTags = useMemo(
() => (tagsOverlay ? createOverlayTags(viewNodes, createTagMap(tagsOverlay)) : []),
[viewNodes, tagsOverlay]
);
const overlayTags = tagsOverlay
? createOverlayTags(viewNodes, createTagMap(tagsOverlay))
: [];

return { overlayTags, overlayTool };
}
25 changes: 11 additions & 14 deletions libs/modelviewer/src/providers/tagSelectionProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const TagSelectionProvider = (props: Props) => {
const config = useConfig();
const selectionControls = useModelSelectionControls();

const { visibleTags, tagList, setVisibleTags } = useModelTags(tagsOverlay);
const { tagList, visibleTags, setVisibleTags } = useModelTags(tagsOverlay);

const {
viewNodes,
Expand All @@ -59,19 +59,16 @@ export const TagSelectionProvider = (props: Props) => {
selectionControls?.cameraFirstPerson();
};

const fitCameraToAAbb = useCallback(
(aabb: AabbModel, duration?: number) => {
if (selectionControls) {
const box3 = selectionControls.getBoundingBoxFormAabbModel(aabb);
selectionControls.fitCameraToBox3(
box3,
duration || config.defaultCameraMoveDuration,
config.defaultRadiusFactor
);
}
},
[selectionControls]
);
const fitCameraToAAbb = (aabb: AabbModel, duration?: number) => {
if (selectionControls) {
const box3 = selectionControls.getBoundingBoxFormAabbModel(aabb);
selectionControls.fitCameraToBox3(
box3,
duration || config.defaultCameraMoveDuration,
config.defaultRadiusFactor
);
}
};

const toggleTags = (tags: string[]) => {
const elements: string[] = tags.reduce((acc, tag) => {
Expand Down
3 changes: 2 additions & 1 deletion libs/punchapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@cc-components/punchshared": "workspace:^",
"@cc-components/punchsidesheet": "workspace:^",
"@cc-components/shared": "workspace:^",
"@cc-components/sharedcomponents": "workspace:^"
"@cc-components/sharedcomponents": "workspace:^",
"@cc-components/modelviewer": "workspace:^"
}
}
5 changes: 4 additions & 1 deletion libs/punchapp/src/lib/config/frameworkConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
ComponentRenderArgs,
IAppConfigurator,
} from '@equinor/fusion-framework-react-app';
import { enableModelViewer, ModelViewerEnvConfig } from '@cc-components/modelviewer';

import { enableContext } from '@equinor/fusion-framework-react-module-context';
import buildQuery from 'odata-query';

Expand All @@ -21,7 +23,7 @@ export const configure = async (config: IAppConfigurator, c: ComponentRenderArgs
});
});

const envConfig: PunchEnvConfig = c.env.config?.environment as PunchEnvConfig;
const envConfig = c.env.config?.environment as PunchEnvConfig & ModelViewerEnvConfig;

if (!envConfig) {
throw new Error('Failed to load environemnt config for workorder');
Expand All @@ -32,6 +34,7 @@ export const configure = async (config: IAppConfigurator, c: ComponentRenderArgs
});

enableAgGrid(config);
enableModelViewer(config, envConfig);
};

type PunchEnvConfig = {
Expand Down
3 changes: 2 additions & 1 deletion libs/punchsidesheet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"dependencies": {
"@cc-components/punchshared": "workspace:^",
"@cc-components/shared": "workspace:^",
"@cc-components/sharedcomponents": "workspace:^"
"@cc-components/sharedcomponents": "workspace:^",
"@cc-components/modelviewer": "workspace:^"
}
}
39 changes: 37 additions & 2 deletions libs/punchsidesheet/src/lib/ui-sidesheet/PunchSidesheet.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import { Punch } from '@cc-components/punchshared';
import { LinkCell, useContextId, useHttpClient } from '@cc-components/shared';
import { Punch, PunchStatus } from '@cc-components/punchshared';
import {
BaseStatus,
LinkCell,
colorMap,
hasProperty,
useContextId,
useHttpClient,
} from '@cc-components/shared';

import { statusColorMap } from '@cc-components/shared/mapping';

import {
BannerItem,
SidesheetHeader,
Expand All @@ -9,11 +19,24 @@ import {
StyledSideSheetContainer,
StyledTabs,
} from '@cc-components/sharedcomponents';

import { ModelViewerTab } from '@cc-components/modelviewer';

import { Tabs } from '@equinor/eds-core-react';
import { useQuery } from '@tanstack/react-query';
import { useRef, useState } from 'react';
import { DetailsTab } from './DetailsTab';
import { StyledTabListWrapper, StyledTabsList } from './sidesheet.styles';
import { useModelViewerTags } from '../utils-sidesheet/useModelViewerTags';

const viewerOptions = {
statusResolver: (status: string) => {
return hasProperty(colorMap, status)
? statusColorMap[status as BaseStatus]
: '#9e9e9e';
},
defaultCroppingDistance: 3,
};

export const PunchSidesheet = (props: {
id: string;
Expand Down Expand Up @@ -48,6 +71,8 @@ export const PunchSidesheet = (props: {
}
);

const tagsOverlay = useModelViewerTags(punch);

if (isLoadingSidesheet) {
return <SidesheetSkeleton close={props.close} />;
}
Expand Down Expand Up @@ -117,13 +142,23 @@ export const PunchSidesheet = (props: {
<StyledTabListWrapper>
<StyledTabsList ref={ref}>
<Tabs.Tab>Details </Tabs.Tab>
<Tabs.Tab>3D </Tabs.Tab>
</StyledTabsList>
</StyledTabListWrapper>

<StyledPanels>
<Tabs.Panel>
<DetailsTab punch={punch} />
</Tabs.Panel>
<Tabs.Panel style={{ height: '100%' }}>
<ModelViewerTab
tagOverlay={tagsOverlay}
options={viewerOptions}
isFetching={false}
error={null}
facilities={[punch.facility ?? '']}
/>
</Tabs.Panel>
</StyledPanels>
</StyledTabs>
</StyledSideSheetContainer>
Expand Down
15 changes: 15 additions & 0 deletions libs/punchsidesheet/src/lib/utils-sidesheet/useModelViewerTags.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Punch } from '@cc-components/punchshared';
import { TagOverlay } from '@cc-components/modelviewer';

export const useModelViewerTags = (punch?: Punch): TagOverlay[] => {
if (!punch) return [];

return [
{
tagNo: punch.tagNo ?? 'No tag',
description: punch.description ?? 'No description',
status: punch.category,
icon: <h3>{punch.category}</h3>,
},
];
};
2 changes: 1 addition & 1 deletion patches/3d-patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ var production = "production";

export const InjectProcessPlugin = {
name: 'rollup-plugin-metadata',
renderChunk: (code) => fix + code,
renderChunk: (code: any) => fix + code,
};
Loading

0 comments on commit 6d6f03e

Please sign in to comment.