@vertesia/ui 0.78.0 → 0.79.0
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/SelectList.js +18 -13
- package/lib/esm/core/components/SelectList.js.map +1 -1
- package/lib/esm/core/components/SidePanel.js +1 -1
- package/lib/esm/core/components/SidePanel.js.map +1 -1
- package/lib/esm/core/components/shadcn/filters/filterBar.js +39 -12
- package/lib/esm/core/components/shadcn/filters/filterBar.js.map +1 -1
- package/lib/esm/core/components/shadcn/index.js +1 -0
- package/lib/esm/core/components/shadcn/index.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/tabs.js +11 -6
- package/lib/esm/core/components/shadcn/tabs.js.map +1 -1
- package/lib/esm/core/components/table/index.js +1 -1
- package/lib/esm/core/components/table/index.js.map +1 -1
- package/lib/esm/features/facets/CollectionsFacetsNav.js +66 -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 +82 -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} +5 -3
- 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/store/collections/EditCollectionView.js +14 -1
- package/lib/esm/features/store/collections/EditCollectionView.js.map +1 -1
- package/lib/esm/features/store/collections/SelectCollection.js +47 -18
- package/lib/esm/features/store/collections/SelectCollection.js.map +1 -1
- package/lib/esm/features/store/objects/DocumentSearchResults.js +9 -5
- package/lib/esm/features/store/objects/DocumentSearchResults.js.map +1 -1
- package/lib/esm/features/store/objects/components/ContentOverview.js +172 -78
- package/lib/esm/features/store/objects/components/ContentOverview.js.map +1 -1
- package/lib/esm/features/store/objects/components/DocumentIcon.js +6 -0
- package/lib/esm/features/store/objects/components/DocumentIcon.js.map +1 -1
- package/lib/esm/features/store/objects/layout/documentLayout.js +3 -4
- package/lib/esm/features/store/objects/layout/documentLayout.js.map +1 -1
- package/lib/esm/features/store/objects/selection/actions/AddToCollectionAction.js +2 -2
- package/lib/esm/features/store/objects/selection/actions/AddToCollectionAction.js.map +1 -1
- package/lib/esm/features/store/objects/upload/DocumentUploadModal.js +1 -1
- package/lib/esm/features/store/objects/upload/DocumentUploadModal.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 +33 -1
- package/lib/esm/features/user/UserInfo.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/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/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/shadcn/filters/filterBar.d.ts.map +1 -1
- package/lib/types/core/components/shadcn/index.d.ts +1 -0
- package/lib/types/core/components/shadcn/index.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/tabs.d.ts +2 -1
- package/lib/types/core/components/shadcn/tabs.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 +13 -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/{VFacetsNav.d.ts → utils/SearchInterface.d.ts} +1 -8
- 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/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/store/collections/EditCollectionView.d.ts.map +1 -1
- package/lib/types/features/store/collections/SelectCollection.d.ts +10 -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/components/ContentOverview.d.ts.map +1 -1
- package/lib/types/features/store/objects/components/DocumentIcon.d.ts +4 -0
- package/lib/types/features/store/objects/components/DocumentIcon.d.ts.map +1 -1
- package/lib/types/features/store/objects/layout/documentLayout.d.ts.map +1 -1
- package/lib/types/features/store/objects/search/DocumentSearchContext.d.ts +1 -3
- package/lib/types/features/store/objects/search/DocumentSearchContext.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/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-features.js +1 -1
- package/lib/vertesia-ui-features.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 +5 -4
- package/src/core/components/SelectList.tsx +11 -1
- package/src/core/components/SidePanel.tsx +13 -10
- package/src/core/components/shadcn/filters/filterBar.tsx +46 -20
- package/src/core/components/shadcn/index.ts +1 -0
- package/src/core/components/shadcn/resizeable.tsx +54 -0
- package/src/core/components/shadcn/tabs.tsx +16 -6
- package/src/core/components/table/index.tsx +1 -1
- package/src/features/facets/CollectionsFacetsNav.tsx +94 -0
- package/src/features/facets/DocumentsFacetsNav.tsx +22 -11
- package/src/features/facets/EnvironmentFacet.tsx +1 -1
- package/src/features/facets/InteractionsFacetsNav.tsx +111 -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 +8 -0
- package/src/features/facets/{VTypeFacet.tsx → utils/VTypeFacet.tsx} +6 -3
- package/src/features/facets/{VUserFacet.tsx → utils/VUserFacet.tsx} +1 -1
- package/src/features/store/collections/EditCollectionView.tsx +14 -1
- package/src/features/store/collections/SelectCollection.tsx +160 -31
- package/src/features/store/objects/DocumentSearchResults.tsx +42 -37
- package/src/features/store/objects/components/ContentOverview.tsx +432 -261
- package/src/features/store/objects/components/DocumentIcon.tsx +31 -1
- package/src/features/store/objects/layout/documentLayout.tsx +3 -7
- package/src/features/store/objects/selection/actions/AddToCollectionAction.tsx +15 -8
- package/src/features/store/objects/upload/DocumentUploadModal.tsx +5 -6
- package/src/features/store/types/ObjectSchemaEditor.tsx +1 -1
- package/src/features/user/UserInfo.tsx +66 -3
- package/src/shell/login/UserInfo.tsx +1 -1
- package/src/widgets/schema-editor/index.ts +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/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.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/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/{VTypeFacet.d.ts → utils/VTypeFacet.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,7 +1,7 @@
|
|
|
1
1
|
import { useEffect, useState } 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
6
|
import { ContentObject, ImageRenditionFormat } from "@vertesia/common";
|
|
7
7
|
import { Copy, Download, SquarePen } from "lucide-react";
|
|
@@ -18,15 +18,51 @@ export function ContentOverview({
|
|
|
18
18
|
loadText,
|
|
19
19
|
refetch,
|
|
20
20
|
}: 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
21
|
const toast = useToast();
|
|
22
|
+
|
|
23
|
+
const handleCopyContent = async (
|
|
24
|
+
content: string,
|
|
25
|
+
type: "text" | "properties",
|
|
26
|
+
) => {
|
|
27
|
+
try {
|
|
28
|
+
await navigator.clipboard.writeText(content);
|
|
29
|
+
toast({
|
|
30
|
+
status: "success",
|
|
31
|
+
title: `${type === "text" ? "Content" : "Properties"} copied`,
|
|
32
|
+
description: `Successfully copied ${type} to clipboard`,
|
|
33
|
+
duration: 2000,
|
|
34
|
+
});
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.error(`Failed to copy ${type}:`, err);
|
|
37
|
+
toast({
|
|
38
|
+
status: "error",
|
|
39
|
+
title: "Copy failed",
|
|
40
|
+
description: `Failed to copy ${type} to clipboard`,
|
|
41
|
+
duration: 5000,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<>
|
|
48
|
+
<ResizablePanelGroup direction="horizontal" className="h-[calc(100vh-200px)]">
|
|
49
|
+
<ResizablePanel className="min-w-[100px]">
|
|
50
|
+
<PropertiesPanel object={object} refetch={refetch ?? (() => Promise.resolve())} handleCopyContent={handleCopyContent} />
|
|
51
|
+
</ResizablePanel>
|
|
52
|
+
<ResizableHandle withHandle />
|
|
53
|
+
|
|
54
|
+
<ResizablePanel className="min-w-[100px]">
|
|
55
|
+
<DataPanel object={object} loadText={loadText ?? false} handleCopyContent={handleCopyContent} />
|
|
56
|
+
</ResizablePanel>
|
|
57
|
+
</ResizablePanelGroup>
|
|
58
|
+
|
|
59
|
+
</>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function PropertiesPanel({ object, refetch, handleCopyContent }: { object: ContentObject, refetch: () => Promise<unknown>, handleCopyContent: (content: string, type: "text" | "properties") => Promise<void> }) {
|
|
27
64
|
const [viewCode, setViewCode] = useState(false);
|
|
28
|
-
const
|
|
29
|
-
const VIEW_TEXT = "Preview";
|
|
65
|
+
const [isPropertiesModalOpen, setPropertiesModalOpen] = useState(false);
|
|
30
66
|
|
|
31
67
|
const handleOpenPropertiesModal = () => {
|
|
32
68
|
setPropertiesModalOpen(true);
|
|
@@ -36,6 +72,98 @@ export function ContentOverview({
|
|
|
36
72
|
setPropertiesModalOpen(false);
|
|
37
73
|
};
|
|
38
74
|
|
|
75
|
+
return (
|
|
76
|
+
<>
|
|
77
|
+
<div className="flex justify-between items-center px-2">
|
|
78
|
+
<div className="flex items-center gap-1 bg-muted mb-2 p-1 rounded">
|
|
79
|
+
<Button
|
|
80
|
+
variant={`${viewCode ? "ghost" : "primary"}`}
|
|
81
|
+
size="sm"
|
|
82
|
+
alt="Preview properties"
|
|
83
|
+
onClick={() => setViewCode(!viewCode)}
|
|
84
|
+
>
|
|
85
|
+
Properties
|
|
86
|
+
</Button>
|
|
87
|
+
<Button
|
|
88
|
+
variant={`${viewCode ? "primary" : "ghost"}`}
|
|
89
|
+
size="sm"
|
|
90
|
+
alt="View in JSON format"
|
|
91
|
+
onClick={() => setViewCode(!viewCode)}
|
|
92
|
+
>
|
|
93
|
+
JSON
|
|
94
|
+
</Button>
|
|
95
|
+
</div>
|
|
96
|
+
<div className="flex items-center gap-2">
|
|
97
|
+
{object.properties && (
|
|
98
|
+
<Button
|
|
99
|
+
variant="ghost"
|
|
100
|
+
size="sm"
|
|
101
|
+
title="Copy properties"
|
|
102
|
+
onClick={() =>
|
|
103
|
+
handleCopyContent(
|
|
104
|
+
JSON.stringify(
|
|
105
|
+
object.properties,
|
|
106
|
+
null,
|
|
107
|
+
2,
|
|
108
|
+
),
|
|
109
|
+
"properties",
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
>
|
|
113
|
+
<Copy className="size-4" />
|
|
114
|
+
</Button>
|
|
115
|
+
)}
|
|
116
|
+
<Button
|
|
117
|
+
variant="ghost"
|
|
118
|
+
size="sm"
|
|
119
|
+
onClick={handleOpenPropertiesModal}
|
|
120
|
+
title="Edit properties"
|
|
121
|
+
className="flex items-center gap-2"
|
|
122
|
+
>
|
|
123
|
+
<SquarePen className="size-4" />
|
|
124
|
+
</Button>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
{
|
|
129
|
+
object.properties ? (
|
|
130
|
+
<div className="h-[calc(100vh-220px)] overflow-auto px-2">
|
|
131
|
+
<JSONDisplay
|
|
132
|
+
value={object.properties}
|
|
133
|
+
viewCode={viewCode}
|
|
134
|
+
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
) : (
|
|
138
|
+
<div className="h-[calc(100vh-220px)] overflow-auto px-2">
|
|
139
|
+
<div>No properties defined</div>
|
|
140
|
+
</div>
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
{/* Properties Editor Modal */}
|
|
144
|
+
<PropertiesEditorModal
|
|
145
|
+
isOpen={isPropertiesModalOpen}
|
|
146
|
+
onClose={handleClosePropertiesModal}
|
|
147
|
+
object={object}
|
|
148
|
+
refetch={refetch}
|
|
149
|
+
/>
|
|
150
|
+
</>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function DataPanel({ object, loadText, handleCopyContent }: { object: ContentObject, loadText: boolean, handleCopyContent: (content: string, type: "text" | "properties") => Promise<void> }) {
|
|
155
|
+
const { store } = useUserSession();
|
|
156
|
+
|
|
157
|
+
const content = object.content;
|
|
158
|
+
const isImage =
|
|
159
|
+
content && content.type && content.type.startsWith("image/");
|
|
160
|
+
|
|
161
|
+
const [viewImage, setViewImage] = useState(isImage);
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
const [text, setText] = useState<string | undefined>(object.text);
|
|
165
|
+
const [isLoadingText, setIsLoadingText] = useState<boolean>(false);
|
|
166
|
+
|
|
39
167
|
useEffect(() => {
|
|
40
168
|
if (loadText && !text) {
|
|
41
169
|
setIsLoadingText(true);
|
|
@@ -53,28 +181,68 @@ export function ContentOverview({
|
|
|
53
181
|
}
|
|
54
182
|
}, [loadText]);
|
|
55
183
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
184
|
+
return (
|
|
185
|
+
<>
|
|
186
|
+
<div className="flex justify-between items-center px-2">
|
|
187
|
+
<div className="flex items-center gap-1 bg-muted mb-2 p-1 rounded">
|
|
188
|
+
{isImage &&
|
|
189
|
+
<Button
|
|
190
|
+
variant={`${viewImage ? "primary" : "ghost"}`}
|
|
191
|
+
size="sm"
|
|
192
|
+
alt="View Image"
|
|
193
|
+
onClick={() => setViewImage(true)}
|
|
194
|
+
>
|
|
195
|
+
Image
|
|
196
|
+
</Button>
|
|
197
|
+
}
|
|
198
|
+
<Button
|
|
199
|
+
variant={`${viewImage ? "ghost" : "primary"}`}
|
|
200
|
+
size="sm"
|
|
201
|
+
alt="View Text"
|
|
202
|
+
onClick={() => setViewImage(false)}
|
|
203
|
+
>
|
|
204
|
+
Text
|
|
205
|
+
</Button>
|
|
206
|
+
|
|
207
|
+
</div>
|
|
208
|
+
{!viewImage && <TextActions object={object} text={text} handleCopyContent={handleCopyContent} />}
|
|
209
|
+
</div>
|
|
210
|
+
{
|
|
211
|
+
viewImage ? (
|
|
212
|
+
<ImagePanel object={object} />
|
|
213
|
+
) : (
|
|
214
|
+
isLoadingText ? (
|
|
215
|
+
<div className="flex justify-center items-center h-[calc(100vh-260px)]">
|
|
216
|
+
<Spinner size="lg" />
|
|
217
|
+
</div>
|
|
218
|
+
) : (
|
|
219
|
+
<TextPanel object={object} text={text} />
|
|
220
|
+
)
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
</>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function TextActions({ object, text, handleCopyContent }: { object: ContentObject, handleCopyContent: (content: string, type: "text" | "properties") => Promise<void>, text: string | undefined }) {
|
|
228
|
+
const { client } = useUserSession();
|
|
229
|
+
const toast = useToast();
|
|
230
|
+
|
|
231
|
+
const content = object.content;
|
|
232
|
+
|
|
233
|
+
const isMarkdownOrText =
|
|
234
|
+
content &&
|
|
235
|
+
content.type &&
|
|
236
|
+
(content.type === "text/markdown" || content.type === "text/plain");
|
|
237
|
+
|
|
238
|
+
// Check for markdown indicators, ignoring any HTML comments
|
|
239
|
+
const seemsMarkdown =
|
|
240
|
+
text &&
|
|
241
|
+
// Look for markdown indicators
|
|
242
|
+
(text.includes("\n#") ||
|
|
243
|
+
text.includes("\n*") ||
|
|
244
|
+
text.includes("\n+") ||
|
|
245
|
+
text.includes("!["));
|
|
78
246
|
|
|
79
247
|
const handleExportDocument = async (format: "docx" | "pdf") => {
|
|
80
248
|
try {
|
|
@@ -145,17 +313,45 @@ export function ContentOverview({
|
|
|
145
313
|
|
|
146
314
|
const handleExportDocx = () => handleExportDocument("docx");
|
|
147
315
|
const handleExportPdf = () => handleExportDocument("pdf");
|
|
316
|
+
return (
|
|
317
|
+
<div className="h-[41px] text-lg font-semibold flex justify-between items-center px-2">
|
|
318
|
+
<div className="flex items-center gap-2">
|
|
319
|
+
{text && (
|
|
320
|
+
<Button variant="ghost" size="sm" title="Copy text" className="flex items-center gap-2" onClick={() => handleCopyContent(text, "text")}>
|
|
321
|
+
<Copy className="size-4" />
|
|
322
|
+
</Button>
|
|
323
|
+
)}
|
|
324
|
+
{(isMarkdownOrText || seemsMarkdown) && text && (
|
|
325
|
+
<>
|
|
326
|
+
<Button
|
|
327
|
+
variant="ghost"
|
|
328
|
+
size="sm"
|
|
329
|
+
onClick={handleExportDocx}
|
|
330
|
+
className="flex items-center gap-2"
|
|
331
|
+
>
|
|
332
|
+
<Download className="size-4" />
|
|
333
|
+
DOCX
|
|
334
|
+
</Button>
|
|
335
|
+
<Button
|
|
336
|
+
variant="ghost"
|
|
337
|
+
size="sm"
|
|
338
|
+
onClick={handleExportPdf}
|
|
339
|
+
className="flex items-center gap-2"
|
|
340
|
+
>
|
|
341
|
+
<Download className="size-4" />
|
|
342
|
+
PDF
|
|
343
|
+
</Button>
|
|
344
|
+
</>
|
|
345
|
+
)}
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function TextPanel({ object, text }: { object: ContentObject, text: string | undefined }) {
|
|
352
|
+
const toast = useToast();
|
|
353
|
+
const { client } = useUserSession();
|
|
148
354
|
|
|
149
|
-
const content = object.content;
|
|
150
|
-
const isImage =
|
|
151
|
-
content &&
|
|
152
|
-
content.source &&
|
|
153
|
-
content.type &&
|
|
154
|
-
content.type.startsWith("image/");
|
|
155
|
-
const isMarkdownOrText =
|
|
156
|
-
content &&
|
|
157
|
-
content.type &&
|
|
158
|
-
(content.type === "text/markdown" || content.type === "text/plain");
|
|
159
355
|
// Check for markdown indicators, ignoring any HTML comments
|
|
160
356
|
const seemsMarkdown =
|
|
161
357
|
text &&
|
|
@@ -165,237 +361,212 @@ export function ContentOverview({
|
|
|
165
361
|
text.includes("\n+") ||
|
|
166
362
|
text.includes("!["));
|
|
167
363
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
});
|
|
364
|
+
const handleExportDocument = async (format: "docx" | "pdf") => {
|
|
365
|
+
try {
|
|
366
|
+
// Request document rendition from the server
|
|
367
|
+
const response = await client.objects.getRendition(object.id, {
|
|
368
|
+
format: format as any, // We're extending the format type
|
|
369
|
+
generate_if_missing: true,
|
|
370
|
+
sign_url: true,
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
if (response.status === "generating") {
|
|
374
|
+
toast({
|
|
375
|
+
status: "info",
|
|
376
|
+
title: "Generating document",
|
|
377
|
+
description: `Please wait while we prepare your ${format.toUpperCase()} file...`,
|
|
378
|
+
duration: 5000,
|
|
192
379
|
});
|
|
380
|
+
|
|
381
|
+
// Poll for completion
|
|
382
|
+
setTimeout(() => handleExportDocument(format), 3000);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (response.status === "failed") {
|
|
387
|
+
throw new Error("Document generation failed");
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Download the generated file or open in new window
|
|
391
|
+
if (response.renditions && response.renditions.length > 0) {
|
|
392
|
+
const downloadUrl = response.renditions[0];
|
|
393
|
+
|
|
394
|
+
if (format === 'pdf') {
|
|
395
|
+
// Open PDF in new window
|
|
396
|
+
window.open(downloadUrl, '_blank');
|
|
397
|
+
toast({
|
|
398
|
+
status: "success",
|
|
399
|
+
title: "PDF opened",
|
|
400
|
+
description: "PDF document opened in a new window",
|
|
401
|
+
duration: 2000,
|
|
402
|
+
});
|
|
403
|
+
} else {
|
|
404
|
+
// Download DOCX file
|
|
405
|
+
const link = document.createElement("a");
|
|
406
|
+
link.href = downloadUrl;
|
|
407
|
+
link.download = `${object.name || "document"}.${format}`;
|
|
408
|
+
document.body.appendChild(link);
|
|
409
|
+
link.click();
|
|
410
|
+
document.body.removeChild(link);
|
|
411
|
+
|
|
412
|
+
toast({
|
|
413
|
+
status: "success",
|
|
414
|
+
title: "Document exported",
|
|
415
|
+
description: `Successfully exported to ${format.toUpperCase()} format`,
|
|
416
|
+
duration: 2000,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
} catch (err) {
|
|
421
|
+
console.error(`Failed to export document as ${format}:`, err);
|
|
422
|
+
toast({
|
|
423
|
+
status: "error",
|
|
424
|
+
title: "Export failed",
|
|
425
|
+
description: `Failed to export document to ${format.toUpperCase()} format`,
|
|
426
|
+
duration: 5000,
|
|
427
|
+
});
|
|
193
428
|
}
|
|
194
|
-
}
|
|
429
|
+
};
|
|
195
430
|
|
|
196
431
|
return (
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
<div className="w-
|
|
200
|
-
|
|
201
|
-
<div className="
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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>
|
|
268
|
-
|
|
269
|
-
<div className="w-full lg:w-1/2 mt-4 lg:mt-0">
|
|
270
|
-
<div className="h-[41px] text-lg font-semibold mb-4 border-b flex justify-between items-center">
|
|
271
|
-
<span className="py-1">Text</span>
|
|
272
|
-
<div className="flex items-center gap-2">
|
|
273
|
-
{text && (
|
|
274
|
-
<Button
|
|
275
|
-
variant="ghost"
|
|
276
|
-
size="sm"
|
|
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
|
-
)}
|
|
308
|
-
</div>
|
|
309
|
-
</div>
|
|
310
|
-
{isLoadingText && <Spinner size="md" />}
|
|
311
|
-
{text ? (
|
|
312
|
-
<div className="border shadow-xs rounded-xs max-w-7xl">
|
|
313
|
-
{seemsMarkdown ? (
|
|
314
|
-
<div className="vprose prose-sm p-1">
|
|
315
|
-
<MarkdownRenderer
|
|
316
|
-
components={{
|
|
317
|
-
a: ({ node, ...props }: { node?: any; href?: string; children?: React.ReactNode }) => {
|
|
318
|
-
const href = props.href || "";
|
|
319
|
-
if (href.includes("/store/objects/")) {
|
|
320
|
-
return (
|
|
321
|
-
<NavLink
|
|
322
|
-
topLevelNav
|
|
323
|
-
href={href}
|
|
324
|
-
className="text-info"
|
|
325
|
-
>
|
|
326
|
-
{props.children}
|
|
327
|
-
</NavLink>
|
|
328
|
-
);
|
|
432
|
+
text ? (
|
|
433
|
+
<>
|
|
434
|
+
<div className="max-w-7xl px-2 h-[calc(100vh-210px)] overflow-auto">
|
|
435
|
+
{seemsMarkdown ? (
|
|
436
|
+
<div className="vprose prose-sm p-1">
|
|
437
|
+
<MarkdownRenderer
|
|
438
|
+
components={{
|
|
439
|
+
a: ({ node, ...props }: { node?: any; href?: string; children?: React.ReactNode }) => {
|
|
440
|
+
const href = props.href || "";
|
|
441
|
+
if (href.includes("/store/objects/")) {
|
|
442
|
+
return (
|
|
443
|
+
<NavLink
|
|
444
|
+
topLevelNav
|
|
445
|
+
href={href}
|
|
446
|
+
className="text-info"
|
|
447
|
+
>
|
|
448
|
+
{props.children}
|
|
449
|
+
</NavLink>
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
return <a {...props} data-debug="test" target="_blank" rel="noopener noreferrer" />;
|
|
453
|
+
},
|
|
454
|
+
p: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
455
|
+
<p {...props} className={`my-0`} />
|
|
456
|
+
),
|
|
457
|
+
pre: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
458
|
+
<pre {...props} className={`my-2 p-2 rounded`} />
|
|
459
|
+
),
|
|
460
|
+
code: ({
|
|
461
|
+
node,
|
|
462
|
+
className,
|
|
463
|
+
children,
|
|
464
|
+
...props
|
|
465
|
+
}: {
|
|
466
|
+
node?: any;
|
|
467
|
+
className?: string;
|
|
468
|
+
children?: React.ReactNode;
|
|
469
|
+
}) => {
|
|
470
|
+
const match = /language-(\w+)/.exec(className || "");
|
|
471
|
+
const isInline = !match;
|
|
472
|
+
return (
|
|
473
|
+
<code
|
|
474
|
+
{...props}
|
|
475
|
+
className={
|
|
476
|
+
isInline
|
|
477
|
+
? `px-1.5 py-0.5 rounded`
|
|
478
|
+
: "text-muted"
|
|
329
479
|
}
|
|
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
|
-
)}
|
|
480
|
+
>
|
|
481
|
+
{children}
|
|
482
|
+
</code>
|
|
483
|
+
);
|
|
484
|
+
},
|
|
485
|
+
h1: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
486
|
+
<h1 {...props} className={`font-bold text-2xl my-2`} />
|
|
487
|
+
),
|
|
488
|
+
h2: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
489
|
+
<h2 {...props} className={`font-bold text-xl my-2`} />
|
|
490
|
+
),
|
|
491
|
+
h3: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
492
|
+
<h3 {...props} className={`font-bold text-lg my-2`} />
|
|
493
|
+
),
|
|
494
|
+
li: ({ node, ...props }: { node?: any; children?: React.ReactNode }) => (
|
|
495
|
+
<li {...props} />
|
|
496
|
+
),
|
|
497
|
+
}}
|
|
498
|
+
>
|
|
499
|
+
{text}
|
|
500
|
+
</MarkdownRenderer>
|
|
385
501
|
</div>
|
|
386
502
|
) : (
|
|
387
|
-
<
|
|
503
|
+
<pre className="text-wrap bg-muted text-muted p-2">
|
|
504
|
+
{text}
|
|
505
|
+
</pre>
|
|
388
506
|
)}
|
|
389
507
|
</div>
|
|
508
|
+
</>
|
|
509
|
+
) :
|
|
510
|
+
<div className="px-2">
|
|
511
|
+
<div>No content</div>
|
|
390
512
|
</div>
|
|
513
|
+
);
|
|
514
|
+
}
|
|
391
515
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
516
|
+
function ImagePanel({ object }: { object: ContentObject }) {
|
|
517
|
+
const { client } = useUserSession();
|
|
518
|
+
const [imageUrl, setImageUrl] = useState<string>();
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
const content = object.content;
|
|
522
|
+
const isImage =
|
|
523
|
+
content && content.type && content.type.startsWith("image/");
|
|
524
|
+
|
|
525
|
+
useEffect(() => {
|
|
526
|
+
if (isImage) {
|
|
527
|
+
const loadImage = async () => {
|
|
528
|
+
const webSupportedFormats = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml'];
|
|
529
|
+
const isOriginalWebSupported = content?.type && webSupportedFormats.includes(content.type);
|
|
530
|
+
|
|
531
|
+
try {
|
|
532
|
+
const rendition = await client.objects.getRendition(object.id, {
|
|
533
|
+
format: ImageRenditionFormat.jpeg,
|
|
534
|
+
generate_if_missing: false,
|
|
535
|
+
sign_url: true,
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
if (rendition.status === "found" && rendition.renditions?.length) {
|
|
539
|
+
// Use rendition URL directly
|
|
540
|
+
setImageUrl(rendition.renditions[0]);
|
|
541
|
+
} else if (isOriginalWebSupported) {
|
|
542
|
+
// Fall back to original file only if web-supported
|
|
543
|
+
const downloadUrl = await client.files.getDownloadUrl(object.content.source!);
|
|
544
|
+
setImageUrl(downloadUrl.url);
|
|
545
|
+
}
|
|
546
|
+
} catch (error) {
|
|
547
|
+
// Fall back to original file only if web-supported
|
|
548
|
+
if (isOriginalWebSupported) {
|
|
549
|
+
const downloadUrl = await client.files.getDownloadUrl(object.content.source!);
|
|
550
|
+
setImageUrl(downloadUrl.url);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
loadImage();
|
|
556
|
+
}
|
|
557
|
+
}, []);
|
|
558
|
+
|
|
559
|
+
return (
|
|
560
|
+
<div className="mb-4 px-2">
|
|
561
|
+
{imageUrl ? (
|
|
562
|
+
<img
|
|
563
|
+
src={imageUrl}
|
|
564
|
+
alt={object.name}
|
|
565
|
+
className="w-full object-contain"
|
|
566
|
+
/>
|
|
567
|
+
) : (
|
|
568
|
+
<Spinner size="md" />
|
|
569
|
+
)}
|
|
399
570
|
</div>
|
|
400
571
|
);
|
|
401
|
-
}
|
|
572
|
+
}
|