@cccsaurora/clue-ui 1.2.0-dev.171 → 1.2.0-dev.175

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.
@@ -15,8 +15,8 @@ import { u as useContextSelector, c as createContext, a as useContext } from "./
15
15
  import ErrorBoundary from "./components/ErrorBoundary.js";
16
16
  import { adaptSchema } from "./components/actions/form/schemaAdapter.js";
17
17
  import { I as Icon } from "./iconify-CXMreGTg.js";
18
- import Markdown from "./components/display/markdown/index.js";
19
18
  import ClassificationChip from "./components/ClassificationChip.js";
19
+ import Result from "./components/actions/formats/index.js";
20
20
  import { SNACKBAR_EVENT_ID } from "./data/event.js";
21
21
  import { dayjs } from "./utils/time.js";
22
22
  import { safeDispatchEvent } from "./utils/window.js";
@@ -115,10 +115,7 @@ const ResultModal = ({ result: _result, onClose, show = false }) => {
115
115
  ] }),
116
116
  /* @__PURE__ */ jsx(Typography, { variant: "body1", children: result.action.summary }),
117
117
  /* @__PURE__ */ jsx(Divider, { flexItem: true }),
118
- resultFinished ? /* @__PURE__ */ jsx(ErrorBoundary, { children: result.format === "markdown" ? /* @__PURE__ */ jsx(Markdown, { md: result.output }) : result.format === "json" ? /* @__PURE__ */ jsx(JSONViewer, { data: result.output, collapse: true, forceCompact: true }) : /* @__PURE__ */ jsxs(Stack, { sx: { overflowY: "auto" }, children: [
119
- /* @__PURE__ */ jsx(Markdown, { md: "`" + result.format + "` is not recognized as a format in this application." }),
120
- /* @__PURE__ */ jsx(JSONViewer, { data: result, collapse: true, forceCompact: true })
121
- ] }) }) : /* @__PURE__ */ jsxs(Stack, { flex: 1, sx: { pt: 2, alignItems: "center" }, spacing: 1, children: [
118
+ resultFinished ? /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(Result, { result }) }) : /* @__PURE__ */ jsxs(Stack, { flex: 1, sx: { pt: 2, alignItems: "center" }, spacing: 1, children: [
122
119
  result.summary && /* @__PURE__ */ jsx(Typography, { variant: "caption", children: result.summary }),
123
120
  /* @__PURE__ */ jsx(
124
121
  LinearProgress,
@@ -186,7 +183,6 @@ const ClueActionProvider = ({
186
183
  async (actionId, selectors, params, options) => {
187
184
  const { forceMenu, onComplete, skipMenu, skipResultModal, timeout, includeContext, extraContext } = {
188
185
  forceMenu: false,
189
- skipResultModal: false,
190
186
  skipMenu: false,
191
187
  onComplete: null,
192
188
  timeout: null,
@@ -239,7 +235,6 @@ const ClueActionProvider = ({
239
235
  action: actionToRun,
240
236
  selectors,
241
237
  params: validatedParams ?? {},
242
- skipResultModal,
243
238
  context: context2,
244
239
  onComplete,
245
240
  timeout
@@ -430,9 +425,6 @@ const ActionForm = ({ runningActionData }) => {
430
425
  if (runningActionData == null ? void 0 : runningActionData.timeout) {
431
426
  options.timeout = runningActionData == null ? void 0 : runningActionData.timeout;
432
427
  }
433
- if (runningActionData == null ? void 0 : runningActionData.skipResultModal) {
434
- options.skipResultModal = runningActionData == null ? void 0 : runningActionData.skipResultModal;
435
- }
436
428
  await executeAction(runningActionData == null ? void 0 : runningActionData.id, runningActionData == null ? void 0 : runningActionData.selectors, formData, options);
437
429
  } catch (e) {
438
430
  console.error(e);
@@ -5,7 +5,7 @@ import "@mui/material";
5
5
  import "../display/icons/Iconified.js";
6
6
  import "../../index-Bmoj6JY8.js";
7
7
  import "../../hooks/ClueComponentContext.js";
8
- import { A } from "../../ActionForm-wVwVYO-b.js";
8
+ import { A } from "../../ActionForm-Hg3A_2XX.js";
9
9
  import "../../utils-CW9CNV1h.js";
10
10
  import "react";
11
11
  import "../../index-BDVjGvMI.js";
@@ -1,14 +1,13 @@
1
1
  import "react/jsx-runtime";
2
2
  import "../../iconify-CXMreGTg.js";
3
3
  import "@mui/material";
4
- import "../../index-Bmoj6JY8.js";
5
- import "../display/markdown/index.js";
6
4
  import "../../hooks/ClueComponentContext.js";
7
- import { R } from "../../ActionForm-wVwVYO-b.js";
5
+ import { R } from "../../ActionForm-Hg3A_2XX.js";
8
6
  import "react";
9
7
  import "../../index-BDVjGvMI.js";
10
8
  import "../ClassificationChip.js";
11
9
  import "../ErrorBoundary.js";
10
+ import "./formats/index.js";
12
11
  export {
13
12
  R as default
14
13
  };
@@ -0,0 +1,16 @@
1
+ import { ActionResult } from "../../../types/action";
2
+ import { WithActionData } from "../../../types/WithActionData";
3
+ import { FC } from 'react';
4
+
5
+ export interface ActionFileResult {
6
+ data: string;
7
+ mime_type: string;
8
+ file_name: string;
9
+ }
10
+ /**
11
+ * Render a file action result with metadata, hash statistics, and download support.
12
+ */
13
+ declare const FileResult: FC<{
14
+ result: WithActionData<ActionResult<ActionFileResult>>;
15
+ }>;
16
+ export default FileResult;
@@ -0,0 +1,112 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { Stack, Typography, Divider, Table, TableBody, TableRow, TableCell, Button } from "@mui/material";
3
+ import Iconified from "../../display/icons/Iconified.js";
4
+ import { ClueComponentContext } from "../../../hooks/ClueComponentContext.js";
5
+ import { useState, useMemo, useEffect } from "react";
6
+ import { u as useContextSelector } from "../../../index-BDVjGvMI.js";
7
+ const decodeBase64ToBytes = (base64Data) => {
8
+ const byteCharacters = atob(base64Data);
9
+ const byteArray = new Uint8Array(new ArrayBuffer(byteCharacters.length));
10
+ for (let i = 0; i < byteCharacters.length; i++) {
11
+ byteArray[i] = byteCharacters.charCodeAt(i);
12
+ }
13
+ return byteArray;
14
+ };
15
+ const formatBytes = (bytes) => {
16
+ if (bytes === 0) {
17
+ return "0 B";
18
+ }
19
+ const units = ["B", "KB", "MB", "GB"];
20
+ const unitIndex = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
21
+ const value = bytes / 1024 ** unitIndex;
22
+ return `${value.toFixed(unitIndex === 0 ? 0 : 2)} ${units[unitIndex]}`;
23
+ };
24
+ const saveFileFromServer = (output) => {
25
+ const byteArray = decodeBase64ToBytes(output.data);
26
+ const blob = new Blob([byteArray], { type: output.mime_type || "application/octet-stream" });
27
+ const url = URL.createObjectURL(blob);
28
+ const link = document.createElement("a");
29
+ link.href = url;
30
+ link.download = output.file_name || "result.txt";
31
+ document.body.appendChild(link);
32
+ link.click();
33
+ document.body.removeChild(link);
34
+ URL.revokeObjectURL(url);
35
+ };
36
+ const FileResult = ({ result }) => {
37
+ var _a, _b, _c, _d, _e;
38
+ const { t } = useContextSelector(ClueComponentContext, (ctx) => ctx == null ? void 0 : ctx.i18next);
39
+ const [sha256Hash, setSha256Hash] = useState("");
40
+ const actionName = ((_a = result.action) == null ? void 0 : _a.name) ?? t("actions.result.file.unknown");
41
+ const outputBytes = useMemo(() => {
42
+ var _a2;
43
+ if (!((_a2 = result.output) == null ? void 0 : _a2.data)) {
44
+ return null;
45
+ }
46
+ try {
47
+ return decodeBase64ToBytes(result.output.data);
48
+ } catch {
49
+ return null;
50
+ }
51
+ }, [(_b = result.output) == null ? void 0 : _b.data]);
52
+ useEffect(() => {
53
+ let cancelled = false;
54
+ const generateHash = async () => {
55
+ if (!outputBytes || typeof crypto === "undefined" || !crypto.subtle) {
56
+ setSha256Hash("N/A");
57
+ return;
58
+ }
59
+ const digest = await crypto.subtle.digest("SHA-256", outputBytes);
60
+ const digestArray = Array.from(new Uint8Array(digest));
61
+ const digestHex = digestArray.map((value) => value.toString(16).padStart(2, "0")).join("");
62
+ if (!cancelled) {
63
+ setSha256Hash(digestHex);
64
+ }
65
+ };
66
+ setSha256Hash("");
67
+ generateHash();
68
+ return () => {
69
+ cancelled = true;
70
+ };
71
+ }, [outputBytes]);
72
+ return /* @__PURE__ */ jsxs(Stack, { sx: { overflowY: "auto" }, spacing: 3, children: [
73
+ /* @__PURE__ */ jsx(Typography, { variant: "h5", children: t("actions.result.file.title", { actionName }) }),
74
+ /* @__PURE__ */ jsx(Typography, { children: t("actions.result.file.description", { actionName }) }),
75
+ /* @__PURE__ */ jsx(Divider, { flexItem: true }),
76
+ /* @__PURE__ */ jsx(Typography, { variant: "h6", children: t("actions.result.file.stats.title") }),
77
+ outputBytes && /* @__PURE__ */ jsx(Table, { sx: { maxWidth: 900 }, children: /* @__PURE__ */ jsxs(TableBody, { children: [
78
+ /* @__PURE__ */ jsxs(TableRow, { children: [
79
+ /* @__PURE__ */ jsx(TableCell, { sx: { width: "35%" }, children: t("actions.result.file.stats.label.decoded_size") }),
80
+ /* @__PURE__ */ jsx(TableCell, { children: formatBytes(outputBytes.length) || "n/a" })
81
+ ] }),
82
+ /* @__PURE__ */ jsxs(TableRow, { children: [
83
+ /* @__PURE__ */ jsx(TableCell, { sx: { width: "35%" }, children: t("actions.result.file.stats.label.decoded_bytes") }),
84
+ /* @__PURE__ */ jsx(TableCell, { children: outputBytes.length || "n/a" })
85
+ ] }),
86
+ /* @__PURE__ */ jsxs(TableRow, { children: [
87
+ /* @__PURE__ */ jsx(TableCell, { sx: { width: "35%" }, children: t("actions.result.file.stats.label.base64_length") }),
88
+ /* @__PURE__ */ jsx(TableCell, { children: ((_c = result.output) == null ? void 0 : _c.data.length) ?? "n/a" })
89
+ ] }),
90
+ /* @__PURE__ */ jsxs(TableRow, { children: [
91
+ /* @__PURE__ */ jsx(TableCell, { sx: { width: "35%" }, children: t("actions.result.file.stats.label.sha256") }),
92
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx("code", { children: sha256Hash || t("actions.result.file.stats.calculating") }) })
93
+ ] })
94
+ ] }) }),
95
+ /* @__PURE__ */ jsx(
96
+ Button,
97
+ {
98
+ startIcon: /* @__PURE__ */ jsx(Iconified, { icon: "ic:baseline-download" }),
99
+ variant: "outlined",
100
+ sx: { alignSelf: "center" },
101
+ disabled: !((_d = result.output) == null ? void 0 : _d.data),
102
+ onClick: () => result.output && saveFileFromServer(result.output),
103
+ name: "download",
104
+ role: "button",
105
+ children: t("download", { file: ((_e = result.output) == null ? void 0 : _e.file_name) ?? "result.txt" })
106
+ }
107
+ )
108
+ ] });
109
+ };
110
+ export {
111
+ FileResult as default
112
+ };
@@ -0,0 +1,8 @@
1
+ import { ActionResult } from "../../../types/action";
2
+ import { WithActionData } from "../../../types/WithActionData";
3
+ import { FC } from 'react';
4
+
5
+ declare const Result: FC<{
6
+ result: WithActionData<ActionResult>;
7
+ }>;
8
+ export default Result;
@@ -0,0 +1,23 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Stack } from "@mui/material";
3
+ import { J as JSONViewer } from "../../../index-Bmoj6JY8.js";
4
+ import Markdown from "../../display/markdown/index.js";
5
+ import FileResult from "./FileResult.js";
6
+ const Result = ({ result }) => {
7
+ if (result.format === "markdown") {
8
+ return /* @__PURE__ */ jsx(Markdown, { md: result.output });
9
+ }
10
+ if (result.format === "json") {
11
+ return /* @__PURE__ */ jsx(JSONViewer, { data: result.output, collapse: true, forceCompact: true });
12
+ }
13
+ if (result.format === "file") {
14
+ return /* @__PURE__ */ jsx(FileResult, { result });
15
+ }
16
+ return /* @__PURE__ */ jsxs(Stack, { sx: { overflowY: "auto" }, children: [
17
+ /* @__PURE__ */ jsx(Markdown, { md: "`" + result.format + "` is not recognized as a format in this application." }),
18
+ /* @__PURE__ */ jsx(JSONViewer, { data: result, collapse: true, forceCompact: true })
19
+ ] });
20
+ };
21
+ export {
22
+ Result as default
23
+ };
@@ -1,7 +1,7 @@
1
1
  import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
2
  import { useTheme, Tooltip, IconButton, CircularProgress, Button, Popover, Paper, Stack, Box, Typography, Divider } from "@mui/material";
3
3
  import { useClueComponentSelector, useClueEnrichSelector } from "../../hooks/selectors.js";
4
- import { c as capitalize } from "../../ActionForm-wVwVYO-b.js";
4
+ import { c as capitalize } from "../../ActionForm-Hg3A_2XX.js";
5
5
  import { useState, useRef, useCallback, useEffect } from "react";
6
6
  import Iconified from "../display/icons/Iconified.js";
7
7
  const EnrichPopover = ({ show = false, size = "small", selector }) => {
@@ -6,7 +6,7 @@ import { SNACKBAR_EVENT_ID } from "../../data/event.js";
6
6
  import { ClueGroupContext } from "../../hooks/ClueGroupContext.js";
7
7
  import { useClueComponentSelector, useClueEnrichSelector } from "../../hooks/selectors.js";
8
8
  import { safeDispatchEvent } from "../../utils/window.js";
9
- import { c as capitalize } from "../../ActionForm-wVwVYO-b.js";
9
+ import { c as capitalize } from "../../ActionForm-Hg3A_2XX.js";
10
10
  import { useState, useMemo, useCallback } from "react";
11
11
  import { u as useContextSelector } from "../../index-BDVjGvMI.js";
12
12
  import ExecutePopover from "../actions/ExecutePopover.js";
@@ -6,6 +6,15 @@
6
6
  "actions.executing": "Executing",
7
7
  "actions.json.hide": "Hide JSON",
8
8
  "actions.json.show": "Show JSON",
9
+ "actions.result.file.description": "The action {{actionName}} has provided a file for download. If you wish to download the result, use the download button below.",
10
+ "actions.result.file.stats.calculating": "Calculating...",
11
+ "actions.result.file.stats.label.base64_length": "Base64 Length:",
12
+ "actions.result.file.stats.label.decoded_bytes": "Decoded Bytes:",
13
+ "actions.result.file.stats.label.decoded_size": "Decoded Size:",
14
+ "actions.result.file.stats.label.sha256": "SHA-256:",
15
+ "actions.result.file.stats.title": "File statistics",
16
+ "actions.result.file.title": "{{actionName}} has provided a file",
17
+ "actions.result.file.unknown": "Unknown",
9
18
  "adminmenu": "Admin menu",
10
19
  "adminmenu.config": "Configuration",
11
20
  "adminmenu.users": "Users",
@@ -24,6 +33,7 @@
24
33
  "clipboard.success": "was copied to clipboard.",
25
34
  "close": "Close",
26
35
  "details.open": "Open Details",
36
+ "download": "Download {{file}}",
27
37
  "drawer.chat": "Chat",
28
38
  "drawer.collapse": "Collapse Menu",
29
39
  "drawer.dashboard": "Dashboard",
@@ -6,6 +6,15 @@
6
6
  "actions.executing": "Executing",
7
7
  "actions.json.hide": "Masquer JSON",
8
8
  "actions.json.show": "Afficher JSON",
9
+ "actions.result.file.description": "L'action {{actionName}} a fourni un fichier à télécharger. Si vous souhaitez télécharger le résultat, utilisez le bouton de téléchargement ci-dessous.",
10
+ "actions.result.file.stats.calculating": "Calcul en cours...",
11
+ "actions.result.file.stats.label.base64_length": "Longueur base64 :",
12
+ "actions.result.file.stats.label.decoded_bytes": "Octets décodés :",
13
+ "actions.result.file.stats.label.decoded_size": "Taille décodée :",
14
+ "actions.result.file.stats.label.sha256": "SHA-256 :",
15
+ "actions.result.file.stats.title": "Statistiques du fichier",
16
+ "actions.result.file.title": "{{actionName}} a fourni un fichier",
17
+ "actions.result.file.unknown": "Inconnu",
9
18
  "adminmenu": "Menu d'administration",
10
19
  "adminmenu.config": "Configuration",
11
20
  "adminmenu.users": "Usagers",
@@ -24,6 +33,7 @@
24
33
  "clipboard.success": "a été copié dans le presse-papiers.",
25
34
  "close": "Fermer",
26
35
  "details.open": "Ouvrir les détails",
36
+ "download": "Télécharger {{file}}",
27
37
  "drawer.chat": "Clavardage",
28
38
  "drawer.collapse": "Fermer le Menu",
29
39
  "drawer.dashboard": "Tableau de bord",
@@ -2,7 +2,7 @@ import "react/jsx-runtime";
2
2
  import "@mui/material";
3
3
  import "../index-CC12Ux-9.js";
4
4
  import "../useClueTypeConfig-CHWm5uda.js";
5
- import { a, C } from "../ActionForm-wVwVYO-b.js";
5
+ import { a, C } from "../ActionForm-Hg3A_2XX.js";
6
6
  import "../components/display/icons/Iconified.js";
7
7
  import "../components/ErrorBoundary.js";
8
8
  import "../data/event.js";
@@ -1,5 +1,5 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { C as ClueActionProvider } from "../ActionForm-wVwVYO-b.js";
2
+ import { C as ClueActionProvider } from "../ActionForm-Hg3A_2XX.js";
3
3
  import { ClueComponentProvider } from "./ClueComponentContext.js";
4
4
  import { ClueConfigProvider } from "./ClueConfigProvider.js";
5
5
  import { ClueDatabaseProvider } from "./ClueDatabaseContext.js";
@@ -1,4 +1,4 @@
1
- import { a as ClueActionContext } from "../ActionForm-wVwVYO-b.js";
1
+ import { a as ClueActionContext } from "../ActionForm-Hg3A_2XX.js";
2
2
  import { ClueComponentContext } from "./ClueComponentContext.js";
3
3
  import { C as ClueEnrichContext } from "../ClueEnrichContext-DzZhWGxh.js";
4
4
  import { ClueFetcherContext } from "./ClueFetcherContext.js";
@@ -1,5 +1,5 @@
1
1
  import "react";
2
- import { b } from "../ActionForm-wVwVYO-b.js";
2
+ import { b } from "../ActionForm-Hg3A_2XX.js";
3
3
  export {
4
4
  b as useActionResult
5
5
  };
@@ -1,4 +1,4 @@
1
- import { u } from "../ActionForm-wVwVYO-b.js";
1
+ import { u } from "../ActionForm-Hg3A_2XX.js";
2
2
  import "../index-BDVjGvMI.js";
3
3
  export {
4
4
  u as default
package/icons/Action.js CHANGED
@@ -3,7 +3,7 @@ import { I as Icon } from "../iconify-CXMreGTg.js";
3
3
  import { useTheme, Stack, Divider, Typography } from "@mui/material";
4
4
  import CountBadge from "../components/CountBadge.js";
5
5
  import { C as CluePopupContext } from "../AnnotationPreview-D5NX8_su.js";
6
- import { u as useClueActions } from "../ActionForm-wVwVYO-b.js";
6
+ import { u as useClueActions } from "../ActionForm-Hg3A_2XX.js";
7
7
  import { g as groupBy } from "../groupBy-mXHt-nYT.js";
8
8
  import { memo, useRef, useMemo, useEffect } from "react";
9
9
  import { u as useContextSelector } from "../index-BDVjGvMI.js";
package/main.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A, u } from "./ActionForm-wVwVYO-b.js";
1
+ import { A, u } from "./ActionForm-Hg3A_2XX.js";
2
2
  import { default as default2 } from "./components/AnnotationDetailPopover.js";
3
3
  import { A as A2 } from "./AnnotationDetails-CbXSCkTF.js";
4
4
  import { default as default3 } from "./components/AnnotationEntry.js";
package/package.json CHANGED
@@ -66,7 +66,7 @@
66
66
  },
67
67
  "type": "module",
68
68
  "types": "main.d.ts",
69
- "version": "1.2.0-dev.171",
69
+ "version": "1.2.0-dev.175",
70
70
  "exports": {
71
71
  ".": "./main.js",
72
72
  "./index.css": "./index.css",
@@ -88,6 +88,8 @@
88
88
  "./components/fetchers/*": "./components/fetchers/*.js",
89
89
  "./components/display/*": "./components/display/*.js",
90
90
  "./components/stats/*": "./components/stats/*.js",
91
+ "./components/actions/formats/*": "./components/actions/formats/*.js",
92
+ "./components/actions/formats": "./components/actions/formats/index.js",
91
93
  "./components/actions/form/*": "./components/actions/form/*.js",
92
94
  "./components/display/graph/*": "./components/display/graph/*.js",
93
95
  "./components/display/graph": "./components/display/graph/index.js",
@@ -9,7 +9,6 @@ interface RunningActionData {
9
9
  selectors: Selector[];
10
10
  params: { [index: string]: any };
11
11
  context?: ActionContextInformation;
12
- skipResultModal?: boolean;
13
12
  onComplete?: (result: WithActionData<ActionResult>) => void;
14
13
  timeout?: number;
15
14
  }