diff --git a/packages/forms/frontend/sirius-components-forms/package.json b/packages/forms/frontend/sirius-components-forms/package.json index 0c0d512a343..c955fee5597 100644 --- a/packages/forms/frontend/sirius-components-forms/package.json +++ b/packages/forms/frontend/sirius-components-forms/package.json @@ -12,6 +12,7 @@ }, "main": "./dist/sirius-components-forms.umd.js", "module": "./dist/sirius-components-forms.es.js", + "type": "module", "types": "./dist/index.d.ts", "files": [ "dist" diff --git a/packages/forms/frontend/sirius-components-forms/src/representations/FormRepresentation.tsx b/packages/forms/frontend/sirius-components-forms/src/representations/FormRepresentation.tsx index bc3355635d3..188f609641f 100644 --- a/packages/forms/frontend/sirius-components-forms/src/representations/FormRepresentation.tsx +++ b/packages/forms/frontend/sirius-components-forms/src/representations/FormRepresentation.tsx @@ -10,42 +10,17 @@ * Contributors: * Obeo - initial API and implementation *******************************************************************************/ -import { gql, useSubscription } from '@apollo/client'; -import { RepresentationComponentProps, Toast } from '@eclipse-sirius/sirius-components-core'; -import Typography from '@mui/material/Typography'; +import { RepresentationComponentProps } from '@eclipse-sirius/sirius-components-core'; +import { useEffect, useMemo, useState } from 'react'; import { makeStyles } from 'tss-react/mui'; -import { useMachine } from '@xstate/react'; -import { useEffect, useState } from 'react'; import { FormContext } from '../contexts/FormContext'; import { Form } from '../form/Form'; -import { formRefreshedEventPayloadFragment } from '../form/FormEventFragments'; -import { GQLFormEventSubscription } from '../form/FormEventFragments.types'; +import { GQLFormEventPayload } from '../form/FormEventFragments.types'; import { Page } from '../pages/Page'; import { ToolbarAction } from '../toolbaraction/ToolbarAction'; import { FormRepresentationState } from './FormRepresentation.types'; -import { - FormRepresentationContext, - FormRepresentationEvent, - HandleCompleteEvent, - HandleSubscriptionResultEvent, - HideToastEvent, - SchemaValue, - ShowToastEvent, - SwitchFormEvent, - formRepresentationMachine, -} from './FormRepresentationMachine'; - -const formEventSubscription = gql(` - subscription formEvent($input: FormEventInput!) { - formEvent(input: $input) { - __typename - ... on FormRefreshedEventPayload { - ...formRefreshedEventPayloadFragment - } - } - } - ${formRefreshedEventPayloadFragment} -`); +import { useFormSubscription } from './useFormSubscription'; +import { GQLFormRefreshedEventPayload } from './useFormSubscription.types'; const useFormRepresentationStyles = makeStyles()((theme) => ({ page: { @@ -76,107 +51,62 @@ const useFormRepresentationStyles = makeStyles()((theme) => ({ }, })); -/** - * Connect the Form component to the GraphQL API over Web Socket. - */ +const isFormRefreshedEventPayload = (payload: GQLFormEventPayload): payload is GQLFormRefreshedEventPayload => + payload && payload.__typename === 'FormRefreshedEventPayload'; + export const FormRepresentation = ({ editingContextId, representationId, readOnly }: RepresentationComponentProps) => { - const { classes } = useFormRepresentationStyles(); - const [{ value, context }, dispatch] = useMachine( - formRepresentationMachine, - { - context: { - formId: representationId, - }, - } - ); - const { toast, formRepresentation } = value as SchemaValue; - const { id, formId, form, message } = context; const [state, setState] = useState({ payload: null, + form: null, }); - /** - * Displays an other form if the selection indicates that we should display another properties view. - */ + const { payload } = useFormSubscription(editingContextId, representationId); useEffect(() => { - if (formId !== representationId) { - const switchFormEvent: SwitchFormEvent = { type: 'SWITCH_FORM', formId: representationId }; - dispatch(switchFormEvent); + if (isFormRefreshedEventPayload(payload)) { + setState((prevState) => ({ ...prevState, form: payload.form })); } - }, [representationId, formId, dispatch]); + }, [payload]); - const { error } = useSubscription(formEventSubscription, { - variables: { - input: { - id, - editingContextId, - formId: representationId, - }, - }, - fetchPolicy: 'no-cache', - onData: ({ data }) => { - if (data.data) { - const { formEvent } = data.data; - setState((prevState) => ({ ...prevState, payload: formEvent })); - } - const handleDataEvent: HandleSubscriptionResultEvent = { - type: 'HANDLE_SUBSCRIPTION_RESULT', - result: data, - }; - dispatch(handleDataEvent); - }, - onComplete: () => { - const completeEvent: HandleCompleteEvent = { type: 'HANDLE_COMPLETE' }; - dispatch(completeEvent); - }, - }); - - useEffect(() => { - if (error) { - const { message } = error; - const showToastEvent: ShowToastEvent = { type: 'SHOW_TOAST', message }; - dispatch(showToastEvent); - } - }, [error, dispatch]); + const { classes } = useFormRepresentationStyles(); - let content: JSX.Element | null = null; - if (formRepresentation === 'ready') { - if (form.pages.length > 1) { - content =
; - } else if (form.pages.length === 1) { - let selectedPageToolbar = null; - if (form.pages[0].toolbarActions?.length > 0) { - selectedPageToolbar = ( -
- {form.pages[0].toolbarActions.map((toolbarAction) => ( -
- -
- ))} + const renderedForm = useMemo(() => { + let content: JSX.Element | null = null; + if (state.form) { + if (state.form.pages.length > 1) { + content = ; + } else if (state.form.pages.length === 1) { + let selectedPageToolbar = null; + if (state.form.pages[0].toolbarActions?.length > 0) { + selectedPageToolbar = ( +
+ {state.form.pages[0].toolbarActions.map((toolbarAction) => ( +
+ +
+ ))} +
+ ); + } + content = ( +
+ {selectedPageToolbar} +
); } - content = ( -
- {selectedPageToolbar} - -
- ); } - } else if (formRepresentation === 'complete') { - content = ( -
- - The form does not exist anymore - -
- ); - } + return content; + }, [state.form]); return (
@@ -184,12 +114,7 @@ export const FormRepresentation = ({ editingContextId, representationId, readOnl value={{ payload: state.payload, }}> - {content} - dispatch({ type: 'HIDE_TOAST' } as HideToastEvent)} - /> + {renderedForm}
); diff --git a/packages/forms/frontend/sirius-components-forms/src/representations/FormRepresentation.types.ts b/packages/forms/frontend/sirius-components-forms/src/representations/FormRepresentation.types.ts index eba02c09dc1..34ea24aea7c 100644 --- a/packages/forms/frontend/sirius-components-forms/src/representations/FormRepresentation.types.ts +++ b/packages/forms/frontend/sirius-components-forms/src/representations/FormRepresentation.types.ts @@ -11,8 +11,9 @@ * Obeo - initial API and implementation *******************************************************************************/ -import { GQLFormEventPayload } from '../form/FormEventFragments.types'; +import { GQLForm, GQLFormEventPayload } from '../form/FormEventFragments.types'; export interface FormRepresentationState { payload: GQLFormEventPayload | null; + form: GQLForm | null; } diff --git a/packages/forms/frontend/sirius-components-forms/src/representations/FormRepresentationMachine.ts b/packages/forms/frontend/sirius-components-forms/src/representations/FormRepresentationMachine.ts deleted file mode 100644 index 2f81bfc687b..00000000000 --- a/packages/forms/frontend/sirius-components-forms/src/representations/FormRepresentationMachine.ts +++ /dev/null @@ -1,188 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2021, 2024 Obeo. - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Obeo - initial API and implementation - *******************************************************************************/ -import { SubscriptionResult } from '@apollo/client'; -import { assign, Machine } from 'xstate'; -import { - GQLForm, - GQLFormEventPayload, - GQLFormEventSubscription, - GQLFormRefreshedEventPayload, -} from '../form/FormEventFragments.types'; - -export interface FormRepresentationStateSchema { - states: { - toast: { - states: { - visible: {}; - hidden: {}; - }; - }; - formRepresentation: { - states: { - idle: {}; - ready: {}; - complete: {}; - }; - }; - }; -} - -export type SchemaValue = { - toast: 'visible' | 'hidden'; - formRepresentation: 'idle' | 'ready' | 'complete'; -}; - -export interface FormRepresentationContext { - id: string; - formId: string; - form: GQLForm | null; - message: string | null; -} - -export type ShowToastEvent = { type: 'SHOW_TOAST'; message: string }; -export type HideToastEvent = { type: 'HIDE_TOAST' }; -export type SwitchFormEvent = { type: 'SWITCH_FORM'; formId: string }; -export type HandleSubscriptionResultEvent = { - type: 'HANDLE_SUBSCRIPTION_RESULT'; - result: SubscriptionResult; -}; -export type HandleCompleteEvent = { type: 'HANDLE_COMPLETE' }; -export type FormRepresentationEvent = - | SwitchFormEvent - | HandleSubscriptionResultEvent - | HandleCompleteEvent - | ShowToastEvent - | HideToastEvent; - -const isFormRefreshedEventPayload = (payload: GQLFormEventPayload): payload is GQLFormRefreshedEventPayload => - payload.__typename === 'FormRefreshedEventPayload'; - -export const formRepresentationMachine = Machine< - FormRepresentationContext, - FormRepresentationStateSchema, - FormRepresentationEvent ->( - { - type: 'parallel', - context: { - id: crypto.randomUUID(), - formId: null, - form: null, - message: null, - }, - states: { - toast: { - initial: 'hidden', - states: { - hidden: { - on: { - SHOW_TOAST: { - target: 'visible', - actions: 'setMessage', - }, - }, - }, - visible: { - on: { - HIDE_TOAST: { - target: 'hidden', - actions: 'clearMessage', - }, - }, - }, - }, - }, - formRepresentation: { - initial: 'idle', - states: { - idle: { - on: { - SWITCH_FORM: { - target: 'idle', - actions: 'switchForm', - }, - HANDLE_SUBSCRIPTION_RESULT: [ - { - cond: 'isFormRefreshedEventPayload', - target: 'ready', - actions: 'handleSubscriptionResult', - }, - { - target: 'idle', - actions: 'handleSubscriptionResult', - }, - ], - }, - }, - ready: { - on: { - SWITCH_FORM: { - target: 'idle', - actions: 'switchForm', - }, - HANDLE_SUBSCRIPTION_RESULT: { - target: 'ready', - actions: 'handleSubscriptionResult', - }, - HANDLE_COMPLETE: { - target: 'complete', - }, - }, - }, - complete: { - on: { - SWITCH_FORM: { - target: 'idle', - actions: 'switchForm', - }, - }, - }, - }, - }, - }, - }, - { - guards: { - isFormRefreshedEventPayload: (_, event) => { - const { result } = event as HandleSubscriptionResultEvent; - const { data } = result; - return isFormRefreshedEventPayload(data.formEvent); - }, - }, - actions: { - switchForm: assign((_, event) => { - const { formId } = event as SwitchFormEvent; - return { - id: crypto.randomUUID(), - formId, - }; - }), - handleSubscriptionResult: assign((_, event) => { - const { result } = event as HandleSubscriptionResultEvent; - const { data } = result; - if (isFormRefreshedEventPayload(data.formEvent)) { - const { form } = data.formEvent; - return { form }; - } - return {}; - }), - setMessage: assign((_, event) => { - const { message } = event as ShowToastEvent; - return { message }; - }), - clearMessage: assign((_) => { - return { message: null }; - }), - }, - } -); diff --git a/packages/forms/frontend/sirius-components-forms/src/representations/useFormSubscription.tsx b/packages/forms/frontend/sirius-components-forms/src/representations/useFormSubscription.tsx new file mode 100644 index 00000000000..c59ecd0b11b --- /dev/null +++ b/packages/forms/frontend/sirius-components-forms/src/representations/useFormSubscription.tsx @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2024 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ + +import { gql, OnDataOptions, useSubscription } from '@apollo/client'; +import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; +import { formRefreshedEventPayloadFragment } from '@eclipse-sirius/sirius-components-forms'; +import { useEffect, useState } from 'react'; +import { + GQLFormEventInput, + GQLFormEventSubscription, + GQLFormEventVariables, + UseFormSubscriptionState, + UseFormSubscriptionValue, +} from './useFormSubscription.types'; + +export const formEventSubscription = ` + subscription formEvent($input: FormEventInput!) { + formEvent(input: $input) { + __typename + ... on FormRefreshedEventPayload { + ...formRefreshedEventPayloadFragment + } + } + } + ${formRefreshedEventPayloadFragment} +`; + +export const useFormSubscription = (editingContextId: string, formId: string): UseFormSubscriptionValue => { + const [state, setState] = useState({ + id: crypto.randomUUID(), + complete: false, + payload: null, + }); + + const input: GQLFormEventInput = { + id: state.id, + editingContextId, + formId, + }; + + const variables: GQLFormEventVariables = { input }; + + const onData = ({ data }: OnDataOptions) => { + const { data: gqlFormEventSubscription } = data; + if (gqlFormEventSubscription) { + const { formEvent: payload } = gqlFormEventSubscription; + setState((prevState) => ({ ...prevState, payload })); + } + }; + + const onComplete = () => setState((prevState) => ({ ...prevState, complete: true })); + + const { error, loading } = useSubscription( + gql(formEventSubscription), + { + variables, + fetchPolicy: 'no-cache', + onData, + onComplete, + } + ); + + const { addErrorMessage } = useMultiToast(); + useEffect(() => { + if (error) { + addErrorMessage('An unexpected error has occurred, please refresh the page'); + } + }, [error]); + + return { + loading, + payload: state.payload, + complete: state.complete, + }; +}; diff --git a/packages/forms/frontend/sirius-components-forms/src/representations/useFormSubscription.types.ts b/packages/forms/frontend/sirius-components-forms/src/representations/useFormSubscription.types.ts new file mode 100644 index 00000000000..af89047a135 --- /dev/null +++ b/packages/forms/frontend/sirius-components-forms/src/representations/useFormSubscription.types.ts @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2024 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ + +import { GQLForm } from '@eclipse-sirius/sirius-components-forms'; + +export interface UseFormSubscriptionValue { + loading: boolean; + payload: GQLFormEventPayload | null; + complete: boolean; +} + +export interface UseFormSubscriptionState { + id: string; + complete: boolean; + payload: GQLFormEventPayload | null; +} + +export interface GQLFormEventInput { + id: string; + editingContextId: string; + formId: string; +} + +export interface GQLFormEventVariables { + input: GQLFormEventInput; +} + +export interface GQLFormEventSubscription { + formEvent: GQLFormEventPayload; +} + +export interface GQLFormEventPayload { + __typename: string; +} + +export interface GQLFormRefreshedEventPayload extends GQLFormEventPayload { + __typename: 'FormRefreshedEventPayload'; + form: GQLForm; +} diff --git a/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramFilterForm.tsx b/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramFilterForm.tsx index c0d42f1e78e..56bfb9ef4bc 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramFilterForm.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramFilterForm.tsx @@ -12,10 +12,18 @@ *******************************************************************************/ import { WorkbenchViewComponentProps } from '@eclipse-sirius/sirius-components-core'; -import { FormBasedView, GQLForm, Group } from '@eclipse-sirius/sirius-components-forms'; +import { + FormBasedView, + FormContext, + GQLForm, + GQLFormRefreshedEventPayload, + Group, +} from '@eclipse-sirius/sirius-components-forms'; +import { useEffect, useState } from 'react'; import { makeStyles } from 'tss-react/mui'; -import { DiagramFilterFormProps } from './DiagramFilterForm.types'; +import { DiagramFilterFormProps, DiagramFilterViewState } from './DiagramFilterForm.types'; import { useDiagramFilterSubscription } from './useDiagramFilterSubscription'; +import { GQLDiagramFilterEventPayload } from './useDiagramFilterSubscription.types'; const useDiagramFilterViewStyles = makeStyles()((theme) => ({ idle: { @@ -26,8 +34,20 @@ const useDiagramFilterViewStyles = makeStyles()((theme) => ({ }, })); +const isFormRefreshedEventPayload = (payload: GQLDiagramFilterEventPayload): payload is GQLFormRefreshedEventPayload => + payload && payload.__typename === 'FormRefreshedEventPayload'; + export const DiagramFilterForm = ({ editingContextId, diagramId, readOnly }: DiagramFilterFormProps) => { - const { form } = useDiagramFilterSubscription(editingContextId, [diagramId]); + const [state, setState] = useState({ + form: null, + }); + + const { payload } = useDiagramFilterSubscription(editingContextId, [diagramId]); + useEffect(() => { + if (isFormRefreshedEventPayload(payload)) { + setState((prevState) => ({ ...prevState, form: payload.form })); + } + }, [payload]); const { classes } = useDiagramFilterViewStyles(); @@ -44,15 +64,22 @@ export const DiagramFilterForm = ({ editingContextId, diagramId, readOnly }: Dia } }; - if (!form) { + if (!state.form) { return null; } return ( - +
+ + + +
); }; diff --git a/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramFilterForm.types.ts b/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramFilterForm.types.ts index b22a36803dd..88a0145921b 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramFilterForm.types.ts +++ b/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramFilterForm.types.ts @@ -11,8 +11,14 @@ * Obeo - initial API and implementation *******************************************************************************/ +import { GQLForm } from '@eclipse-sirius/sirius-components-forms'; + export interface DiagramFilterFormProps { editingContextId: string; diagramId: string; readOnly: boolean; } + +export interface DiagramFilterViewState { + form: GQLForm | null; +} diff --git a/packages/sirius-web/frontend/sirius-web-application/src/diagrams/useDiagramFilterSubscription.tsx b/packages/sirius-web/frontend/sirius-web-application/src/diagrams/useDiagramFilterSubscription.tsx index 42633b688ad..7e2995dfc64 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/diagrams/useDiagramFilterSubscription.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/diagrams/useDiagramFilterSubscription.tsx @@ -17,17 +17,12 @@ import { formRefreshedEventPayloadFragment } from '@eclipse-sirius/sirius-compon import { useEffect, useState } from 'react'; import { GQLDiagramFilterEventInput, - GQLDiagramFilterEventPayload, GQLDiagramFilterEventSubscription, GQLDiagramFilterEventVariables, - GQLFormRefreshedEventPayload, UseDiagramFilterSubscriptionState, UseDiagramFilterSubscriptionValue, } from './useDiagramFilterSubscription.types'; -const isFormRefreshedEventPayload = (payload: GQLDiagramFilterEventPayload): payload is GQLFormRefreshedEventPayload => - payload.__typename === 'FormRefreshedEventPayload'; - export const getDiagramFilterEventSubscription = ` subscription diagramFilterEvent($input: DiagramFilterEventInput!) { diagramFilterEvent(input: $input) { @@ -47,7 +42,7 @@ export const useDiagramFilterSubscription = ( ): UseDiagramFilterSubscriptionValue => { const [state, setState] = useState({ id: crypto.randomUUID(), - form: null, + payload: null, complete: false, }); @@ -63,10 +58,7 @@ export const useDiagramFilterSubscription = ( const { data: gqlDiagramFilterEventSubscription } = data; if (gqlDiagramFilterEventSubscription) { const { diagramFilterEvent: payload } = gqlDiagramFilterEventSubscription; - if (isFormRefreshedEventPayload(payload)) { - const { form } = payload; - setState((prevState) => ({ ...prevState, form })); - } + setState((prevState) => ({ ...prevState, payload })); } }; @@ -92,7 +84,7 @@ export const useDiagramFilterSubscription = ( return { loading, - form: state.form, + payload: state.payload, complete: state.complete, }; }; diff --git a/packages/sirius-web/frontend/sirius-web-application/src/diagrams/useDiagramFilterSubscription.types.ts b/packages/sirius-web/frontend/sirius-web-application/src/diagrams/useDiagramFilterSubscription.types.ts index a30b4f7eaf6..46e84245884 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/diagrams/useDiagramFilterSubscription.types.ts +++ b/packages/sirius-web/frontend/sirius-web-application/src/diagrams/useDiagramFilterSubscription.types.ts @@ -15,13 +15,13 @@ import { GQLForm } from '@eclipse-sirius/sirius-components-forms'; export interface UseDiagramFilterSubscriptionValue { loading: boolean; - form: GQLForm | null; + payload: GQLDiagramFilterEventPayload | null; complete: boolean; } export interface UseDiagramFilterSubscriptionState { id: string; - form: GQLForm | null; + payload: GQLDiagramFilterEventPayload | null; complete: boolean; } diff --git a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/DetailsView.tsx b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/DetailsView.tsx index da6603636ab..dd92f1f21b6 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/DetailsView.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/DetailsView.tsx @@ -17,6 +17,7 @@ import { useEffect, useState } from 'react'; import { makeStyles } from 'tss-react/mui'; import { DetailsViewState } from './DetailsView.types'; import { useDetailsViewSubscription } from './useDetailsViewSubscription'; +import { GQLDetailsEventPayload, GQLFormRefreshedEventPayload } from './useDetailsViewSubscription.types'; const useDetailsViewStyles = makeStyles()((theme) => ({ idle: { @@ -24,9 +25,13 @@ const useDetailsViewStyles = makeStyles()((theme) => ({ }, })); +const isFormRefreshedEventPayload = (payload: GQLDetailsEventPayload): payload is GQLFormRefreshedEventPayload => + payload && payload.__typename === 'FormRefreshedEventPayload'; + export const DetailsView = ({ editingContextId, readOnly }: WorkbenchViewComponentProps) => { const [state, setState] = useState({ currentSelection: { entries: [] }, + form: null, }); const { selection } = useSelection(); @@ -42,6 +47,7 @@ export const DetailsView = ({ editingContextId, readOnly }: WorkbenchViewCompone .map((entry) => entry.id) .sort() .join(':'); + useEffect(() => { if (selection.entries.length > 0 && currentSelectionKey !== newSelectionKey) { setState((prevState) => ({ ...prevState, currentSelection: selection })); @@ -52,11 +58,17 @@ export const DetailsView = ({ editingContextId, readOnly }: WorkbenchViewCompone const objectIds: string[] = state.currentSelection.entries.map((entry) => entry.id); const skip = objectIds.length === 0; - const { form, payload } = useDetailsViewSubscription(editingContextId, objectIds, skip); + + const { payload } = useDetailsViewSubscription(editingContextId, objectIds, skip); + useEffect(() => { + if (isFormRefreshedEventPayload(payload)) { + setState((prevState) => ({ ...prevState, form: payload.form })); + } + }, [payload]); const { classes } = useDetailsViewStyles(); - if (!form) { + if (!state.form) { return (
No object selected @@ -69,7 +81,7 @@ export const DetailsView = ({ editingContextId, readOnly }: WorkbenchViewCompone value={{ payload: payload, }}> - +
); diff --git a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/DetailsView.types.ts b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/DetailsView.types.ts index 344ee6595cb..7cee0ab6710 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/DetailsView.types.ts +++ b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/DetailsView.types.ts @@ -12,7 +12,9 @@ *******************************************************************************/ import { Selection } from '@eclipse-sirius/sirius-components-core'; +import { GQLForm } from '@eclipse-sirius/sirius-components-forms'; export interface DetailsViewState { currentSelection: Selection; + form: GQLForm | null; } diff --git a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RelatedElementsView.tsx b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RelatedElementsView.tsx index e1a515186f0..95672e3f4be 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RelatedElementsView.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RelatedElementsView.tsx @@ -11,12 +11,19 @@ * Obeo - initial API and implementation *******************************************************************************/ import { useSelection, WorkbenchViewComponentProps } from '@eclipse-sirius/sirius-components-core'; -import { FormBasedView, GQLForm, Group } from '@eclipse-sirius/sirius-components-forms'; +import { + FormBasedView, + FormContext, + GQLForm, + GQLFormRefreshedEventPayload, + Group, +} from '@eclipse-sirius/sirius-components-forms'; import Typography from '@mui/material/Typography'; import { useEffect, useState } from 'react'; import { makeStyles } from 'tss-react/mui'; import { RelatedElementsViewState } from './RelatedElementsView.types'; import { useRelatedElementsViewSubscription } from './useRelatedElementsViewSubscription'; +import { GQLRelatedElementsEventPayload } from './useRelatedElementsViewSubscription.types'; const useRelatedElementsViewStyles = makeStyles()((theme) => ({ idle: { @@ -27,9 +34,14 @@ const useRelatedElementsViewStyles = makeStyles()((theme) => ({ }, })); +const isFormRefreshedEventPayload = ( + payload: GQLRelatedElementsEventPayload +): payload is GQLFormRefreshedEventPayload => payload && payload.__typename === 'FormRefreshedEventPayload'; + export const RelatedElementsView = ({ editingContextId, readOnly }: WorkbenchViewComponentProps) => { const [state, setState] = useState({ currentSelection: { entries: [] }, + form: null, }); const { selection } = useSelection(); @@ -55,7 +67,13 @@ export const RelatedElementsView = ({ editingContextId, readOnly }: WorkbenchVie const objectIds: string[] = state.currentSelection.entries.map((entry) => entry.id); const skip = objectIds.length === 0; - const { form } = useRelatedElementsViewSubscription(editingContextId, objectIds, skip); + + const { payload } = useRelatedElementsViewSubscription(editingContextId, objectIds, skip); + useEffect(() => { + if (isFormRefreshedEventPayload(payload)) { + setState((prevState) => ({ ...prevState, form: payload.form })); + } + }, [payload]); const { classes } = useRelatedElementsViewStyles(); @@ -72,7 +90,7 @@ export const RelatedElementsView = ({ editingContextId, readOnly }: WorkbenchVie } }; - if (!form) { + if (!state.form) { return (
No object selected @@ -80,11 +98,18 @@ export const RelatedElementsView = ({ editingContextId, readOnly }: WorkbenchVie ); } return ( - +
+ + + +
); }; diff --git a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RelatedElementsView.types.ts b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RelatedElementsView.types.ts index fcfa46fae4c..a267ede1d1b 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RelatedElementsView.types.ts +++ b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RelatedElementsView.types.ts @@ -12,7 +12,9 @@ *******************************************************************************/ import { Selection } from '@eclipse-sirius/sirius-components-core'; +import { GQLForm } from '@eclipse-sirius/sirius-components-forms'; export interface RelatedElementsViewState { currentSelection: Selection; + form: GQLForm | null; } diff --git a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RepresentationsView.tsx b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RepresentationsView.tsx index f361ebfb6fa..8b6a4e4575f 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RepresentationsView.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RepresentationsView.tsx @@ -13,8 +13,10 @@ import { useSelection, WorkbenchViewComponentProps } from '@eclipse-sirius/sirius-components-core'; import { FormBasedView, + FormContext, GQLForm, GQLList, + GQLRepresentationsEventPayload, GQLTree, GQLWidget, ListPropertySection, @@ -25,6 +27,7 @@ import { useEffect, useState } from 'react'; import { makeStyles } from 'tss-react/mui'; import { RepresentationsViewState } from './RepresentationsView.types'; import { useRepresentationsViewSubscription } from './useRepresentationsViewSubscription'; +import { GQLFormRefreshedEventPayload } from './useRepresentationsViewSubscription.types'; const useRepresentationsViewStyles = makeStyles()((theme) => ({ idle: { @@ -37,10 +40,14 @@ const useRepresentationsViewStyles = makeStyles()((theme) => ({ const isList = (widget: GQLWidget | undefined): widget is GQLList => widget && widget.__typename === 'List'; const isTree = (widget: GQLWidget | undefined): widget is GQLTree => widget && widget.__typename === 'TreeWidget'; +const isFormRefreshedEventPayload = ( + payload: GQLRepresentationsEventPayload +): payload is GQLFormRefreshedEventPayload => payload && payload.__typename === 'FormRefreshedEventPayload'; export const RepresentationsView = ({ editingContextId, readOnly }: WorkbenchViewComponentProps) => { const [state, setState] = useState({ currentSelection: { entries: [] }, + form: null, }); const { selection } = useSelection(); @@ -66,7 +73,13 @@ export const RepresentationsView = ({ editingContextId, readOnly }: WorkbenchVie const objectIds: string[] = state.currentSelection.entries.map((entry) => entry.id); const skip = objectIds.length === 0; - const { form } = useRepresentationsViewSubscription(editingContextId, objectIds, skip); + + const { payload } = useRepresentationsViewSubscription(editingContextId, objectIds, skip); + useEffect(() => { + if (isFormRefreshedEventPayload(payload)) { + setState((prevState) => ({ ...prevState, form: payload.form })); + } + }, [payload]); const { classes } = useRepresentationsViewStyles(); @@ -99,7 +112,7 @@ export const RepresentationsView = ({ editingContextId, readOnly }: WorkbenchVie } }; - if (!form) { + if (!state.form) { return (
No object selected @@ -107,11 +120,18 @@ export const RepresentationsView = ({ editingContextId, readOnly }: WorkbenchVie ); } return ( - +
+ + + +
); }; diff --git a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RepresentationsView.types.ts b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RepresentationsView.types.ts index 44fee3cab19..b8f55763531 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RepresentationsView.types.ts +++ b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/RepresentationsView.types.ts @@ -12,7 +12,9 @@ *******************************************************************************/ import { Selection } from '@eclipse-sirius/sirius-components-core'; +import { GQLForm } from '@eclipse-sirius/sirius-components-forms'; export interface RepresentationsViewState { currentSelection: Selection; + form: GQLForm | null; } diff --git a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useDetailsViewSubscription.tsx b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useDetailsViewSubscription.tsx index 970198744e8..0696dc088ff 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useDetailsViewSubscription.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useDetailsViewSubscription.tsx @@ -17,17 +17,12 @@ import { formRefreshedEventPayloadFragment } from '@eclipse-sirius/sirius-compon import { useEffect, useState } from 'react'; import { GQLDetailsEventInput, - GQLDetailsEventPayload, GQLDetailsEventSubscription, GQLDetailsEventVariables, - GQLFormRefreshedEventPayload, UseDetailsViewSubscriptionState, UseDetailsViewSubscriptionValue, } from './useDetailsViewSubscription.types'; -const isFormRefreshedEventPayload = (payload: GQLDetailsEventPayload): payload is GQLFormRefreshedEventPayload => - payload.__typename === 'FormRefreshedEventPayload'; - export const getDetailsViewEventSubscription = ` subscription detailsEvent($input: DetailsEventInput!) { detailsEvent(input: $input) { @@ -47,7 +42,6 @@ export const useDetailsViewSubscription = ( ): UseDetailsViewSubscriptionValue => { const [state, setState] = useState({ id: crypto.randomUUID(), - form: null, complete: false, payload: null, }); @@ -65,10 +59,6 @@ export const useDetailsViewSubscription = ( if (gqlDetailsEventSubscription) { const { detailsEvent: payload } = gqlDetailsEventSubscription; setState((prevState) => ({ ...prevState, payload })); - if (isFormRefreshedEventPayload(payload)) { - const { form } = payload; - setState((prevState) => ({ ...prevState, form })); - } } }; @@ -94,7 +84,6 @@ export const useDetailsViewSubscription = ( return { loading, - form: state.form, payload: state.payload, complete: state.complete, }; diff --git a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useDetailsViewSubscription.types.ts b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useDetailsViewSubscription.types.ts index 6a693c08c0b..9540da5d369 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useDetailsViewSubscription.types.ts +++ b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useDetailsViewSubscription.types.ts @@ -15,14 +15,12 @@ import { GQLForm } from '@eclipse-sirius/sirius-components-forms'; export interface UseDetailsViewSubscriptionValue { loading: boolean; - form: GQLForm | null; payload: GQLDetailsEventPayload | null; complete: boolean; } export interface UseDetailsViewSubscriptionState { id: string; - form: GQLForm | null; complete: boolean; payload: GQLDetailsEventPayload | null; } diff --git a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRelatedElementsViewSubscription.tsx b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRelatedElementsViewSubscription.tsx index f774739f9f2..81555d8984c 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRelatedElementsViewSubscription.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRelatedElementsViewSubscription.tsx @@ -16,19 +16,13 @@ import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; import { formRefreshedEventPayloadFragment } from '@eclipse-sirius/sirius-components-forms'; import { useEffect, useState } from 'react'; import { - GQLFormRefreshedEventPayload, GQLRelatedElementsEventInput, - GQLRelatedElementsEventPayload, GQLRelatedElementsEventSubscription, GQLRelatedElementsEventVariables, UseRelatedElementsViewSubscriptionState, UseRelatedElementsViewSubscriptionValue, } from './useRelatedElementsViewSubscription.types'; -const isFormRefreshedEventPayload = ( - payload: GQLRelatedElementsEventPayload -): payload is GQLFormRefreshedEventPayload => payload.__typename === 'FormRefreshedEventPayload'; - export const getRelatedElementsViewEventSubscription = ` subscription relatedElementsEvent($input: RelatedElementsEventInput!) { relatedElementsEvent(input: $input) { @@ -48,7 +42,7 @@ export const useRelatedElementsViewSubscription = ( ): UseRelatedElementsViewSubscriptionValue => { const [state, setState] = useState({ id: crypto.randomUUID(), - form: null, + payload: null, complete: false, }); @@ -64,10 +58,7 @@ export const useRelatedElementsViewSubscription = ( const { data: gqlRelatedElementsEventSubscription } = data; if (gqlRelatedElementsEventSubscription) { const { relatedElementsEvent: payload } = gqlRelatedElementsEventSubscription; - if (isFormRefreshedEventPayload(payload)) { - const { form } = payload; - setState((prevState) => ({ ...prevState, form })); - } + setState((prevState) => ({ ...prevState, payload })); } }; @@ -93,7 +84,7 @@ export const useRelatedElementsViewSubscription = ( return { loading, - form: state.form, + payload: state.payload, complete: state.complete, }; }; diff --git a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRelatedElementsViewSubscription.types.ts b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRelatedElementsViewSubscription.types.ts index b258ab65994..402e7bdd584 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRelatedElementsViewSubscription.types.ts +++ b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRelatedElementsViewSubscription.types.ts @@ -15,13 +15,13 @@ import { GQLForm } from '@eclipse-sirius/sirius-components-forms'; export interface UseRelatedElementsViewSubscriptionValue { loading: boolean; - form: GQLForm | null; + payload: GQLRelatedElementsEventPayload | null; complete: boolean; } export interface UseRelatedElementsViewSubscriptionState { id: string; - form: GQLForm | null; + payload: GQLRelatedElementsEventPayload | null; complete: boolean; } diff --git a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRepresentationsViewSubscription.tsx b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRepresentationsViewSubscription.tsx index 02e2dd74a00..74fb3839b7b 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRepresentationsViewSubscription.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRepresentationsViewSubscription.tsx @@ -16,19 +16,13 @@ import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; import { formRefreshedEventPayloadFragment } from '@eclipse-sirius/sirius-components-forms'; import { useEffect, useState } from 'react'; import { - GQLFormRefreshedEventPayload, GQLRepresentationsEventInput, - GQLRepresentationsEventPayload, GQLRepresentationsEventSubscription, GQLRepresentationsEventVariables, UseRepresentationsViewSubscriptionState, UseRepresentationsViewSubscriptionValue, } from './useRepresentationsViewSubscription.types'; -const isFormRefreshedEventPayload = ( - payload: GQLRepresentationsEventPayload -): payload is GQLFormRefreshedEventPayload => payload.__typename === 'FormRefreshedEventPayload'; - export const getRepresentationsViewEventSubscription = ` subscription representationsEvent($input: RepresentationsEventInput!) { representationsEvent(input: $input) { @@ -48,7 +42,7 @@ export const useRepresentationsViewSubscription = ( ): UseRepresentationsViewSubscriptionValue => { const [state, setState] = useState({ id: crypto.randomUUID(), - form: null, + payload: null, complete: false, }); @@ -64,10 +58,7 @@ export const useRepresentationsViewSubscription = ( const { data: gqlRepresentationsEventSubscription } = data; if (gqlRepresentationsEventSubscription) { const { representationsEvent: payload } = gqlRepresentationsEventSubscription; - if (isFormRefreshedEventPayload(payload)) { - const { form } = payload; - setState((prevState) => ({ ...prevState, form })); - } + setState((prevState) => ({ ...prevState, payload })); } }; @@ -93,7 +84,7 @@ export const useRepresentationsViewSubscription = ( return { loading, - form: state.form, + payload: state.payload, complete: state.complete, }; }; diff --git a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRepresentationsViewSubscription.types.ts b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRepresentationsViewSubscription.types.ts index 43d30305239..c5d224e58b0 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRepresentationsViewSubscription.types.ts +++ b/packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/useRepresentationsViewSubscription.types.ts @@ -15,13 +15,13 @@ import { GQLForm } from '@eclipse-sirius/sirius-components-forms'; export interface UseRepresentationsViewSubscriptionValue { loading: boolean; - form: GQLForm | null; + payload: GQLRepresentationsEventPayload | null; complete: boolean; } export interface UseRepresentationsViewSubscriptionState { id: string; - form: GQLForm | null; + payload: GQLRepresentationsEventPayload | null; complete: boolean; }