diff --git a/example/react/components/FlexLayout.tsx b/example/react/components/FlexLayout.tsx index 8b6722a..ab4fde1 100644 --- a/example/react/components/FlexLayout.tsx +++ b/example/react/components/FlexLayout.tsx @@ -6,6 +6,7 @@ import Three from './Three'; import Issues from './Issues'; import IssueSorter from './IssueSorter'; import IssueDetails from './IssueDetails'; +import Settings from './Settings'; function LeftFlexLayout() { return ; @@ -24,7 +25,7 @@ function RightTopFlexLayout() { - + }> diff --git a/example/react/components/Settings.tsx b/example/react/components/Settings.tsx new file mode 100644 index 0000000..1a1578e --- /dev/null +++ b/example/react/components/Settings.tsx @@ -0,0 +1,151 @@ +import React, { useState } from 'react'; +import { useSelector } from 'react-redux'; + +import SettingsIcon from '@mui/icons-material/Settings'; +import Box from '@mui/material/Box'; + +import Button from '@mui/material/Button'; +import Drawer from '@mui/material/Drawer'; +import CardContent from '@mui/material/CardContent'; +import Typography from '@mui/material/Typography'; + +import SettingsTwoToneIcon from '@mui/icons-material/SettingsTwoTone'; +import Panel from './Panel'; + +import { DataGrid } from '@mui/x-data-grid'; +import type { GridRenderCellParams, GridColDef, GridRowSelectionModel } from '@mui/x-data-grid'; +import Checkbox from '@mui/material/Checkbox'; + +import VisibilityIcon from '@mui/icons-material/Visibility'; +import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; +import { RootState } from '../state/store'; +import { IFCSomething } from '../../types'; +import BCFViewer from '../../viewer/BCFViewer'; + +function RenderCheckBox(props: GridRenderCellParams) { + const [checked, setChecked] = React.useState(props.value); + + const handleChange = (event: React.ChangeEvent) => { + setChecked(event.target.checked); + BCFViewer.setVisibility([props.id as number], event.target.checked); + }; + + return ( + } + checkedIcon={} + checked={checked} + onChange={handleChange} + /> + ); +} + +const columns: GridColDef[] = [ + { field: 'type', headerName: 'Type', width: 100 }, + { field: 'objectType', headerName: 'Object Type', width: 250 }, + { field: 'name', headerName: 'Name', width: 380 }, + { + field: 'visible', + headerName: 'Visible', + width: 100, + renderCell: RenderCheckBox, + }, +]; + +function getRowId(row: IFCSomething) { + return row.expressID; +} + +const onRowSelectionModelChange = (rowSelectionModel: GridRowSelectionModel) => { + BCFViewer.setSelection(rowSelectionModel as number[]); +}; + +function SettingsContent() { + const state = useSelector((store: RootState) => store.bcf.IFCSomething); + + return ( + + + + + This panel allows you to control the selection and visibility of the + elements in the model. +
+ These settings are unique to each BCF issue. +
+
+ + This means that you can have different settings for each BCF issue. + +
+ + The checkbox controls the selection. A selected object will be highlighted + in green. +
+ The eye icon controls the visibility of the object. +
+
+ N.B: A hidden object will be highlighted if selected (!). +
+
+ + + +
+
+
+ ); +} + +export default function Settings() { + const [open, setOpen] = useState(false); + + const onClick = () => { + setOpen((prev) => !prev); + }; + + return ( + <> + + { + setOpen(false); + }} + variant="persistent" + hideBackdrop={true} + PaperProps={{ + sx: { + backgroundColor: 'rgba(0,0,0,0.1)', + backdropFilter: 'blur(5px)', + }, + }} + > + + + + ); +} diff --git a/example/react/state/bcfSlice.ts b/example/react/state/bcfSlice.ts index a78fadc..00eea09 100644 --- a/example/react/state/bcfSlice.ts +++ b/example/react/state/bcfSlice.ts @@ -2,7 +2,7 @@ import { createSlice } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit'; // @ts-ignore import worker from '../../../src/worker/worker?worker'; -import { TopicCameraState } from '../../types'; +import { IFCSomething, TopicCameraState } from '../../types'; import BCFViewer from '../../viewer/BCFViewer'; import * as BCF from '../../../src'; import type { @@ -15,6 +15,7 @@ import { Coloring_Three, Component_Three, Components_Three, + Selection_Three, TopicViewpoint_Three, } from '../../../src/three'; @@ -25,11 +26,13 @@ const bcf = new BCF.ThreeBCF({ export type BCFState = { topics: TopicFolder_ThreeJSON[]; selectedTopic: TopicFolder_ThreeJSON | null; + IFCSomething: IFCSomething[]; }; const initialState: BCFState = { topics: [], selectedTopic: null, + IFCSomething: [], }; type CreateTopicParams = { @@ -85,25 +88,38 @@ export const bcfSlice = createSlice({ const viewpoint = new TopicViewpoint_Three(screenshot); topic.addViewpoint(viewpoint); + // Determine selection + const selectionState = BCFViewer.getSelection(); + const components = new Components_Three(); + const selection = new Selection_Three(); + components.addSelection(selection); + const coloring = new Coloring_Three(); components.addColoring(coloring); coloring.setColor('FF00FF00'); - const component = new Component_Three(); const { componentState } = BCFViewer; if (componentState) { - const { ifcGuid, originatingSystem, authoringToolId } = componentState; - component.set({ - ifcGuid, - originatingSystem, - authoringToolId, + selectionState.forEach((selectedObject) => { + const state = componentState[selectedObject]; + if (state == null) return; + const component = new Component_Three(); + + const { ifcGuid, originatingSystem, authoringToolId } = state; + component.set({ + ifcGuid, + originatingSystem, + authoringToolId, + }); + + coloring.addComponent(component); + selection.addComponent(component); }); } - coloring.addComponent(component); topic.addComponents(components); @@ -339,6 +355,9 @@ export const bcfSlice = createSlice({ header, }); }, + setIFCSomething: (state, action: PayloadAction) => { + state.IFCSomething = action.payload; + }, }, }); @@ -353,6 +372,7 @@ export const { addTopicComment, updateTopicComment, removeTopicComment, + setIFCSomething, } = bcfSlice.actions; export default bcfSlice.reducer; diff --git a/example/types.ts b/example/types.ts index 2d0cad6..d066835 100644 --- a/example/types.ts +++ b/example/types.ts @@ -1,4 +1,5 @@ import * as THREE from 'three'; + import type { TopicFolderBase_Three } from '../src/types'; export interface CameraControlsState { @@ -16,3 +17,12 @@ export interface BCFCameraState { position: THREE.Vector3Tuple; up: THREE.Vector3Tuple; } + +export type IFCSomething = { + expressID: number; + type: string; + objectType: string; + name: string; + selected: boolean; + visible: boolean; +}; diff --git a/example/viewer/Viewer.ts b/example/viewer/Viewer.ts index ece7c66..5b719cb 100644 --- a/example/viewer/Viewer.ts +++ b/example/viewer/Viewer.ts @@ -6,12 +6,15 @@ import { computeBoundsTree, disposeBoundsTree, acceleratedRaycast } from 'three- import Stats from 'three/addons/libs/stats.module.js'; import { IFCLoader } from 'web-ifc-three/IFCLoader'; +import type { Subset } from 'web-ifc-three/IFC/components/subsets/SubsetManager.d.ts'; import { IFCAPPLICATION } from 'web-ifc'; // @ts-ignore import ifc from '../../resources/example_4.ifc?url'; -import { CameraControlsState, BCFCameraState } from '../types'; +import { CameraControlsState, BCFCameraState, IFCSomething } from '../types'; import { Component_Core } from '../../src/core/topic'; +import { store } from '../react/state/store'; +import { setIFCSomething } from '../react/state/bcfSlice'; CameraControls.install({ THREE: THREE }); // @ts-ignore @@ -20,6 +23,16 @@ THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree; THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree; THREE.Mesh.prototype.raycast = acceleratedRaycast; +const model = { id: -1 }; + +const preselectMat = new THREE.MeshLambertMaterial({ + // transparent: true, + // opacity: 1, + color: 0x00ff00, + // depthTest: false, +}); + +let previousSelection: number[] | null = null; /** * THREE Viewer as singleton. */ @@ -57,10 +70,15 @@ export default class THREEViewer { public ifcLoader!: IFCLoader; - public componentState: Component_Core | null = null; + public componentState: { [key: string]: Component_Core } = {}; public originatingSystem: string = ''; + public ifcObjects: { [key: number]: Subset } = {}; + + private selection: number[] = []; + private visibility: number[] = []; + init(container: HTMLElement = document.body) { this.container = container; this.ifcModels = []; @@ -108,57 +126,42 @@ export default class THREEViewer { this.container.addEventListener('pointermove', onPointerMove); - const model = { id: -1 }; - - const preselectMat = new THREE.MeshLambertMaterial({ - transparent: true, - opacity: 1, - color: 0x00ff00, - depthTest: false, - }); - - this.container.addEventListener('pointerdown', (event: PointerEvent) => { - if (event.button === 2 || event.pointerType === 'touch') { - this.ifcLoader.ifcManager.removeSubset(model.id, preselectMat); - } else { - this.raycaster.setFromCamera(this.pointer, this.camera); - const found = this.raycaster.intersectObjects(this.ifcModels)[0]; - - if (found) { - // Gets model ID - model.id = (found.object as any).modelID; - - // Gets Express ID - const index = found.faceIndex; - if (index == null) throw new Error('Face index is null'); - const geometry = (found.object as THREE.Mesh).geometry; - const id = this.ifcLoader.ifcManager.getExpressId(geometry, index); - this.ifcLoader.ifcManager.getItemProperties(model.id, id).then((props) => { - const originatingSystem = this.originatingSystem; - const ifcGuid = props.GlobalId.value; - const authoringToolId = props.Tag.value; - - const component: Component_Core = { - ifcGuid, - authoringToolId, - originatingSystem, - }; - - this.setComponentState(component); - }); - - // Creates subset - this.ifcLoader.ifcManager.createSubset({ - modelID: model.id, - ids: [id], - material: preselectMat, - scene: this.scene, - removePrevious: true, - }); - } else { - this.ifcLoader.ifcManager.removeSubset(model.id, preselectMat); - } - } + this.container.addEventListener('pointerdown', (_event: PointerEvent) => { + // if (event.button === 2 || event.pointerType === 'touch') { + // this.ifcLoader.ifcManager.removeSubset(model.id, preselectMat); + // } else { + // this.raycaster.setFromCamera(this.pointer, this.camera); + // const found = this.raycaster.intersectObjects(this.ifcModels)[0]; + // if (found) { + // // Gets Express ID + // const index = found.faceIndex; + // if (index == null) throw new Error('Face index is null'); + // const geometry = (found.object as THREE.Mesh).geometry; + // const id = this.ifcLoader.ifcManager.getExpressId(geometry, index); + // console.log('id', id); + // this.ifcLoader.ifcManager.getItemProperties(model.id, id).then((props) => { + // const originatingSystem = this.originatingSystem; + // const ifcGuid = props.GlobalId.value; + // const authoringToolId = props.Tag.value; + // const component: Component_Core = { + // ifcGuid, + // authoringToolId, + // originatingSystem, + // }; + // this.setComponentState(component); + // }); + // // Creates subset + // this.ifcLoader.ifcManager.createSubset({ + // modelID: model.id, + // ids: [id], + // material: preselectMat, + // scene: this.scene, + // removePrevious: true, + // }); + // } else { + // this.ifcLoader.ifcManager.removeSubset(model.id, preselectMat); + // } + // } }); const resize = (): void => { @@ -229,18 +232,88 @@ export default class THREEViewer { }); // Should work for GH Pages this.ifcLoader.ifcManager.setWasmPath('../'); + this.ifcLoader.load(ifc, async (ifcModel) => { this.ifcModels.push(ifcModel); - this.scene.add(ifcModel); - this.cameraControls.fitToSphere(this.scene, false); + this.cameraControls.polarAngle = Math.PI / 4; + model.id = ifcModel.modelID; + const [ifcApplication] = await this.ifcLoader.ifcManager.getAllItemsOfType( ifcModel.modelID, IFCAPPLICATION, true, ); this.originatingSystem = ifcApplication.ApplicationFullName.value; + + const spatialStructure = await this.ifcLoader.ifcManager.getSpatialStructure( + ifcModel.modelID, + true, + ); + console.log('spatialStructure', spatialStructure); + const ifcSite = spatialStructure.children[0]; + const ifcBuilding = ifcSite.children[0]; + + const ifc = ifcBuilding.children.flatMap((ifcBuildingStorey: any) => { + const objects: IFCSomething[] = []; + ifcBuildingStorey.children.forEach((object: any) => { + const { + expressID, + type, + PredefinedType: { value: predefinedType }, + ObjectType: { value: objectType }, + Name: { value: name }, + } = object; + + if (type === 'IFCBUILDINGELEMENTPROXY' || type === 'IFCROOF') return; + + const subset = this.ifcLoader.ifcManager.createSubset({ + modelID: model.id, + scene: this.scene, + ids: [expressID], + removePrevious: false, + customID: `${type}-${expressID}`, + }); + + this.visibility.push(expressID); + this.ifcObjects[expressID] = subset; + this.scene.add(subset); + + this.ifcLoader.ifcManager + .getItemProperties(model.id, expressID) + .then((props) => { + const originatingSystem = this.originatingSystem; + const ifcGuid = props.GlobalId.value; + const authoringToolId = props.Tag.value; + + const component: Component_Core = { + uuid: THREE.MathUtils.generateUUID(), + ifcGuid, + authoringToolId, + originatingSystem, + }; + + this.componentState[expressID] = component; + }); + + const ifcObject: IFCSomething = { + expressID, + type: predefinedType === 'NOTDEFINED' ? type : predefinedType, + objectType, + name, + selected: false, + visible: true, + }; + objects.push(ifcObject); + }); + return objects; + }); + + store.dispatch(setIFCSomething(ifc)); + + // await setupAllCategories(); + this.cameraControls.fitToSphere(this.scene, false); }); } @@ -317,7 +390,49 @@ export default class THREEViewer { return bcfCameraState; } - private setComponentState(componentState: Component_Core) { - this.componentState = componentState; + // private setComponentState(componentState: Component_Core) { + // this.componentState = componentState; + // } + + public setSelection(expressIDs: number[]) { + if (previousSelection) { + this.setVisibility(previousSelection, true); + } + this.selection = expressIDs; + + this.ifcLoader.ifcManager.removeSubset(model.id, preselectMat); + + this.ifcLoader.ifcManager.createSubset({ + modelID: model.id, + ids: expressIDs, + material: preselectMat, + scene: this.scene, + removePrevious: true, + }); + + this.setVisibility(expressIDs, false); + previousSelection = expressIDs; + } + + getSelection() { + return [...this.selection]; + } + + public setVisibility(expressIDs: number[], visible: boolean) { + expressIDs.forEach((expressID) => { + const subset = this.ifcObjects[expressID]; + subset.visible = visible; + + if (visible) { + if (!this.visibility.includes(expressID)) this.visibility.push(expressID); + } else { + const index = this.visibility.indexOf(expressID); + if (index > -1) this.visibility.splice(index, 1); + } + }); + } + + getVisibility() { + return [...this.visibility]; } } diff --git a/package.json b/package.json index d7e2097..38d3ea5 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@fontsource/roboto": "^5.0.4", "@mui/icons-material": "^5.13.7", "@mui/material": "^5.13.7", - "@mui/x-data-grid": "^6.13.0", + "@mui/x-data-grid": "^6.16.0", "@mui/x-date-pickers": "^6.14.0", "@reduxjs/toolkit": "^1.9.5", "@types/file-saver": "^2.0.5", diff --git a/src/core/topic.ts b/src/core/topic.ts index f8730c4..3178e64 100644 --- a/src/core/topic.ts +++ b/src/core/topic.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import BCFBaseSchema from './zod'; -export const ComponentSchema_Core = z.object({ +export const ComponentSchema_Core = BCFBaseSchema.extend({ /** * The IfcGuid of the component */ @@ -22,7 +22,7 @@ export type Component_Core = z.infer; /** * The `Coloring` element allows specifying the color of {@link Component_Core | components}. */ -export const ColoringSchema_Core = z.object({ +export const ColoringSchema_Core = BCFBaseSchema.extend({ /** * The color is given in ARGB format. Colors are represented as 6 or 8 hexadecimal digits. * If 8 digits are present, the first two represent the alpha (transparency) channel. @@ -43,6 +43,21 @@ export const ColoringSchema_Core = z.object({ */ export type Coloring_Core = z.infer; +/** + * The `Selection` element lists all components that should be selected (highlighted) when displaying a viewpoint. + */ +export const SelectionSchema_Core = BCFBaseSchema.extend({ + /** + * All components that should be selected (highlighted) when displaying a viewpoint. + */ + components: z.array(ComponentSchema_Core), +}); + +/** + * The `Selection` element lists all components that should be selected (highlighted) when displaying a viewpoint. + */ +export type Selection_Core = z.infer; + export const ComponentsSchema_Core = BCFBaseSchema.extend({ /** * The `Selection` element lists all components that should be selected (highlighted) when displaying a viewpoint. @@ -52,7 +67,7 @@ export const ComponentsSchema_Core = BCFBaseSchema.extend({ * * If the size of the selected components is huge (over 1000 components), alert the user and ask them to reduce the number of selected components. */ - selection: z.any(), + selection: z.array(SelectionSchema_Core), /** * The `Visibility` element decides which objects are visible and which are hidden. * diff --git a/src/core/zod.ts b/src/core/zod.ts index 00075d2..4b6d469 100644 --- a/src/core/zod.ts +++ b/src/core/zod.ts @@ -4,4 +4,6 @@ const BCFBaseSchema = z.object({ uuid: z.string().uuid(), }); +export type BCFBase = z.infer; + export default BCFBaseSchema; diff --git a/src/three-bcf/topic/viewpoint.ts b/src/three-bcf/topic/viewpoint.ts index 39a7405..66b81b7 100644 --- a/src/three-bcf/topic/viewpoint.ts +++ b/src/three-bcf/topic/viewpoint.ts @@ -35,11 +35,27 @@ class ViewpointFactory_XML extends Topic_XML { const { components: _components } = e; _components.forEach((components) => { - const { coloring: _coloring } = components; + const { coloring: _coloring, selection: _selection } = components; const xmlComponents = root.ele('Components'); // Add Selection element - xmlComponents.ele('Selection'); + _selection.forEach((selection) => { + const { components } = selection; + const xmlSelection = xmlComponents.ele('Selection'); + + components.forEach((component) => { + const { ifcGuid, originatingSystem, authoringToolId } = component; + + // IFC GUID is required + if (!ifcGuid) return; + + const xmlComponent = xmlSelection.ele('Component').att('IfcGuid', ifcGuid); + + if (originatingSystem) + xmlComponent.ele('OriginatingSystem').txt(originatingSystem); + if (authoringToolId) xmlComponent.ele('AuthoringToolId').txt(authoringToolId); + }); + }); // Add Visibility element const xmlVisibility = xmlComponents.ele('Visibility'); @@ -51,8 +67,6 @@ class ViewpointFactory_XML extends Topic_XML { .att('OpeningsVisible', 'false'); xmlVisibility.ele('Exceptions'); - // TODO: Coloring is empty!!! - // Add Coloring element _coloring.forEach((coloring) => { const { color, components } = coloring; diff --git a/src/three/topic.ts b/src/three/topic.ts index 486efdc..8c97940 100644 --- a/src/three/topic.ts +++ b/src/three/topic.ts @@ -10,17 +10,20 @@ import { TopicComment_Core, TopicViewpoint_Core, Coloring_Core, + Selection_Core, } from '../core'; /** * See {@link Component_Core}. */ export class Component_Three implements Component_Core { + uuid: string; ifcGuid: string; originatingSystem: string; authoringToolId: string; constructor() { + this.uuid = THREE.MathUtils.generateUUID(); this.ifcGuid = ''; this.originatingSystem = ''; this.authoringToolId = ''; @@ -52,6 +55,7 @@ export class Component_Three implements Component_Core { toJSON(): Component_Core { return { + uuid: this.uuid, ifcGuid: this.ifcGuid, originatingSystem: this.originatingSystem, authoringToolId: this.authoringToolId, @@ -73,11 +77,14 @@ export class Coloring_Three implements Coloring_Core { */ private static regex = /^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6})$/; + uuid: string; + color: string; components: Component_Three[]; constructor() { + this.uuid = THREE.MathUtils.generateUUID(); this.color = ''; this.components = []; } @@ -120,6 +127,7 @@ export class Coloring_Three implements Coloring_Core { } fromJSON(json: Coloring_Core) { + this.uuid = json.uuid; this.color = json.color; this.components = json.components.map((c) => { const component = new Component_Three(); @@ -130,23 +138,70 @@ export class Coloring_Three implements Coloring_Core { toJSON(): Coloring_Core { return { + uuid: this.uuid, color: this.color, components: this.components.map((c) => c.toJSON()), }; } } + +/** + * See {@link Selection_Core}. + */ +export class Selection_Three implements Selection_Core { + uuid: string; + components: Component_Three[]; + + constructor() { + this.uuid = THREE.MathUtils.generateUUID(); + this.components = []; + } + + addComponent(component: Component_Three) { + this.components.push(component); + } + + updateComponent(component: Component_Three) { + const index = this.components.findIndex((c) => c.ifcGuid === component.ifcGuid); + if (index === -1) throw new Error('Component not found'); + this.components[index] = component; + } + + removeComponent(ifcGuid: string) { + const index = this.components.findIndex((c) => c.ifcGuid === ifcGuid); + if (index === -1) throw new Error('Component not found'); + this.components.splice(index, 1); + } + + fromJSON(json: Selection_Core) { + this.uuid = json.uuid; + this.components = json.components.map((c) => { + const component = new Component_Three(); + component.fromJSON(c); + return component; + }); + } + + toJSON(): Selection_Core { + return { + uuid: this.uuid, + components: this.components.map((c) => c.toJSON()), + }; + } +} + /** * See {@link Components_Core}. */ export class Components_Three implements Components_Core { uuid: string; - selection: any; + selection: Selection_Three[]; visibility: any; coloring: Coloring_Three[]; constructor() { this.uuid = THREE.MathUtils.generateUUID(); - this.selection = null; + this.selection = []; this.visibility = null; this.coloring = []; } @@ -154,7 +209,7 @@ export class Components_Three implements Components_Core { toJSON(): Components_Core { return { uuid: this.uuid, - selection: this.selection, + selection: this.selection.map((s) => s.toJSON()), visibility: this.visibility, coloring: this.coloring.map((c) => c.toJSON()), }; @@ -162,7 +217,11 @@ export class Components_Three implements Components_Core { fromJSON(json: Components_Core) { this.uuid = json.uuid; - this.selection = json.selection; + this.selection = json.selection.map((s) => { + const selection = new Selection_Three(); + selection.fromJSON(s); + return selection; + }); this.visibility = json.visibility; this.coloring = json.coloring.map((c) => { const coloring = new Coloring_Three(); @@ -176,16 +235,32 @@ export class Components_Three implements Components_Core { } updateColoring(coloring: Coloring_Three) { - const index = this.coloring.findIndex((c) => c.color === coloring.color); + const index = this.coloring.findIndex((c) => c.uuid === coloring.uuid); if (index === -1) throw new Error('Coloring not found'); this.coloring[index] = coloring; } - removeColoring(color: string) { - const index = this.coloring.findIndex((c) => c.color === color); + removeColoring(coloring: Coloring_Three) { + const index = this.coloring.findIndex((c) => c.uuid === coloring.uuid); if (index === -1) throw new Error('Coloring not found'); this.coloring.splice(index, 1); } + + addSelection(selection: Selection_Three) { + this.selection.push(selection); + } + + updateSelection(selection: Selection_Three) { + const index = this.selection.findIndex((s) => s.uuid === selection.uuid); + if (index === -1) throw new Error('Selection not found'); + this.selection[index] = selection; + } + + removeSelection(uuid: string) { + const index = this.selection.findIndex((s) => s.uuid === uuid); + if (index === -1) throw new Error('Selection not found'); + this.selection.splice(index, 1); + } } /** diff --git a/yarn.lock b/yarn.lock index 02b20e7..8dcda8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -240,7 +240,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.22.10, @babel/runtime@npm:^7.22.15": +"@babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.22.15": version: 7.22.15 resolution: "@babel/runtime@npm:7.22.15" dependencies: @@ -961,27 +961,12 @@ __metadata: languageName: node linkType: hard -"@mui/utils@npm:^5.14.7": - version: 5.14.8 - resolution: "@mui/utils@npm:5.14.8" - dependencies: - "@babel/runtime": ^7.22.10 - "@types/prop-types": ^15.7.5 - "@types/react-is": ^18.2.1 - prop-types: ^15.8.1 - react-is: ^18.2.0 - peerDependencies: - react: ^17.0.0 || ^18.0.0 - checksum: 2fb29c9d7908a47276b4f4a31a7e76d5a7d437afe95d2c0d6cd9c07f04beea89857f763c4f5c546fe243539d9986181815bfded42e516077122ed373d11a7ebf - languageName: node - linkType: hard - -"@mui/x-data-grid@npm:^6.13.0": - version: 6.13.0 - resolution: "@mui/x-data-grid@npm:6.13.0" +"@mui/x-data-grid@npm:^6.16.0": + version: 6.16.0 + resolution: "@mui/x-data-grid@npm:6.16.0" dependencies: "@babel/runtime": ^7.22.15 - "@mui/utils": ^5.14.7 + "@mui/utils": ^5.14.8 clsx: ^2.0.0 prop-types: ^15.8.1 reselect: ^4.1.8 @@ -990,7 +975,7 @@ __metadata: "@mui/system": ^5.4.1 react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 - checksum: 756d1b6bdccff60e209b4970ed3e74825377dba91764abfc7aa5084c33abaa37b4874c05bbfdafe13f3f191a4194723b0bbfb9b02f00cf677ecd8ca782af57f0 + checksum: 017a58b00452a67afb52375b1704bbe3f59784cd3839025e5ceab9b84ccab558f2a3421b2691c0799f6458f2a29a910e7f7ba86e7454336a893502628ca2148a languageName: node linkType: hard @@ -4111,7 +4096,7 @@ __metadata: "@fontsource/roboto": ^5.0.4 "@mui/icons-material": ^5.13.7 "@mui/material": ^5.13.7 - "@mui/x-data-grid": ^6.13.0 + "@mui/x-data-grid": ^6.16.0 "@mui/x-date-pickers": ^6.14.0 "@reduxjs/toolkit": ^1.9.5 "@types/file-saver": ^2.0.5