@vertesia/ui 0.78.0 → 0.79.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/core/components/Panel.js +8 -0
- package/lib/esm/core/components/Panel.js.map +1 -0
- package/lib/esm/core/components/SelectBox.js +1 -1
- package/lib/esm/core/components/SelectBox.js.map +1 -1
- package/lib/esm/core/components/SelectList.js +18 -13
- package/lib/esm/core/components/SelectList.js.map +1 -1
- package/lib/esm/core/components/SidePanel.js +2 -2
- package/lib/esm/core/components/SidePanel.js.map +1 -1
- package/lib/esm/core/components/index.js +1 -1
- package/lib/esm/core/components/index.js.map +1 -1
- package/lib/esm/core/components/shadcn/breadcrumb.js +29 -8
- package/lib/esm/core/components/shadcn/breadcrumb.js.map +1 -1
- package/lib/esm/core/components/shadcn/button.js +3 -2
- package/lib/esm/core/components/shadcn/button.js.map +1 -1
- package/lib/esm/core/components/shadcn/filters/filterBar.js +41 -14
- package/lib/esm/core/components/shadcn/filters/filterBar.js.map +1 -1
- package/lib/esm/core/components/shadcn/index.js +2 -0
- package/lib/esm/core/components/shadcn/index.js.map +1 -1
- package/lib/esm/core/components/shadcn/input.js +4 -1
- package/lib/esm/core/components/shadcn/input.js.map +1 -1
- package/lib/esm/core/components/shadcn/resizeable.js +15 -0
- package/lib/esm/core/components/shadcn/resizeable.js.map +1 -0
- package/lib/esm/core/components/shadcn/selectBox.js +15 -9
- package/lib/esm/core/components/shadcn/selectBox.js.map +1 -1
- package/lib/esm/core/components/shadcn/tabs.js +20 -8
- package/lib/esm/core/components/shadcn/tabs.js.map +1 -1
- package/lib/esm/core/components/shadcn/textarea.js +7 -0
- package/lib/esm/core/components/shadcn/textarea.js.map +1 -0
- package/lib/esm/core/components/table/index.js +1 -1
- package/lib/esm/core/components/table/index.js.map +1 -1
- package/lib/esm/core/hooks/CompositeState.js +139 -1
- package/lib/esm/core/hooks/CompositeState.js.map +1 -1
- package/lib/esm/core/hooks/index.js +1 -0
- package/lib/esm/core/hooks/index.js.map +1 -1
- package/lib/esm/core/hooks/useScrollableSearch.js +92 -0
- package/lib/esm/core/hooks/useScrollableSearch.js.map +1 -0
- package/lib/esm/env/index.js +1 -1
- package/lib/esm/env/index.js.map +1 -1
- package/lib/esm/features/agent/PayloadBuilder.js +80 -55
- package/lib/esm/features/agent/PayloadBuilder.js.map +1 -1
- package/lib/esm/features/agent/chat/ModernAgentConversation.js +22 -24
- package/lib/esm/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +2 -3
- package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
- package/lib/esm/features/agent/chat/ModernAgentOutput/Header.js +2 -2
- package/lib/esm/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
- package/lib/esm/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.js +15 -20
- package/lib/esm/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.js.map +1 -1
- package/lib/esm/features/agent/chat/ModernAgentOutput/PlanPanel.js +1 -0
- package/lib/esm/features/agent/chat/ModernAgentOutput/PlanPanel.js.map +1 -1
- package/lib/esm/features/agent/chat/ModernAgentOutput/SlidingPlanPanel.js +3 -3
- package/lib/esm/features/agent/chat/ModernAgentOutput/SlidingPlanPanel.js.map +1 -1
- package/lib/esm/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js +6 -6
- package/lib/esm/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js.map +1 -1
- package/lib/esm/features/facets/CollectionsFacetsNav.js +85 -0
- package/lib/esm/features/facets/CollectionsFacetsNav.js.map +1 -0
- package/lib/esm/features/facets/DocumentsFacetsNav.js +19 -7
- package/lib/esm/features/facets/DocumentsFacetsNav.js.map +1 -1
- package/lib/esm/features/facets/EnvironmentFacet.js +1 -1
- package/lib/esm/features/facets/EnvironmentFacet.js.map +1 -1
- package/lib/esm/features/facets/InteractionsFacetsNav.js +88 -0
- package/lib/esm/features/facets/InteractionsFacetsNav.js.map +1 -0
- package/lib/esm/features/facets/PromptsFacetsNav.js +80 -0
- package/lib/esm/features/facets/PromptsFacetsNav.js.map +1 -0
- package/lib/esm/features/facets/RunsFacetsNav.js +28 -6
- package/lib/esm/features/facets/RunsFacetsNav.js.map +1 -1
- package/lib/esm/features/facets/WorkflowExecutionsFacetsNav.js +7 -5
- package/lib/esm/features/facets/WorkflowExecutionsFacetsNav.js.map +1 -1
- package/lib/esm/features/facets/index.js +10 -8
- package/lib/esm/features/facets/index.js.map +1 -1
- package/lib/esm/features/facets/utils/SearchInterface.js +2 -0
- package/lib/esm/features/facets/utils/SearchInterface.js.map +1 -0
- package/lib/esm/features/facets/utils/StringFacet.js.map +1 -0
- package/lib/esm/features/facets/utils/StringListFacet.js.map +1 -0
- package/lib/esm/features/facets/utils/TypeFacet.js.map +1 -0
- package/lib/esm/features/facets/utils/VEnvironmentFacet.js.map +1 -0
- package/lib/esm/features/facets/utils/VInteractionFacet.js.map +1 -0
- package/lib/esm/features/facets/utils/VStringFacet.js.map +1 -0
- package/lib/esm/features/facets/{VTypeFacet.js → utils/VTypeFacet.js} +9 -4
- package/lib/esm/features/facets/utils/VTypeFacet.js.map +1 -0
- package/lib/esm/features/facets/{VUserFacet.js → utils/VUserFacet.js} +1 -1
- package/lib/esm/features/facets/utils/VUserFacet.js.map +1 -0
- package/lib/esm/features/facets/utils/utils.js.map +1 -0
- package/lib/esm/features/layout/GenericPageNavHeader.js +58 -5
- package/lib/esm/features/layout/GenericPageNavHeader.js.map +1 -1
- package/lib/esm/features/store/collections/BrowseCollectionView.js +3 -0
- package/lib/esm/features/store/collections/BrowseCollectionView.js.map +1 -1
- package/lib/esm/features/store/collections/CreateCollection.js +2 -2
- package/lib/esm/features/store/collections/CreateCollection.js.map +1 -1
- package/lib/esm/features/store/collections/EditCollectionView.js +43 -31
- package/lib/esm/features/store/collections/EditCollectionView.js.map +1 -1
- package/lib/esm/features/store/collections/SelectCollection.js +46 -16
- package/lib/esm/features/store/collections/SelectCollection.js.map +1 -1
- package/lib/esm/features/store/objects/DocumentSearchResults.js +43 -13
- package/lib/esm/features/store/objects/DocumentSearchResults.js.map +1 -1
- package/lib/esm/features/store/objects/DocumentTable.js +6 -6
- package/lib/esm/features/store/objects/DocumentTable.js.map +1 -1
- package/lib/esm/features/store/objects/components/ContentOverview.js +225 -87
- package/lib/esm/features/store/objects/components/ContentOverview.js.map +1 -1
- package/lib/esm/features/store/objects/components/DocumentIcon.js +11 -3
- package/lib/esm/features/store/objects/components/DocumentIcon.js.map +1 -1
- package/lib/esm/features/store/objects/components/SaveVersionConfirmModal.js +11 -2
- package/lib/esm/features/store/objects/components/SaveVersionConfirmModal.js.map +1 -1
- package/lib/esm/features/store/objects/components/useDownloadObject.js +2 -2
- package/lib/esm/features/store/objects/components/useDownloadObject.js.map +1 -1
- package/lib/esm/features/store/objects/layout/DocumentTableColumn.js +13 -1
- package/lib/esm/features/store/objects/layout/DocumentTableColumn.js.map +1 -1
- package/lib/esm/features/store/objects/layout/documentLayout.js +7 -8
- package/lib/esm/features/store/objects/layout/documentLayout.js.map +1 -1
- package/lib/esm/features/store/objects/layout/renderers.js +28 -12
- package/lib/esm/features/store/objects/layout/renderers.js.map +1 -1
- package/lib/esm/features/store/objects/search/DocumentSearchContext.js +5 -1
- package/lib/esm/features/store/objects/search/DocumentSearchContext.js.map +1 -1
- package/lib/esm/features/store/objects/search/DocumentSearchProvider.js +1 -1
- package/lib/esm/features/store/objects/search/DocumentSearchProvider.js.map +1 -1
- package/lib/esm/features/store/objects/selection/ObjectsActionContext.js +3 -2
- package/lib/esm/features/store/objects/selection/ObjectsActionContext.js.map +1 -1
- package/lib/esm/features/store/objects/selection/SelectionActions.js +2 -0
- package/lib/esm/features/store/objects/selection/SelectionActions.js.map +1 -1
- package/lib/esm/features/store/objects/selection/actions/AddToCollectionAction.js +12 -4
- package/lib/esm/features/store/objects/selection/actions/AddToCollectionAction.js.map +1 -1
- package/lib/esm/features/store/objects/selection/actions/DeleteObjectsAction.js +20 -2
- package/lib/esm/features/store/objects/selection/actions/DeleteObjectsAction.js.map +1 -1
- package/lib/esm/features/store/objects/upload/DocumentUploadModal.js +16 -8
- package/lib/esm/features/store/objects/upload/DocumentUploadModal.js.map +1 -1
- package/lib/esm/features/store/types/CreateOrUpdateTypeModal.js +1 -1
- package/lib/esm/features/store/types/CreateOrUpdateTypeModal.js.map +1 -1
- package/lib/esm/features/store/types/ObjectSchemaEditor.js +1 -1
- package/lib/esm/features/store/types/ObjectSchemaEditor.js.map +1 -1
- package/lib/esm/features/user/UserInfo.js +35 -1
- package/lib/esm/features/user/UserInfo.js.map +1 -1
- package/lib/esm/router/HistoryNavigator.js +25 -2
- package/lib/esm/router/HistoryNavigator.js.map +1 -1
- package/lib/esm/router/Nav.js +3 -3
- package/lib/esm/router/Nav.js.map +1 -1
- package/lib/esm/session/UserSession.js +1 -0
- package/lib/esm/session/UserSession.js.map +1 -1
- package/lib/esm/session/UserSessionProvider.js +9 -2
- package/lib/esm/session/UserSessionProvider.js.map +1 -1
- package/lib/esm/session/auth/composable.js +66 -67
- package/lib/esm/session/auth/composable.js.map +1 -1
- package/lib/esm/shell/login/UserInfo.js +1 -1
- package/lib/esm/shell/login/UserInfo.js.map +1 -1
- package/lib/esm/widgets/form/Form.js +17 -30
- package/lib/esm/widgets/form/Form.js.map +1 -1
- package/lib/esm/widgets/form/FormContext.js +4 -2
- package/lib/esm/widgets/form/FormContext.js.map +1 -1
- package/lib/esm/widgets/form/ManagedObject.js +4 -0
- package/lib/esm/widgets/form/ManagedObject.js.map +1 -1
- package/lib/esm/widgets/form/fields.js +4 -3
- package/lib/esm/widgets/form/fields.js.map +1 -1
- package/lib/esm/widgets/form/inputs.js +2 -0
- package/lib/esm/widgets/form/inputs.js.map +1 -1
- package/lib/esm/widgets/schema-editor/index.js +0 -1
- package/lib/esm/widgets/schema-editor/index.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types/core/components/Panel.d.ts +11 -0
- package/lib/types/core/components/Panel.d.ts.map +1 -0
- package/lib/types/core/components/SelectList.d.ts +2 -1
- package/lib/types/core/components/SelectList.d.ts.map +1 -1
- package/lib/types/core/components/SidePanel.d.ts.map +1 -1
- package/lib/types/core/components/index.d.ts +1 -1
- package/lib/types/core/components/index.d.ts.map +1 -1
- package/lib/types/core/components/shadcn/breadcrumb.d.ts +3 -2
- package/lib/types/core/components/shadcn/breadcrumb.d.ts.map +1 -1
- package/lib/types/core/components/shadcn/button.d.ts.map +1 -1
- package/lib/types/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
- package/lib/types/core/components/shadcn/index.d.ts +2 -0
- package/lib/types/core/components/shadcn/index.d.ts.map +1 -1
- package/lib/types/core/components/shadcn/input.d.ts.map +1 -1
- package/lib/types/core/components/shadcn/resizeable.d.ts +9 -0
- package/lib/types/core/components/shadcn/resizeable.d.ts.map +1 -0
- package/lib/types/core/components/shadcn/selectBox.d.ts +3 -2
- package/lib/types/core/components/shadcn/selectBox.d.ts.map +1 -1
- package/lib/types/core/components/shadcn/tabs.d.ts +2 -1
- package/lib/types/core/components/shadcn/tabs.d.ts.map +1 -1
- package/lib/types/core/components/shadcn/textarea.d.ts +4 -0
- package/lib/types/core/components/shadcn/textarea.d.ts.map +1 -0
- package/lib/types/core/hooks/CompositeState.d.ts +115 -6
- package/lib/types/core/hooks/CompositeState.d.ts.map +1 -1
- package/lib/types/core/hooks/index.d.ts +1 -0
- package/lib/types/core/hooks/index.d.ts.map +1 -1
- package/lib/types/core/hooks/useScrollableSearch.d.ts +82 -0
- package/lib/types/core/hooks/useScrollableSearch.d.ts.map +1 -0
- package/lib/types/env/index.d.ts +3 -1
- package/lib/types/env/index.d.ts.map +1 -1
- package/lib/types/features/agent/PayloadBuilder.d.ts +11 -19
- package/lib/types/features/agent/PayloadBuilder.d.ts.map +1 -1
- package/lib/types/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
- package/lib/types/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +1 -1
- package/lib/types/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
- package/lib/types/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
- package/lib/types/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.d.ts.map +1 -1
- package/lib/types/features/agent/chat/ModernAgentOutput/PlanPanel.d.ts.map +1 -1
- package/lib/types/features/facets/CollectionsFacetsNav.d.ts +14 -0
- package/lib/types/features/facets/CollectionsFacetsNav.d.ts.map +1 -0
- package/lib/types/features/facets/DocumentsFacetsNav.d.ts +1 -1
- package/lib/types/features/facets/DocumentsFacetsNav.d.ts.map +1 -1
- package/lib/types/features/facets/InteractionsFacetsNav.d.ts +14 -0
- package/lib/types/features/facets/InteractionsFacetsNav.d.ts.map +1 -0
- package/lib/types/features/facets/PromptsFacetsNav.d.ts +15 -0
- package/lib/types/features/facets/PromptsFacetsNav.d.ts.map +1 -0
- package/lib/types/features/facets/RunsFacetsNav.d.ts +1 -1
- package/lib/types/features/facets/RunsFacetsNav.d.ts.map +1 -1
- package/lib/types/features/facets/WorkflowExecutionsFacetsNav.d.ts +1 -1
- package/lib/types/features/facets/WorkflowExecutionsFacetsNav.d.ts.map +1 -1
- package/lib/types/features/facets/index.d.ts +10 -8
- package/lib/types/features/facets/index.d.ts.map +1 -1
- package/lib/types/features/facets/utils/SearchInterface.d.ts +14 -0
- package/lib/types/features/facets/utils/SearchInterface.d.ts.map +1 -0
- package/lib/types/features/facets/utils/StringFacet.d.ts.map +1 -0
- package/lib/types/features/facets/utils/StringListFacet.d.ts.map +1 -0
- package/lib/types/features/facets/utils/TypeFacet.d.ts.map +1 -0
- package/lib/types/features/facets/utils/VEnvironmentFacet.d.ts.map +1 -0
- package/lib/types/features/facets/utils/VInteractionFacet.d.ts.map +1 -0
- package/lib/types/features/facets/utils/VStringFacet.d.ts.map +1 -0
- package/lib/types/features/facets/{VTypeFacet.d.ts → utils/VTypeFacet.d.ts} +2 -1
- package/lib/types/features/facets/utils/VTypeFacet.d.ts.map +1 -0
- package/lib/types/features/facets/utils/VUserFacet.d.ts.map +1 -0
- package/lib/types/features/facets/utils/utils.d.ts.map +1 -0
- package/lib/types/features/layout/GenericPageNavHeader.d.ts +2 -1
- package/lib/types/features/layout/GenericPageNavHeader.d.ts.map +1 -1
- package/lib/types/features/store/collections/BrowseCollectionView.d.ts.map +1 -1
- package/lib/types/features/store/collections/CreateCollection.d.ts.map +1 -1
- package/lib/types/features/store/collections/EditCollectionView.d.ts.map +1 -1
- package/lib/types/features/store/collections/SelectCollection.d.ts +12 -8
- package/lib/types/features/store/collections/SelectCollection.d.ts.map +1 -1
- package/lib/types/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
- package/lib/types/features/store/objects/DocumentTable.d.ts +4 -0
- package/lib/types/features/store/objects/DocumentTable.d.ts.map +1 -1
- package/lib/types/features/store/objects/components/ContentOverview.d.ts.map +1 -1
- package/lib/types/features/store/objects/components/DocumentIcon.d.ts +7 -1
- package/lib/types/features/store/objects/components/DocumentIcon.d.ts.map +1 -1
- package/lib/types/features/store/objects/components/SaveVersionConfirmModal.d.ts.map +1 -1
- package/lib/types/features/store/objects/components/useDownloadObject.d.ts +1 -1
- package/lib/types/features/store/objects/components/useDownloadObject.d.ts.map +1 -1
- package/lib/types/features/store/objects/layout/DocumentTableColumn.d.ts +2 -1
- package/lib/types/features/store/objects/layout/DocumentTableColumn.d.ts.map +1 -1
- package/lib/types/features/store/objects/layout/documentLayout.d.ts +4 -2
- package/lib/types/features/store/objects/layout/documentLayout.d.ts.map +1 -1
- package/lib/types/features/store/objects/layout/renderers.d.ts +1 -1
- package/lib/types/features/store/objects/layout/renderers.d.ts.map +1 -1
- package/lib/types/features/store/objects/search/DocumentSearchContext.d.ts +2 -3
- package/lib/types/features/store/objects/search/DocumentSearchContext.d.ts.map +1 -1
- package/lib/types/features/store/objects/selection/ObjectsActionContext.d.ts.map +1 -1
- package/lib/types/features/store/objects/selection/SelectionActions.d.ts.map +1 -1
- package/lib/types/features/store/objects/selection/actions/DeleteObjectsAction.d.ts +1 -0
- package/lib/types/features/store/objects/selection/actions/DeleteObjectsAction.d.ts.map +1 -1
- package/lib/types/features/store/objects/upload/DocumentUploadModal.d.ts.map +1 -1
- package/lib/types/features/user/UserInfo.d.ts +12 -1
- package/lib/types/features/user/UserInfo.d.ts.map +1 -1
- package/lib/types/router/HistoryNavigator.d.ts.map +1 -1
- package/lib/types/router/Nav.d.ts +2 -1
- package/lib/types/router/Nav.d.ts.map +1 -1
- package/lib/types/session/UserSession.d.ts.map +1 -1
- package/lib/types/session/UserSessionProvider.d.ts.map +1 -1
- package/lib/types/session/auth/composable.d.ts.map +1 -1
- package/lib/types/widgets/form/Form.d.ts +2 -1
- package/lib/types/widgets/form/Form.d.ts.map +1 -1
- package/lib/types/widgets/form/FormContext.d.ts +5 -2
- package/lib/types/widgets/form/FormContext.d.ts.map +1 -1
- package/lib/types/widgets/form/ManagedObject.d.ts.map +1 -1
- package/lib/types/widgets/form/fields.d.ts +2 -2
- package/lib/types/widgets/form/fields.d.ts.map +1 -1
- package/lib/types/widgets/form/inputs.d.ts.map +1 -1
- package/lib/types/widgets/schema-editor/index.d.ts +0 -1
- package/lib/types/widgets/schema-editor/index.d.ts.map +1 -1
- package/lib/vertesia-ui-core.js +1 -1
- package/lib/vertesia-ui-core.js.map +1 -1
- package/lib/vertesia-ui-env.js +1 -1
- package/lib/vertesia-ui-env.js.map +1 -1
- package/lib/vertesia-ui-features.js +1 -1
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-router.js +1 -1
- package/lib/vertesia-ui-router.js.map +1 -1
- package/lib/vertesia-ui-session.js +1 -1
- package/lib/vertesia-ui-session.js.map +1 -1
- package/lib/vertesia-ui-shell.js +1 -1
- package/lib/vertesia-ui-shell.js.map +1 -1
- package/lib/vertesia-ui-widgets.js +1 -1
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/package.json +166 -165
- package/src/core/components/Panel.tsx +34 -0
- package/src/core/components/SelectList.tsx +11 -1
- package/src/core/components/SidePanel.tsx +18 -13
- package/src/core/components/index.ts +1 -1
- package/src/core/components/shadcn/breadcrumb.tsx +49 -30
- package/src/core/components/shadcn/button.tsx +3 -2
- package/src/core/components/shadcn/filters/filterBar.tsx +49 -23
- package/src/core/components/shadcn/index.ts +2 -0
- package/src/core/components/shadcn/input.tsx +10 -7
- package/src/core/components/shadcn/resizeable.tsx +54 -0
- package/src/core/components/shadcn/selectBox.tsx +87 -67
- package/src/core/components/shadcn/tabs.tsx +25 -8
- package/src/core/components/shadcn/textarea.tsx +21 -0
- package/src/core/components/table/index.tsx +1 -1
- package/src/core/hooks/index.ts +1 -0
- package/src/core/hooks/useScrollableSearch.tsx +193 -0
- package/src/features/agent/chat/ModernAgentConversation.tsx +109 -118
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +2 -22
- package/src/features/agent/chat/ModernAgentOutput/Header.tsx +1 -9
- package/src/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.tsx +39 -55
- package/src/features/agent/chat/ModernAgentOutput/PlanPanel.tsx +1 -0
- package/src/features/agent/chat/ModernAgentOutput/SlidingPlanPanel.tsx +8 -8
- package/src/features/agent/chat/ModernAgentOutput/WorkstreamTabs.tsx +8 -8
- package/src/features/facets/CollectionsFacetsNav.tsx +115 -0
- package/src/features/facets/DocumentsFacetsNav.tsx +22 -11
- package/src/features/facets/EnvironmentFacet.tsx +1 -1
- package/src/features/facets/InteractionsFacetsNav.tsx +121 -0
- package/src/features/facets/PromptsFacetsNav.tsx +110 -0
- package/src/features/facets/RunsFacetsNav.tsx +40 -9
- package/src/features/facets/WorkflowExecutionsFacetsNav.tsx +10 -8
- package/src/features/facets/index.ts +11 -9
- package/src/features/facets/utils/SearchInterface.tsx +12 -0
- package/src/features/facets/{VTypeFacet.tsx → utils/VTypeFacet.tsx} +12 -5
- package/src/features/facets/{VUserFacet.tsx → utils/VUserFacet.tsx} +1 -1
- package/src/features/layout/GenericPageNavHeader.tsx +73 -10
- package/src/features/store/collections/BrowseCollectionView.tsx +4 -0
- package/src/features/store/collections/CreateCollection.tsx +3 -4
- package/src/features/store/collections/EditCollectionView.tsx +104 -85
- package/src/features/store/collections/SelectCollection.tsx +214 -29
- package/src/features/store/objects/DocumentSearchResults.tsx +98 -27
- package/src/features/store/objects/DocumentTable.tsx +14 -4
- package/src/features/store/objects/components/ContentOverview.tsx +536 -267
- package/src/features/store/objects/components/DocumentIcon.tsx +42 -13
- package/src/features/store/objects/components/SaveVersionConfirmModal.tsx +12 -2
- package/src/features/store/objects/layout/DocumentTableColumn.tsx +16 -1
- package/src/features/store/objects/layout/documentLayout.tsx +10 -12
- package/src/features/store/objects/layout/knowledge.md +10 -10
- package/src/features/store/objects/layout/renderers.tsx +39 -18
- package/src/features/store/objects/search/DocumentSearchContext.ts +6 -1
- package/src/features/store/objects/search/DocumentSearchProvider.tsx +1 -1
- package/src/features/store/objects/selection/ObjectsActionContext.tsx +3 -2
- package/src/features/store/objects/selection/SelectionActions.tsx +2 -0
- package/src/features/store/objects/selection/actions/AddToCollectionAction.tsx +23 -10
- package/src/features/store/objects/selection/actions/DeleteObjectsAction.tsx +22 -2
- package/src/features/store/objects/upload/DocumentUploadModal.tsx +23 -15
- package/src/features/store/objects/upload/useSmartFileUploadProcessing.ts +10 -7
- package/src/features/store/types/CreateOrUpdateTypeModal.tsx +1 -1
- package/src/features/store/types/ObjectSchemaEditor.tsx +1 -1
- package/src/features/user/UserInfo.tsx +66 -3
- package/src/router/HistoryNavigator.ts +33 -2
- package/src/router/Nav.tsx +4 -3
- package/src/shell/login/UserInfo.tsx +1 -1
- package/src/widgets/form/Form.tsx +19 -43
- package/src/widgets/form/FormContext.ts +5 -2
- package/src/widgets/form/fields.tsx +8 -6
- package/src/widgets/form/inputs.tsx +1 -0
- package/src/widgets/schema-editor/index.ts +0 -1
- package/lib/esm/core/components/Textarea.js +0 -15
- package/lib/esm/core/components/Textarea.js.map +0 -1
- package/lib/esm/features/facets/FacetsNav.js +0 -8
- package/lib/esm/features/facets/FacetsNav.js.map +0 -1
- package/lib/esm/features/facets/StringFacet.js.map +0 -1
- package/lib/esm/features/facets/StringListFacet.js.map +0 -1
- package/lib/esm/features/facets/TypeFacet.js.map +0 -1
- package/lib/esm/features/facets/VEnvironmentFacet.js.map +0 -1
- package/lib/esm/features/facets/VFacetsNav.js +0 -48
- package/lib/esm/features/facets/VFacetsNav.js.map +0 -1
- package/lib/esm/features/facets/VInteractionFacet.js.map +0 -1
- package/lib/esm/features/facets/VStringFacet.js.map +0 -1
- package/lib/esm/features/facets/VTypeFacet.js.map +0 -1
- package/lib/esm/features/facets/VUserFacet.js.map +0 -1
- package/lib/esm/features/facets/utils.js.map +0 -1
- package/lib/esm/widgets/schema-editor/JSONSchemaEditorModal.js +0 -49
- package/lib/esm/widgets/schema-editor/JSONSchemaEditorModal.js.map +0 -1
- package/lib/types/core/components/Textarea.d.ts +0 -8
- package/lib/types/core/components/Textarea.d.ts.map +0 -1
- package/lib/types/features/facets/FacetsNav.d.ts +0 -7
- package/lib/types/features/facets/FacetsNav.d.ts.map +0 -1
- package/lib/types/features/facets/StringFacet.d.ts.map +0 -1
- package/lib/types/features/facets/StringListFacet.d.ts.map +0 -1
- package/lib/types/features/facets/TypeFacet.d.ts.map +0 -1
- package/lib/types/features/facets/VEnvironmentFacet.d.ts.map +0 -1
- package/lib/types/features/facets/VFacetsNav.d.ts +0 -16
- package/lib/types/features/facets/VFacetsNav.d.ts.map +0 -1
- package/lib/types/features/facets/VInteractionFacet.d.ts.map +0 -1
- package/lib/types/features/facets/VStringFacet.d.ts.map +0 -1
- package/lib/types/features/facets/VTypeFacet.d.ts.map +0 -1
- package/lib/types/features/facets/VUserFacet.d.ts.map +0 -1
- package/lib/types/features/facets/utils.d.ts.map +0 -1
- package/lib/types/widgets/schema-editor/JSONSchemaEditorModal.d.ts +0 -10
- package/lib/types/widgets/schema-editor/JSONSchemaEditorModal.d.ts.map +0 -1
- package/src/core/components/Textarea.tsx +0 -25
- package/src/features/facets/FacetsNav.tsx +0 -19
- package/src/features/facets/VFacetsNav.tsx +0 -81
- package/src/widgets/schema-editor/JSONSchemaEditorModal.tsx +0 -67
- /package/lib/esm/features/facets/{StringFacet.js → utils/StringFacet.js} +0 -0
- /package/lib/esm/features/facets/{StringListFacet.js → utils/StringListFacet.js} +0 -0
- /package/lib/esm/features/facets/{TypeFacet.js → utils/TypeFacet.js} +0 -0
- /package/lib/esm/features/facets/{VEnvironmentFacet.js → utils/VEnvironmentFacet.js} +0 -0
- /package/lib/esm/features/facets/{VInteractionFacet.js → utils/VInteractionFacet.js} +0 -0
- /package/lib/esm/features/facets/{VStringFacet.js → utils/VStringFacet.js} +0 -0
- /package/lib/esm/features/facets/{utils.js → utils/utils.js} +0 -0
- /package/lib/types/features/facets/{StringFacet.d.ts → utils/StringFacet.d.ts} +0 -0
- /package/lib/types/features/facets/{StringListFacet.d.ts → utils/StringListFacet.d.ts} +0 -0
- /package/lib/types/features/facets/{TypeFacet.d.ts → utils/TypeFacet.d.ts} +0 -0
- /package/lib/types/features/facets/{VEnvironmentFacet.d.ts → utils/VEnvironmentFacet.d.ts} +0 -0
- /package/lib/types/features/facets/{VInteractionFacet.d.ts → utils/VInteractionFacet.d.ts} +0 -0
- /package/lib/types/features/facets/{VStringFacet.d.ts → utils/VStringFacet.d.ts} +0 -0
- /package/lib/types/features/facets/{VUserFacet.d.ts → utils/VUserFacet.d.ts} +0 -0
- /package/lib/types/features/facets/{utils.d.ts → utils/utils.d.ts} +0 -0
- /package/src/features/facets/{StringFacet.tsx → utils/StringFacet.tsx} +0 -0
- /package/src/features/facets/{StringListFacet.tsx → utils/StringListFacet.tsx} +0 -0
- /package/src/features/facets/{TypeFacet.tsx → utils/TypeFacet.tsx} +0 -0
- /package/src/features/facets/{VEnvironmentFacet.tsx → utils/VEnvironmentFacet.tsx} +0 -0
- /package/src/features/facets/{VInteractionFacet.tsx → utils/VInteractionFacet.tsx} +0 -0
- /package/src/features/facets/{VStringFacet.tsx → utils/VStringFacet.tsx} +0 -0
- /package/src/features/facets/{utils.tsx → utils/utils.tsx} +0 -0
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
1
|
+
import { useEffect, useState, memo } from "react";
|
|
2
2
|
|
|
3
3
|
import { useUserSession } from "@vertesia/ui/session";
|
|
4
|
-
import { Button, Spinner, useToast } from "@vertesia/ui/core";
|
|
4
|
+
import { Button, ResizableHandle, ResizablePanel, ResizablePanelGroup, Spinner, useToast } from "@vertesia/ui/core";
|
|
5
5
|
import { JSONDisplay, MarkdownRenderer } from "@vertesia/ui/widgets";
|
|
6
|
-
import { ContentObject, ImageRenditionFormat } from "@vertesia/common";
|
|
7
|
-
import { Copy, Download, SquarePen } from "lucide-react";
|
|
6
|
+
import { ContentNature, ContentObject, ImageRenditionFormat, VideoMetadata, POSTER_RENDITION_NAME } from "@vertesia/common";
|
|
7
|
+
import { Copy, Download, SquarePen, AlertTriangle } from "lucide-react";
|
|
8
8
|
import { PropertiesEditorModal } from "./PropertiesEditorModal";
|
|
9
9
|
import { NavLink } from "@vertesia/ui/router";
|
|
10
10
|
|
|
11
|
+
// Maximum text size before cropping (128K characters)
|
|
12
|
+
const MAX_TEXT_DISPLAY_SIZE = 128 * 1024;
|
|
13
|
+
|
|
14
|
+
enum PanelView {
|
|
15
|
+
Text = "text",
|
|
16
|
+
Image = "image",
|
|
17
|
+
Video = "video"
|
|
18
|
+
}
|
|
19
|
+
|
|
11
20
|
interface ContentOverviewProps {
|
|
12
21
|
object: ContentObject;
|
|
13
22
|
loadText?: boolean;
|
|
@@ -18,15 +27,51 @@ export function ContentOverview({
|
|
|
18
27
|
loadText,
|
|
19
28
|
refetch,
|
|
20
29
|
}: ContentOverviewProps) {
|
|
21
|
-
const { client, store } = useUserSession();
|
|
22
|
-
const [isLoadingText, setIsLoadingText] = useState(false);
|
|
23
|
-
const [text, setText] = useState<string | undefined>(object.text);
|
|
24
|
-
const [imageUrl, setImageUrl] = useState<string>();
|
|
25
|
-
const [isPropertiesModalOpen, setPropertiesModalOpen] = useState(false);
|
|
26
30
|
const toast = useToast();
|
|
31
|
+
|
|
32
|
+
const handleCopyContent = async (
|
|
33
|
+
content: string,
|
|
34
|
+
type: "text" | "properties",
|
|
35
|
+
) => {
|
|
36
|
+
try {
|
|
37
|
+
await navigator.clipboard.writeText(content);
|
|
38
|
+
toast({
|
|
39
|
+
status: "success",
|
|
40
|
+
title: `${type === "text" ? "Content" : "Properties"} copied`,
|
|
41
|
+
description: `Successfully copied ${type} to clipboard`,
|
|
42
|
+
duration: 2000,
|
|
43
|
+
});
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.error(`Failed to copy ${type}:`, err);
|
|
46
|
+
toast({
|
|
47
|
+
status: "error",
|
|
48
|
+
title: "Copy failed",
|
|
49
|
+
description: `Failed to copy ${type} to clipboard`,
|
|
50
|
+
duration: 5000,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<>
|
|
57
|
+
<ResizablePanelGroup direction="horizontal" className="h-[calc(100vh-200px)]">
|
|
58
|
+
<ResizablePanel className="min-w-[100px]">
|
|
59
|
+
<PropertiesPanel object={object} refetch={refetch ?? (() => Promise.resolve())} handleCopyContent={handleCopyContent} />
|
|
60
|
+
</ResizablePanel>
|
|
61
|
+
<ResizableHandle withHandle />
|
|
62
|
+
|
|
63
|
+
<ResizablePanel className="min-w-[100px]">
|
|
64
|
+
<DataPanel object={object} loadText={loadText ?? false} handleCopyContent={handleCopyContent} />
|
|
65
|
+
</ResizablePanel>
|
|
66
|
+
</ResizablePanelGroup>
|
|
67
|
+
|
|
68
|
+
</>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function PropertiesPanel({ object, refetch, handleCopyContent }: { object: ContentObject, refetch: () => Promise<unknown>, handleCopyContent: (content: string, type: "text" | "properties") => Promise<void> }) {
|
|
27
73
|
const [viewCode, setViewCode] = useState(false);
|
|
28
|
-
const
|
|
29
|
-
const VIEW_TEXT = "Preview";
|
|
74
|
+
const [isPropertiesModalOpen, setPropertiesModalOpen] = useState(false);
|
|
30
75
|
|
|
31
76
|
const handleOpenPropertiesModal = () => {
|
|
32
77
|
setPropertiesModalOpen(true);
|
|
@@ -36,13 +81,119 @@ export function ContentOverview({
|
|
|
36
81
|
setPropertiesModalOpen(false);
|
|
37
82
|
};
|
|
38
83
|
|
|
84
|
+
return (
|
|
85
|
+
<>
|
|
86
|
+
<div className="flex justify-between items-center px-2">
|
|
87
|
+
<div className="flex items-center gap-1 bg-muted mb-2 p-1 rounded">
|
|
88
|
+
<Button
|
|
89
|
+
variant={`${viewCode ? "ghost" : "primary"}`}
|
|
90
|
+
size="sm"
|
|
91
|
+
alt="Preview properties"
|
|
92
|
+
onClick={() => setViewCode(!viewCode)}
|
|
93
|
+
>
|
|
94
|
+
Properties
|
|
95
|
+
</Button>
|
|
96
|
+
<Button
|
|
97
|
+
variant={`${viewCode ? "primary" : "ghost"}`}
|
|
98
|
+
size="sm"
|
|
99
|
+
alt="View in JSON format"
|
|
100
|
+
onClick={() => setViewCode(!viewCode)}
|
|
101
|
+
>
|
|
102
|
+
JSON
|
|
103
|
+
</Button>
|
|
104
|
+
</div>
|
|
105
|
+
<div className="flex items-center gap-2">
|
|
106
|
+
{object.properties && (
|
|
107
|
+
<Button
|
|
108
|
+
variant="ghost"
|
|
109
|
+
size="sm"
|
|
110
|
+
title="Copy properties"
|
|
111
|
+
onClick={() =>
|
|
112
|
+
handleCopyContent(
|
|
113
|
+
JSON.stringify(
|
|
114
|
+
object.properties,
|
|
115
|
+
null,
|
|
116
|
+
2,
|
|
117
|
+
),
|
|
118
|
+
"properties",
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
>
|
|
122
|
+
<Copy className="size-4" />
|
|
123
|
+
</Button>
|
|
124
|
+
)}
|
|
125
|
+
<Button
|
|
126
|
+
variant="ghost"
|
|
127
|
+
size="sm"
|
|
128
|
+
onClick={handleOpenPropertiesModal}
|
|
129
|
+
title="Edit properties"
|
|
130
|
+
className="flex items-center gap-2"
|
|
131
|
+
>
|
|
132
|
+
<SquarePen className="size-4" />
|
|
133
|
+
</Button>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
{
|
|
138
|
+
object.properties ? (
|
|
139
|
+
<div className="h-[calc(100vh-220px)] overflow-auto px-2">
|
|
140
|
+
<JSONDisplay
|
|
141
|
+
value={object.properties}
|
|
142
|
+
viewCode={viewCode}
|
|
143
|
+
|
|
144
|
+
/>
|
|
145
|
+
</div>
|
|
146
|
+
) : (
|
|
147
|
+
<div className="h-[calc(100vh-220px)] overflow-auto px-2">
|
|
148
|
+
<div>No properties defined</div>
|
|
149
|
+
</div>
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
{/* Properties Editor Modal */}
|
|
153
|
+
<PropertiesEditorModal
|
|
154
|
+
isOpen={isPropertiesModalOpen}
|
|
155
|
+
onClose={handleClosePropertiesModal}
|
|
156
|
+
object={object}
|
|
157
|
+
refetch={refetch}
|
|
158
|
+
/>
|
|
159
|
+
</>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function DataPanel({ object, loadText, handleCopyContent }: { object: ContentObject, loadText: boolean, handleCopyContent: (content: string, type: "text" | "properties") => Promise<void> }) {
|
|
164
|
+
const { store } = useUserSession();
|
|
165
|
+
|
|
166
|
+
const isImage = object?.metadata?.type === ContentNature.Image;
|
|
167
|
+
const isVideo = object?.metadata?.type === ContentNature.Video;
|
|
168
|
+
|
|
169
|
+
// Determine initial panel view
|
|
170
|
+
const getInitialView = (): PanelView => {
|
|
171
|
+
if (isVideo) return PanelView.Video;
|
|
172
|
+
if (isImage) return PanelView.Image;
|
|
173
|
+
return PanelView.Text;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const [currentPanel, setCurrentPanel] = useState<PanelView>(getInitialView());
|
|
177
|
+
|
|
178
|
+
const [text, setText] = useState<string | undefined>(object.text);
|
|
179
|
+
const [isLoadingText, setIsLoadingText] = useState<boolean>(false);
|
|
180
|
+
const [isTextCropped, setIsTextCropped] = useState<boolean>(false);
|
|
181
|
+
|
|
39
182
|
useEffect(() => {
|
|
40
183
|
if (loadText && !text) {
|
|
41
184
|
setIsLoadingText(true);
|
|
42
185
|
store.objects
|
|
43
186
|
.getObjectText(object.id)
|
|
44
187
|
.then((res) => {
|
|
45
|
-
|
|
188
|
+
if (res.text.length > MAX_TEXT_DISPLAY_SIZE) {
|
|
189
|
+
// Crop the text to 128K characters
|
|
190
|
+
const croppedText = res.text.substring(0, MAX_TEXT_DISPLAY_SIZE);
|
|
191
|
+
setText(croppedText);
|
|
192
|
+
setIsTextCropped(true);
|
|
193
|
+
} else {
|
|
194
|
+
setText(res.text);
|
|
195
|
+
setIsTextCropped(false);
|
|
196
|
+
}
|
|
46
197
|
})
|
|
47
198
|
.catch((err) => {
|
|
48
199
|
console.error("Failed to load text", err);
|
|
@@ -53,30 +204,87 @@ export function ContentOverview({
|
|
|
53
204
|
}
|
|
54
205
|
}, [loadText]);
|
|
55
206
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
207
|
+
return (
|
|
208
|
+
<>
|
|
209
|
+
<div className="flex justify-between items-center px-2">
|
|
210
|
+
<div className="flex items-center gap-1 bg-muted mb-2 p-1 rounded">
|
|
211
|
+
{isImage &&
|
|
212
|
+
<Button
|
|
213
|
+
variant={currentPanel === PanelView.Image ? "primary" : "ghost"}
|
|
214
|
+
size="sm"
|
|
215
|
+
alt="View Image"
|
|
216
|
+
onClick={() => setCurrentPanel(PanelView.Image)}
|
|
217
|
+
>
|
|
218
|
+
Image
|
|
219
|
+
</Button>
|
|
220
|
+
}
|
|
221
|
+
{isVideo &&
|
|
222
|
+
<Button
|
|
223
|
+
variant={currentPanel === PanelView.Video ? "primary" : "ghost"}
|
|
224
|
+
size="sm"
|
|
225
|
+
alt="View Video"
|
|
226
|
+
onClick={() => setCurrentPanel(PanelView.Video)}
|
|
227
|
+
>
|
|
228
|
+
Video
|
|
229
|
+
</Button>
|
|
230
|
+
}
|
|
231
|
+
<Button
|
|
232
|
+
variant={currentPanel === PanelView.Text ? "primary" : "ghost"}
|
|
233
|
+
size="sm"
|
|
234
|
+
alt="View Text"
|
|
235
|
+
onClick={() => setCurrentPanel(PanelView.Text)}
|
|
236
|
+
>
|
|
237
|
+
Text
|
|
238
|
+
</Button>
|
|
239
|
+
|
|
240
|
+
</div>
|
|
241
|
+
{currentPanel === PanelView.Text && <TextActions object={object} text={text} handleCopyContent={handleCopyContent} />}
|
|
242
|
+
</div>
|
|
243
|
+
{
|
|
244
|
+
currentPanel === PanelView.Image ? (
|
|
245
|
+
<ImagePanel object={object} />
|
|
246
|
+
) : currentPanel === PanelView.Video ? (
|
|
247
|
+
<VideoPanel object={object} />
|
|
248
|
+
) : (
|
|
249
|
+
isLoadingText ? (
|
|
250
|
+
<div className="flex justify-center items-center h-[calc(100vh-260px)]">
|
|
251
|
+
<Spinner size="lg" />
|
|
252
|
+
</div>
|
|
253
|
+
) : (
|
|
254
|
+
<TextPanel object={object} text={text} isTextCropped={isTextCropped} />
|
|
255
|
+
)
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
</>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function TextActions({ object, text, handleCopyContent }: { object: ContentObject, handleCopyContent: (content: string, type: "text" | "properties") => Promise<void>, text: string | undefined }) {
|
|
263
|
+
const { client } = useUserSession();
|
|
264
|
+
const toast = useToast();
|
|
265
|
+
const [loadingFormat, setLoadingFormat] = useState<"docx" | "pdf" | null>(null);
|
|
266
|
+
|
|
267
|
+
const content = object.content;
|
|
268
|
+
|
|
269
|
+
const isMarkdown =
|
|
270
|
+
content &&
|
|
271
|
+
content.type &&
|
|
272
|
+
content.type === "text/markdown";
|
|
78
273
|
|
|
79
274
|
const handleExportDocument = async (format: "docx" | "pdf") => {
|
|
275
|
+
// Prevent multiple concurrent exports
|
|
276
|
+
if (loadingFormat) return;
|
|
277
|
+
|
|
278
|
+
setLoadingFormat(format);
|
|
279
|
+
|
|
280
|
+
// Show immediate feedback
|
|
281
|
+
toast({
|
|
282
|
+
status: "info",
|
|
283
|
+
title: `Preparing ${format.toUpperCase()}`,
|
|
284
|
+
description: "Fetching your document...",
|
|
285
|
+
duration: 2000,
|
|
286
|
+
});
|
|
287
|
+
|
|
80
288
|
try {
|
|
81
289
|
// Request document rendition from the server
|
|
82
290
|
const response = await client.objects.getRendition(object.id, {
|
|
@@ -140,262 +348,323 @@ export function ContentOverview({
|
|
|
140
348
|
description: `Failed to export document to ${format.toUpperCase()} format`,
|
|
141
349
|
duration: 5000,
|
|
142
350
|
});
|
|
351
|
+
} finally {
|
|
352
|
+
setLoadingFormat(null);
|
|
143
353
|
}
|
|
144
354
|
};
|
|
145
355
|
|
|
146
356
|
const handleExportDocx = () => handleExportDocument("docx");
|
|
147
357
|
const handleExportPdf = () => handleExportDocument("pdf");
|
|
358
|
+
return (
|
|
359
|
+
<div className="h-[41px] text-lg font-semibold flex justify-between items-center px-2">
|
|
360
|
+
<div className="flex items-center gap-2">
|
|
361
|
+
{text && (
|
|
362
|
+
<Button variant="ghost" size="sm" title="Copy text" className="flex items-center gap-2" onClick={() => handleCopyContent(text, "text")}>
|
|
363
|
+
<Copy className="size-4" />
|
|
364
|
+
</Button>
|
|
365
|
+
)}
|
|
366
|
+
{isMarkdown && text && (
|
|
367
|
+
<>
|
|
368
|
+
<Button
|
|
369
|
+
variant="ghost"
|
|
370
|
+
size="sm"
|
|
371
|
+
onClick={handleExportDocx}
|
|
372
|
+
disabled={loadingFormat !== null}
|
|
373
|
+
className="flex items-center gap-2"
|
|
374
|
+
>
|
|
375
|
+
{loadingFormat === "docx" ? (
|
|
376
|
+
<Spinner size="sm" />
|
|
377
|
+
) : (
|
|
378
|
+
<Download className="size-4" />
|
|
379
|
+
)}
|
|
380
|
+
DOCX
|
|
381
|
+
</Button>
|
|
382
|
+
<Button
|
|
383
|
+
variant="ghost"
|
|
384
|
+
size="sm"
|
|
385
|
+
onClick={handleExportPdf}
|
|
386
|
+
disabled={loadingFormat !== null}
|
|
387
|
+
className="flex items-center gap-2"
|
|
388
|
+
>
|
|
389
|
+
{loadingFormat === "pdf" ? (
|
|
390
|
+
<Spinner size="sm" />
|
|
391
|
+
) : (
|
|
392
|
+
<Download className="size-4" />
|
|
393
|
+
)}
|
|
394
|
+
PDF
|
|
395
|
+
</Button>
|
|
396
|
+
</>
|
|
397
|
+
)}
|
|
398
|
+
</div>
|
|
399
|
+
</div>
|
|
400
|
+
);
|
|
401
|
+
}
|
|
148
402
|
|
|
403
|
+
const TextPanel = memo(({ object, text, isTextCropped }: { object: ContentObject, text: string | undefined, isTextCropped: boolean }) => {
|
|
149
404
|
const content = object.content;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
content.source &&
|
|
153
|
-
content.type &&
|
|
154
|
-
content.type.startsWith("image/");
|
|
405
|
+
|
|
406
|
+
// Check if content type is markdown or plain text
|
|
155
407
|
const isMarkdownOrText =
|
|
156
408
|
content &&
|
|
157
409
|
content.type &&
|
|
158
410
|
(content.type === "text/markdown" || content.type === "text/plain");
|
|
159
|
-
// Check for markdown indicators, ignoring any HTML comments
|
|
160
|
-
const seemsMarkdown =
|
|
161
|
-
text &&
|
|
162
|
-
// Look for markdown indicators
|
|
163
|
-
(text.includes("\n#") ||
|
|
164
|
-
text.includes("\n*") ||
|
|
165
|
-
text.includes("\n+") ||
|
|
166
|
-
text.includes("!["));
|
|
167
411
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
} else {
|
|
180
|
-
return object;
|
|
181
|
-
}
|
|
182
|
-
})
|
|
183
|
-
.catch(() => {
|
|
184
|
-
return object;
|
|
185
|
-
})
|
|
186
|
-
.then(() => {
|
|
187
|
-
client.files
|
|
188
|
-
.getDownloadUrl(object.content.source!)
|
|
189
|
-
.then((r) => {
|
|
190
|
-
setImageUrl(r.url);
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
}, []);
|
|
412
|
+
// Check if text content looks like markdown
|
|
413
|
+
const seemsMarkdown = text && (
|
|
414
|
+
text.includes("\n# ") ||
|
|
415
|
+
text.includes("\n## ") ||
|
|
416
|
+
text.includes("\n### ") ||
|
|
417
|
+
text.includes("\n* ") ||
|
|
418
|
+
text.includes("\n- ") ||
|
|
419
|
+
text.includes("\n+ ") ||
|
|
420
|
+
text.includes("
|
|
422
|
+
);
|
|
195
423
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
<div className="flex flex-col lg:flex-row lg:gap-8">
|
|
199
|
-
<div className="w-full lg:w-1/2">
|
|
200
|
-
<div className="h-[41px] text-lg font-semibold mb-4 border-b flex justify-between items-center">
|
|
201
|
-
<div className="flex items-center gap-1">
|
|
202
|
-
Properties
|
|
203
|
-
<Button
|
|
204
|
-
variant="outline"
|
|
205
|
-
size="sm"
|
|
206
|
-
alt={`${viewCode ? "Preview" : "View in JSON format"}`}
|
|
207
|
-
onClick={() => setViewCode(!viewCode)}
|
|
208
|
-
>
|
|
209
|
-
{viewCode ? VIEW_TEXT : VIEW_JSON}
|
|
210
|
-
</Button>
|
|
211
|
-
</div>
|
|
212
|
-
<div className="flex items-center gap-2">
|
|
213
|
-
{object.properties && (
|
|
214
|
-
<Button
|
|
215
|
-
variant="ghost"
|
|
216
|
-
size="sm"
|
|
217
|
-
title="Copy properties"
|
|
218
|
-
onClick={() =>
|
|
219
|
-
handleCopyContent(
|
|
220
|
-
JSON.stringify(
|
|
221
|
-
object.properties,
|
|
222
|
-
null,
|
|
223
|
-
2,
|
|
224
|
-
),
|
|
225
|
-
"properties",
|
|
226
|
-
)
|
|
227
|
-
}
|
|
228
|
-
>
|
|
229
|
-
<Copy className="size-4" />
|
|
230
|
-
</Button>
|
|
231
|
-
)}
|
|
232
|
-
<Button
|
|
233
|
-
variant="ghost"
|
|
234
|
-
size="sm"
|
|
235
|
-
onClick={handleOpenPropertiesModal}
|
|
236
|
-
title="Edit properties"
|
|
237
|
-
className="flex items-center gap-2"
|
|
238
|
-
>
|
|
239
|
-
<SquarePen className="size-4" />
|
|
240
|
-
</Button>
|
|
241
|
-
</div>
|
|
242
|
-
</div>
|
|
243
|
-
{object.properties ? (
|
|
244
|
-
<JSONDisplay
|
|
245
|
-
value={object.properties}
|
|
246
|
-
viewCode={viewCode}
|
|
247
|
-
/>
|
|
248
|
-
) : (
|
|
249
|
-
<div>No properties defined</div>
|
|
250
|
-
)}
|
|
251
|
-
{isImage && (
|
|
252
|
-
<div className="my-4">
|
|
253
|
-
<div className="h-[41px] text-lg font-semibold mb-4 border-b flex justify-between items-center">
|
|
254
|
-
<span className="py-1">Image</span>
|
|
255
|
-
</div>
|
|
256
|
-
{imageUrl ? (
|
|
257
|
-
<img
|
|
258
|
-
src={imageUrl}
|
|
259
|
-
alt={object.name}
|
|
260
|
-
className="w-full object-contain"
|
|
261
|
-
/>
|
|
262
|
-
) : (
|
|
263
|
-
<Spinner size="md" />
|
|
264
|
-
)}
|
|
265
|
-
</div>
|
|
266
|
-
)}
|
|
267
|
-
</div>
|
|
424
|
+
// Render as markdown if it's markdown/text type OR if text looks like markdown
|
|
425
|
+
const shouldRenderAsMarkdown = isMarkdownOrText || seemsMarkdown;
|
|
268
426
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
title="Copy text"
|
|
278
|
-
onClick={() =>
|
|
279
|
-
handleCopyContent(text, "text")
|
|
280
|
-
}
|
|
281
|
-
className="flex items-center gap-2"
|
|
282
|
-
>
|
|
283
|
-
<Copy className="h-4 w-4" />
|
|
284
|
-
</Button>
|
|
285
|
-
)}
|
|
286
|
-
{(isMarkdownOrText || seemsMarkdown) && text && (
|
|
287
|
-
<>
|
|
288
|
-
<Button
|
|
289
|
-
variant="ghost"
|
|
290
|
-
size="sm"
|
|
291
|
-
onClick={handleExportDocx}
|
|
292
|
-
className="flex items-center gap-2"
|
|
293
|
-
>
|
|
294
|
-
<Download className="h-4 w-4" />
|
|
295
|
-
DOCX
|
|
296
|
-
</Button>
|
|
297
|
-
<Button
|
|
298
|
-
variant="ghost"
|
|
299
|
-
size="sm"
|
|
300
|
-
onClick={handleExportPdf}
|
|
301
|
-
className="flex items-center gap-2"
|
|
302
|
-
>
|
|
303
|
-
<Download className="h-4 w-4" />
|
|
304
|
-
PDF
|
|
305
|
-
</Button>
|
|
306
|
-
</>
|
|
307
|
-
)}
|
|
427
|
+
return (
|
|
428
|
+
text ? (
|
|
429
|
+
<>
|
|
430
|
+
{isTextCropped && (
|
|
431
|
+
<div className="px-2 py-2 bg-attention/10 border-l-4 border-attention mx-2 mb-2 rounded">
|
|
432
|
+
<div className="flex items-center gap-2 text-attention">
|
|
433
|
+
<AlertTriangle className="size-4" />
|
|
434
|
+
<span className="text-sm font-semibold">Showing first 128K characters only</span>
|
|
308
435
|
</div>
|
|
309
436
|
</div>
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
437
|
+
)}
|
|
438
|
+
<div className="max-w-7xl px-2 h-[calc(100vh-210px)] overflow-auto">
|
|
439
|
+
{shouldRenderAsMarkdown ? (
|
|
440
|
+
<div className="vprose prose-sm p-1">
|
|
441
|
+
<MarkdownRenderer
|
|
442
|
+
components={{
|
|
443
|
+
a: ({ node, ...props }: { node?: any; href?: string; children?: React.ReactNode }) => {
|
|
444
|
+
const href = props.href || "";
|
|
445
|
+
if (href.includes("/store/objects/")) {
|
|
446
|
+
return (
|
|
447
|
+
<NavLink
|
|
448
|
+
topLevelNav
|
|
449
|
+
href={href}
|
|
450
|
+
className="text-info"
|
|
451
|
+
>
|
|
452
|
+
{props.children}
|
|
453
|
+
</NavLink>
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
return <a {...props} data-debug="test" target="_blank" rel="noopener noreferrer" />;
|
|
457
|
+
},
|
|
458
|
+
p: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
459
|
+
<p {...props} className={`my-0`} />
|
|
460
|
+
),
|
|
461
|
+
pre: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
462
|
+
<pre {...props} className={`my-2 p-2 rounded`} />
|
|
463
|
+
),
|
|
464
|
+
code: ({
|
|
465
|
+
node,
|
|
466
|
+
className,
|
|
467
|
+
children,
|
|
468
|
+
...props
|
|
469
|
+
}: {
|
|
470
|
+
node?: any;
|
|
471
|
+
className?: string;
|
|
472
|
+
children?: React.ReactNode;
|
|
473
|
+
}) => {
|
|
474
|
+
const match = /language-(\w+)/.exec(className || "");
|
|
475
|
+
const isInline = !match;
|
|
476
|
+
return (
|
|
477
|
+
<code
|
|
478
|
+
{...props}
|
|
479
|
+
className={
|
|
480
|
+
isInline
|
|
481
|
+
? `px-1.5 py-0.5 rounded`
|
|
482
|
+
: "text-muted"
|
|
329
483
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
<code
|
|
352
|
-
{...props}
|
|
353
|
-
className={
|
|
354
|
-
isInline
|
|
355
|
-
? `px-1.5 py-0.5 rounded`
|
|
356
|
-
: "text-muted"
|
|
357
|
-
}
|
|
358
|
-
>
|
|
359
|
-
{children}
|
|
360
|
-
</code>
|
|
361
|
-
);
|
|
362
|
-
},
|
|
363
|
-
h1: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
364
|
-
<h1 {...props} className={`font-bold text-2xl my-2`} />
|
|
365
|
-
),
|
|
366
|
-
h2: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
367
|
-
<h2 {...props} className={`font-bold text-xl my-2`} />
|
|
368
|
-
),
|
|
369
|
-
h3: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
370
|
-
<h3 {...props} className={`font-bold text-lg my-2`} />
|
|
371
|
-
),
|
|
372
|
-
li: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
373
|
-
<li {...props} />
|
|
374
|
-
),
|
|
375
|
-
}}
|
|
376
|
-
>
|
|
377
|
-
{text}
|
|
378
|
-
</MarkdownRenderer>
|
|
379
|
-
</div>
|
|
380
|
-
) : (
|
|
381
|
-
<pre className="text-wrap bg-muted text-muted p-2">
|
|
382
|
-
{text}
|
|
383
|
-
</pre>
|
|
384
|
-
)}
|
|
484
|
+
>
|
|
485
|
+
{children}
|
|
486
|
+
</code>
|
|
487
|
+
);
|
|
488
|
+
},
|
|
489
|
+
h1: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
490
|
+
<h1 {...props} className={`font-bold text-2xl my-2`} />
|
|
491
|
+
),
|
|
492
|
+
h2: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
493
|
+
<h2 {...props} className={`font-bold text-xl my-2`} />
|
|
494
|
+
),
|
|
495
|
+
h3: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
496
|
+
<h3 {...props} className={`font-bold text-lg my-2`} />
|
|
497
|
+
),
|
|
498
|
+
li: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
499
|
+
<li {...props} />
|
|
500
|
+
),
|
|
501
|
+
}}
|
|
502
|
+
>
|
|
503
|
+
{text}
|
|
504
|
+
</MarkdownRenderer>
|
|
385
505
|
</div>
|
|
386
506
|
) : (
|
|
387
|
-
<
|
|
507
|
+
<pre className="text-wrap bg-muted text-muted p-2">
|
|
508
|
+
{text}
|
|
509
|
+
</pre>
|
|
388
510
|
)}
|
|
389
511
|
</div>
|
|
512
|
+
</>
|
|
513
|
+
) :
|
|
514
|
+
<div className="px-2">
|
|
515
|
+
<div>No content</div>
|
|
390
516
|
</div>
|
|
517
|
+
);
|
|
518
|
+
});
|
|
391
519
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
520
|
+
function ImagePanel({ object }: { object: ContentObject }) {
|
|
521
|
+
const { client } = useUserSession();
|
|
522
|
+
const [imageUrl, setImageUrl] = useState<string>();
|
|
523
|
+
|
|
524
|
+
const content = object.content;
|
|
525
|
+
const isImage = object.metadata && object.metadata.type === ContentNature.Image;
|
|
526
|
+
|
|
527
|
+
useEffect(() => {
|
|
528
|
+
if (isImage) {
|
|
529
|
+
const loadImage = async () => {
|
|
530
|
+
const webSupportedFormats = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml'];
|
|
531
|
+
const isOriginalWebSupported = content?.type && webSupportedFormats.includes(content.type);
|
|
532
|
+
|
|
533
|
+
try {
|
|
534
|
+
const rendition = await client.objects.getRendition(object.id, {
|
|
535
|
+
format: ImageRenditionFormat.jpeg,
|
|
536
|
+
generate_if_missing: false,
|
|
537
|
+
sign_url: true,
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
if (rendition.status === "found" && rendition.renditions?.length) {
|
|
541
|
+
// Use rendition URL directly
|
|
542
|
+
setImageUrl(rendition.renditions[0]);
|
|
543
|
+
} else if (isOriginalWebSupported) {
|
|
544
|
+
// Fall back to original file only if web-supported
|
|
545
|
+
const downloadUrl = await client.files.getDownloadUrl(object.content.source!);
|
|
546
|
+
setImageUrl(downloadUrl.url);
|
|
547
|
+
}
|
|
548
|
+
} catch (error) {
|
|
549
|
+
// Fall back to original file only if web-supported
|
|
550
|
+
if (isOriginalWebSupported) {
|
|
551
|
+
const downloadUrl = await client.files.getDownloadUrl(object.content.source!);
|
|
552
|
+
setImageUrl(downloadUrl.url);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
loadImage();
|
|
558
|
+
}
|
|
559
|
+
}, []);
|
|
560
|
+
|
|
561
|
+
return (
|
|
562
|
+
<div className="mb-4 px-2">
|
|
563
|
+
{imageUrl ? (
|
|
564
|
+
<img
|
|
565
|
+
src={imageUrl}
|
|
566
|
+
alt={object.name}
|
|
567
|
+
className="w-full object-contain"
|
|
568
|
+
/>
|
|
569
|
+
) : (
|
|
570
|
+
<Spinner size="md" />
|
|
571
|
+
)}
|
|
399
572
|
</div>
|
|
400
573
|
);
|
|
401
574
|
}
|
|
575
|
+
|
|
576
|
+
function VideoPanel({ object }: { object: ContentObject }) {
|
|
577
|
+
const { client } = useUserSession();
|
|
578
|
+
const [videoUrl, setVideoUrl] = useState<string>();
|
|
579
|
+
const [posterUrl, setPosterUrl] = useState<string>();
|
|
580
|
+
const [isLoading, setIsLoading] = useState<boolean>(true);
|
|
581
|
+
|
|
582
|
+
const content = object.content;
|
|
583
|
+
const isVideo = object.metadata?.type === ContentNature.Video;
|
|
584
|
+
|
|
585
|
+
// Check if there are mp4 or webm renditions available in metadata
|
|
586
|
+
const metadata = object.metadata as VideoMetadata;
|
|
587
|
+
const renditions = metadata?.renditions || [];
|
|
588
|
+
|
|
589
|
+
// Find mp4 or webm rendition by mime type, preferring mp4
|
|
590
|
+
const webRendition = renditions.find(r => r.content.type === 'video/mp4') ||
|
|
591
|
+
renditions.find(r => r.content.type === 'video/webm');
|
|
592
|
+
|
|
593
|
+
// Check if original file is web-compatible
|
|
594
|
+
const webSupportedFormats = ['video/mp4', 'video/webm'];
|
|
595
|
+
const isOriginalWebSupported = content?.type && webSupportedFormats.includes(content.type);
|
|
596
|
+
|
|
597
|
+
// Get poster
|
|
598
|
+
const poster = renditions.find(r => r.name === POSTER_RENDITION_NAME);
|
|
599
|
+
|
|
600
|
+
useEffect(() => {
|
|
601
|
+
const loadPoster = async () => {
|
|
602
|
+
if (poster?.content?.source) {
|
|
603
|
+
try {
|
|
604
|
+
const response = await client.files.getDownloadUrl(poster.content.source);
|
|
605
|
+
setPosterUrl(response.url);
|
|
606
|
+
} catch (error) {
|
|
607
|
+
console.error("Failed to load poster image", error);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
loadPoster();
|
|
612
|
+
}, [poster, client]);
|
|
613
|
+
|
|
614
|
+
useEffect(() => {
|
|
615
|
+
if (isVideo && (webRendition?.content?.source || isOriginalWebSupported)) {
|
|
616
|
+
const loadVideoUrl = async () => {
|
|
617
|
+
try {
|
|
618
|
+
let downloadUrl;
|
|
619
|
+
if (webRendition?.content?.source) {
|
|
620
|
+
// Use rendition if available
|
|
621
|
+
downloadUrl = await client.files.getDownloadUrl(webRendition.content.source);
|
|
622
|
+
} else if (isOriginalWebSupported && content?.source) {
|
|
623
|
+
// Fall back to original file if web-supported
|
|
624
|
+
downloadUrl = await client.files.getDownloadUrl(content.source);
|
|
625
|
+
}
|
|
626
|
+
if (downloadUrl) {
|
|
627
|
+
setVideoUrl(downloadUrl.url);
|
|
628
|
+
}
|
|
629
|
+
} catch (error) {
|
|
630
|
+
console.error("Failed to get video URL", error);
|
|
631
|
+
} finally {
|
|
632
|
+
setIsLoading(false);
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
loadVideoUrl();
|
|
636
|
+
} else {
|
|
637
|
+
setIsLoading(false);
|
|
638
|
+
}
|
|
639
|
+
}, [isVideo, webRendition, isOriginalWebSupported, content?.source, client]);
|
|
640
|
+
|
|
641
|
+
return (
|
|
642
|
+
<div className="mb-4 px-2">
|
|
643
|
+
{!webRendition && !isOriginalWebSupported ? (
|
|
644
|
+
<div className="flex justify-center items-center h-[400px] text-muted">
|
|
645
|
+
<div className="text-center">
|
|
646
|
+
<p>No web-compatible video rendition available</p>
|
|
647
|
+
<p className="text-sm mt-2">MP4 or WebM format required</p>
|
|
648
|
+
</div>
|
|
649
|
+
</div>
|
|
650
|
+
) : isLoading ? (
|
|
651
|
+
<div className="flex justify-center items-center h-[400px]">
|
|
652
|
+
<Spinner size="md" />
|
|
653
|
+
</div>
|
|
654
|
+
) : videoUrl ? (
|
|
655
|
+
<video
|
|
656
|
+
src={videoUrl}
|
|
657
|
+
poster={posterUrl}
|
|
658
|
+
controls
|
|
659
|
+
className="w-full max-h-[calc(100vh-260px)] object-contain"
|
|
660
|
+
>
|
|
661
|
+
Your browser does not support the video tag.
|
|
662
|
+
</video>
|
|
663
|
+
) : (
|
|
664
|
+
<div className="flex justify-center items-center h-[400px] text-muted">
|
|
665
|
+
Failed to load video
|
|
666
|
+
</div>
|
|
667
|
+
)}
|
|
668
|
+
</div>
|
|
669
|
+
);
|
|
670
|
+
}
|