@ixo/editor 6.30.3 → 6.32.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/dist/action-manifest.json +17 -1
- package/dist/{chunk-XYAKFAZ3.js → chunk-37OKRZEK.js} +1224 -232
- package/dist/chunk-37OKRZEK.js.map +1 -0
- package/dist/{chunk-OAAEXL7Q.js → chunk-S7CAGFE3.js} +2 -2
- package/dist/{chunk-LY32OATI.js → chunk-ZXNBOVAA.js} +149 -56
- package/dist/chunk-ZXNBOVAA.js.map +1 -0
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +2 -2
- package/dist/{graphql-client-BV2YEKAc.d.ts → graphql-client-ZY4Iw0jB.d.ts} +1 -1
- package/dist/{index-CEIunGZv.d.ts → index-Up8gA_E9.d.ts} +25 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/mantine/index.d.ts +3 -3
- package/dist/mantine/index.js +2 -2
- package/dist/{store-whqrkEVn.d.ts → store-CqvAkvIZ.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-LY32OATI.js.map +0 -1
- package/dist/chunk-XYAKFAZ3.js.map +0 -1
- /package/dist/{chunk-OAAEXL7Q.js.map → chunk-S7CAGFE3.js.map} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
COLLECTION_USERS_MAX_GRANTS_PER_TX,
|
|
2
3
|
DIFFERENT_WHEN_OPTIONS,
|
|
3
4
|
DIFFERENT_WHEN_OTHER_MAX,
|
|
4
5
|
EVAL_ENGINE_ACTION_TYPE,
|
|
@@ -35,6 +36,7 @@ import {
|
|
|
35
36
|
cancelRun,
|
|
36
37
|
closeRun,
|
|
37
38
|
collectPhantomLegacyRun,
|
|
39
|
+
collectionUsersBatchCount,
|
|
38
40
|
countSuccessfulRuns,
|
|
39
41
|
createInvocationStore,
|
|
40
42
|
createReference,
|
|
@@ -130,7 +132,7 @@ import {
|
|
|
130
132
|
writeActionState,
|
|
131
133
|
writeRunRecordAndReconcile,
|
|
132
134
|
xeroOracleActivityForBlockForEditor
|
|
133
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-ZXNBOVAA.js";
|
|
134
136
|
|
|
135
137
|
// src/mantine/hooks/usePanel.ts
|
|
136
138
|
import { useCallback, useMemo, useEffect, useRef } from "react";
|
|
@@ -9179,7 +9181,7 @@ var ClaimListItem = ({ claim, onViewClaim }) => {
|
|
|
9179
9181
|
};
|
|
9180
9182
|
fetchUserProfile();
|
|
9181
9183
|
}, [claim.agentDid]);
|
|
9182
|
-
const
|
|
9184
|
+
const claimStatus = getClaimStatusInfo(claim);
|
|
9183
9185
|
const displayName = userProfile?.displayname || (claim.agentAddress ? `${claim.agentAddress.slice(0, 12)}...` : "Unknown");
|
|
9184
9186
|
return /* @__PURE__ */ React79.createElement(
|
|
9185
9187
|
"div",
|
|
@@ -9195,7 +9197,7 @@ var ClaimListItem = ({ claim, onViewClaim }) => {
|
|
|
9195
9197
|
tabIndex: 0,
|
|
9196
9198
|
style: { cursor: "pointer" }
|
|
9197
9199
|
},
|
|
9198
|
-
/* @__PURE__ */ React79.createElement(ListItemContainer, { isChecked: false }, /* @__PURE__ */ React79.createElement(Stack48, { gap: 4, style: { flex: 1 } }, /* @__PURE__ */ React79.createElement(Text48, { size: "sm", fw: 500 }, "Claim #", claim.claimId), /* @__PURE__ */ React79.createElement(Text48, { size: "xs", c: "dimmed" }, "Submitted: ", formatDate(claim.submissionDate || claim.submittedAt)), claim.agentDid && /* @__PURE__ */ React79.createElement(Group22, { gap: 4 }, /* @__PURE__ */ React79.createElement(Text48, { size: "xs", c: "dimmed" }, "Agent: ", loadingProfile ? "Loading..." : displayName), userProfile?.verified && /* @__PURE__ */ React79.createElement(Text48, { size: "xs", c: "blue", fw: 600, title: "Verified user" }, "\u2713"))), /* @__PURE__ */ React79.createElement(Stack48, { gap: 4, align: "flex-end" }, /* @__PURE__ */ React79.createElement(Badge8, { color:
|
|
9200
|
+
/* @__PURE__ */ React79.createElement(ListItemContainer, { isChecked: false }, /* @__PURE__ */ React79.createElement(Stack48, { gap: 4, style: { flex: 1 } }, /* @__PURE__ */ React79.createElement(Text48, { size: "sm", fw: 500 }, "Claim #", claim.claimId), /* @__PURE__ */ React79.createElement(Text48, { size: "xs", c: "dimmed" }, "Submitted: ", formatDate(claim.submissionDate || claim.submittedAt)), claim.agentDid && /* @__PURE__ */ React79.createElement(Group22, { gap: 4 }, /* @__PURE__ */ React79.createElement(Text48, { size: "xs", c: "dimmed" }, "Agent: ", loadingProfile ? "Loading..." : displayName), userProfile?.verified && /* @__PURE__ */ React79.createElement(Text48, { size: "xs", c: "blue", fw: 600, title: "Verified user" }, "\u2713"))), /* @__PURE__ */ React79.createElement(Stack48, { gap: 4, align: "flex-end" }, /* @__PURE__ */ React79.createElement(Badge8, { color: claimStatus.color, size: "sm" }, claimStatus.label), /* @__PURE__ */ React79.createElement(ActionIcon13, { variant: "subtle", size: "sm" }, /* @__PURE__ */ React79.createElement(IconArrowRight2, { size: 16 }))))
|
|
9199
9201
|
);
|
|
9200
9202
|
};
|
|
9201
9203
|
|
|
@@ -9681,8 +9683,8 @@ var ClaimsEvaluation = ({ collectionId, adminAddress, deedId, claim, onRefresh }
|
|
|
9681
9683
|
}, [claim, handlers, deedId, collectionId, adminAddress, evaluationResult, onRefresh, editor, buildPaymentCoin]);
|
|
9682
9684
|
const isClaimAlreadyEvaluated = useMemo39(() => {
|
|
9683
9685
|
if (!claim) return false;
|
|
9684
|
-
const
|
|
9685
|
-
return
|
|
9686
|
+
const claimStatus = getClaimStatus(claim);
|
|
9687
|
+
return claimStatus.status === "Approved" || claimStatus.status === "Rejected";
|
|
9686
9688
|
}, [claim]);
|
|
9687
9689
|
if (isClaimAlreadyEvaluated) {
|
|
9688
9690
|
return /* @__PURE__ */ React86.createElement(Stack53, { style: { flex: 1 } }, /* @__PURE__ */ React86.createElement(BaseAlert, { isError: false, errMsg: "This claim has already been reviewed. No further action is required." }));
|
|
@@ -9909,9 +9911,9 @@ var ClaimsList2 = ({ items, isMultiSelect, isItemChecked, onItemCheck }) => {
|
|
|
9909
9911
|
}
|
|
9910
9912
|
const rows = items.map((item) => {
|
|
9911
9913
|
const isChecked = isItemChecked?.(item.claimId);
|
|
9912
|
-
const
|
|
9914
|
+
const claimStatus = getClaimStatus(item);
|
|
9913
9915
|
const profile = item.agentDid ? profiles[item.agentDid] : null;
|
|
9914
|
-
return /* @__PURE__ */ React90.createElement(ListItemContainer, { onClick: () => onItemCheck?.(item.claimId, !isChecked), key: item.claimId, isChecked: !!isChecked }, /* @__PURE__ */ React90.createElement(Flex25, { align: "center", gap: "sm" }, /* @__PURE__ */ React90.createElement(BaseAvatar, { src: profile?.avatarUrl, did: profile?.did, size: 34 }), /* @__PURE__ */ React90.createElement(Stack57, { gap: 0 }, /* @__PURE__ */ React90.createElement(Text57, { size: "sm", fw: 500 }, profile?.displayname || "Unknown User"), /* @__PURE__ */ React90.createElement(Text57, { size: "xs", c: "dimmed", lineClamp: 1 }, shortStr(item.agentAddress, 21, 5) || "No address"))), /* @__PURE__ */ React90.createElement(Flex25, { align: "center", gap: "md" }, /* @__PURE__ */ React90.createElement(Group25, { gap: 4 }, /* @__PURE__ */ React90.createElement(
|
|
9916
|
+
return /* @__PURE__ */ React90.createElement(ListItemContainer, { onClick: () => onItemCheck?.(item.claimId, !isChecked), key: item.claimId, isChecked: !!isChecked }, /* @__PURE__ */ React90.createElement(Flex25, { align: "center", gap: "sm" }, /* @__PURE__ */ React90.createElement(BaseAvatar, { src: profile?.avatarUrl, did: profile?.did, size: 34 }), /* @__PURE__ */ React90.createElement(Stack57, { gap: 0 }, /* @__PURE__ */ React90.createElement(Text57, { size: "sm", fw: 500 }, profile?.displayname || "Unknown User"), /* @__PURE__ */ React90.createElement(Text57, { size: "xs", c: "dimmed", lineClamp: 1 }, shortStr(item.agentAddress, 21, 5) || "No address"))), /* @__PURE__ */ React90.createElement(Flex25, { align: "center", gap: "md" }, /* @__PURE__ */ React90.createElement(Group25, { gap: 4 }, /* @__PURE__ */ React90.createElement(claimStatus.icon, { color: claimStatus.color, size: 18 }), /* @__PURE__ */ React90.createElement(Text57, { c: claimStatus.color, size: "sm" }, claimStatus.status)), isMultiSelect && /* @__PURE__ */ React90.createElement(ListItemCheckbox, { ariaLabel: `Select claim ${item.claimId}`, checked: isItemChecked?.(item.claimId), onCheck: (checked) => onItemCheck?.(item.claimId, checked) })));
|
|
9915
9917
|
});
|
|
9916
9918
|
return /* @__PURE__ */ React90.createElement(Box27, { flex: 1 }, /* @__PURE__ */ React90.createElement(Stack57, { gap: "xs" }, rows));
|
|
9917
9919
|
};
|
|
@@ -9928,61 +9930,83 @@ var MatrixMembersList = ({ items }) => {
|
|
|
9928
9930
|
};
|
|
9929
9931
|
|
|
9930
9932
|
// src/core/utils/files.ts
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
|
|
9937
|
-
|
|
9938
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
9941
|
-
|
|
9942
|
-
const
|
|
9943
|
-
|
|
9944
|
-
|
|
9945
|
-
|
|
9946
|
-
|
|
9947
|
-
|
|
9948
|
-
|
|
9949
|
-
|
|
9950
|
-
|
|
9951
|
-
|
|
9952
|
-
if (isObjectRow(r)) {
|
|
9953
|
-
for (const k of Object.keys(r)) keySet.add(k);
|
|
9954
|
-
}
|
|
9933
|
+
var safeString = (value) => {
|
|
9934
|
+
if (value === null || value === void 0) return "";
|
|
9935
|
+
if (typeof value === "string") return value;
|
|
9936
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
9937
|
+
try {
|
|
9938
|
+
return JSON.stringify(value);
|
|
9939
|
+
} catch {
|
|
9940
|
+
return String(value);
|
|
9941
|
+
}
|
|
9942
|
+
};
|
|
9943
|
+
var csvEscape = (field) => {
|
|
9944
|
+
const needsQuotes = /[",\n\r]/.test(field);
|
|
9945
|
+
const out = field.replace(/"/g, '""');
|
|
9946
|
+
return needsQuotes ? `"${out}"` : out;
|
|
9947
|
+
};
|
|
9948
|
+
var isObjectRow = (r) => r !== null && typeof r === "object" && !Array.isArray(r);
|
|
9949
|
+
function unionHeaders(rows) {
|
|
9950
|
+
const keySet = /* @__PURE__ */ new Set();
|
|
9951
|
+
for (const r of rows) {
|
|
9952
|
+
if (isObjectRow(r)) {
|
|
9953
|
+
for (const k of Object.keys(r)) keySet.add(k);
|
|
9955
9954
|
}
|
|
9956
|
-
headers = Array.from(keySet);
|
|
9957
|
-
} else {
|
|
9958
|
-
headers = ["value"];
|
|
9959
9955
|
}
|
|
9956
|
+
return Array.from(keySet);
|
|
9957
|
+
}
|
|
9958
|
+
function rowsToCsv(rows) {
|
|
9959
|
+
const headers = rows.length > 0 && isObjectRow(rows[0]) ? unionHeaders(rows) : ["value"];
|
|
9960
9960
|
const csvLines = [];
|
|
9961
9961
|
csvLines.push(headers.map((h) => csvEscape(h)).join(","));
|
|
9962
9962
|
for (const row of rows) {
|
|
9963
9963
|
if (isObjectRow(row)) {
|
|
9964
9964
|
const obj = row;
|
|
9965
|
-
|
|
9966
|
-
csvLines.push(line);
|
|
9965
|
+
csvLines.push(headers.map((h) => csvEscape(safeString(Object.prototype.hasOwnProperty.call(obj, h) ? obj[h] : ""))).join(","));
|
|
9967
9966
|
} else {
|
|
9968
9967
|
csvLines.push(csvEscape(safeString(row)));
|
|
9969
9968
|
}
|
|
9970
9969
|
}
|
|
9971
|
-
|
|
9972
|
-
|
|
9973
|
-
|
|
9970
|
+
return csvLines.join("\r\n");
|
|
9971
|
+
}
|
|
9972
|
+
function sectionsToCsv(sections) {
|
|
9973
|
+
const blocks = [];
|
|
9974
|
+
sections.forEach((section, index) => {
|
|
9975
|
+
const lines = [];
|
|
9976
|
+
if (index > 0) lines.push("");
|
|
9977
|
+
lines.push(csvEscape(section.title));
|
|
9978
|
+
if (section.rows.length === 0) {
|
|
9979
|
+
lines.push(csvEscape(section.emptyNote || "No records"));
|
|
9980
|
+
} else {
|
|
9981
|
+
lines.push(rowsToCsv(section.rows));
|
|
9982
|
+
}
|
|
9983
|
+
blocks.push(lines.join("\r\n"));
|
|
9984
|
+
});
|
|
9985
|
+
return blocks.join("\r\n");
|
|
9986
|
+
}
|
|
9987
|
+
var UTF8_BOM = "\uFEFF";
|
|
9988
|
+
function timestampSuffix(d = /* @__PURE__ */ new Date()) {
|
|
9989
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
9990
|
+
return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
|
|
9991
|
+
}
|
|
9992
|
+
function downloadBlob(blob, filename) {
|
|
9974
9993
|
const url = URL.createObjectURL(blob);
|
|
9975
9994
|
const a = document.createElement("a");
|
|
9976
|
-
const pad = (n) => String(n).padStart(2, "0");
|
|
9977
|
-
const d = /* @__PURE__ */ new Date();
|
|
9978
|
-
const defaultName = `list-export-${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}.csv`;
|
|
9979
9995
|
a.href = url;
|
|
9980
|
-
a.download =
|
|
9996
|
+
a.download = filename;
|
|
9981
9997
|
document.body.appendChild(a);
|
|
9982
9998
|
a.click();
|
|
9983
9999
|
document.body.removeChild(a);
|
|
9984
10000
|
URL.revokeObjectURL(url);
|
|
9985
10001
|
}
|
|
10002
|
+
function downloadArrayAsCsv(rows, options) {
|
|
10003
|
+
const blob = new Blob([UTF8_BOM + rowsToCsv(rows)], { type: "text/csv;charset=utf-8;" });
|
|
10004
|
+
downloadBlob(blob, options?.filename || `list-export-${timestampSuffix()}.csv`);
|
|
10005
|
+
}
|
|
10006
|
+
function downloadSectionedCsv(sections, options) {
|
|
10007
|
+
const blob = new Blob([UTF8_BOM + sectionsToCsv(sections)], { type: "text/csv;charset=utf-8;" });
|
|
10008
|
+
downloadBlob(blob, options?.filename || `list-export-${timestampSuffix()}.csv`);
|
|
10009
|
+
}
|
|
9986
10010
|
|
|
9987
10011
|
// src/mantine/blocks/list/flow/ListFlowView.tsx
|
|
9988
10012
|
import { useDisclosure as useDisclosure3 } from "@mantine/hooks";
|
|
@@ -27314,7 +27338,7 @@ import React270, { useCallback as useCallback96, useEffect as useEffect98, useRe
|
|
|
27314
27338
|
import { Alert as Alert39, Button as Button54, Flex as Flex37, Loader as Loader44, Paper as Paper22, Stack as Stack183, Text as Text163, TextInput as TextInput10 } from "@mantine/core";
|
|
27315
27339
|
import { IconSearch as IconSearch10 } from "@tabler/icons-react";
|
|
27316
27340
|
var ADDRESS_PREFIX = "ixo1";
|
|
27317
|
-
var RecipientInput = ({ value, onChange, isDisabled, placeholder }) => {
|
|
27341
|
+
var RecipientInput = ({ value, onChange, isDisabled, placeholder, onBulkPaste }) => {
|
|
27318
27342
|
const handlers = useBlocknoteHandlers();
|
|
27319
27343
|
const handlersRef = useRef30(handlers);
|
|
27320
27344
|
handlersRef.current = handlers;
|
|
@@ -27388,6 +27412,13 @@ var RecipientInput = ({ value, onChange, isDisabled, placeholder }) => {
|
|
|
27388
27412
|
rightSection: searching ? /* @__PURE__ */ React270.createElement(Loader44, { size: 14 }) : null,
|
|
27389
27413
|
value: query,
|
|
27390
27414
|
onChange: (e) => handleQueryChange(e.currentTarget.value),
|
|
27415
|
+
onPaste: (e) => {
|
|
27416
|
+
if (!onBulkPaste) return;
|
|
27417
|
+
const text = e.clipboardData?.getData("text") ?? "";
|
|
27418
|
+
if (!/[\r\n\t]/.test(text.trim())) return;
|
|
27419
|
+
e.preventDefault();
|
|
27420
|
+
onBulkPaste(text);
|
|
27421
|
+
},
|
|
27391
27422
|
onKeyDown: (e) => {
|
|
27392
27423
|
if (e.key === "Enter") {
|
|
27393
27424
|
e.preventDefault();
|
|
@@ -31379,41 +31410,119 @@ function CollapsibleSection({ title, defaultOpen = false, badge, children }) {
|
|
|
31379
31410
|
// src/mantine/blocks/action/actionTypes/_shared/dataExport/DownloadCsvButton.tsx
|
|
31380
31411
|
import React311, { useCallback as useCallback105, useState as useState162 } from "react";
|
|
31381
31412
|
import { ActionIcon as ActionIcon44 } from "@mantine/core";
|
|
31382
|
-
import { IconDownload as IconDownload4 } from "@tabler/icons-react";
|
|
31383
|
-
var
|
|
31413
|
+
import { IconDownload as IconDownload4, IconFileZip } from "@tabler/icons-react";
|
|
31414
|
+
var DownloadIconButton = ({ onDownload, disabled, label, Icon, onError }) => {
|
|
31384
31415
|
const [busy, setBusy] = useState162(false);
|
|
31385
31416
|
const handleClick = useCallback105(async () => {
|
|
31386
31417
|
setBusy(true);
|
|
31387
31418
|
try {
|
|
31388
31419
|
await onDownload();
|
|
31420
|
+
} catch (err) {
|
|
31421
|
+
const message = err instanceof Error ? err.message : "The download failed.";
|
|
31422
|
+
console.error(`[dataExport] ${label} failed`, err);
|
|
31423
|
+
onError?.(message);
|
|
31389
31424
|
} finally {
|
|
31390
31425
|
setBusy(false);
|
|
31391
31426
|
}
|
|
31392
|
-
}, [onDownload]);
|
|
31393
|
-
return /* @__PURE__ */ React311.createElement(ActionIcon44, { variant: "subtle", color: "gray", size: "sm", "aria-label": label, title: label, loading: busy, disabled, onClick: handleClick }, /* @__PURE__ */ React311.createElement(
|
|
31427
|
+
}, [onDownload, onError, label]);
|
|
31428
|
+
return /* @__PURE__ */ React311.createElement(ActionIcon44, { variant: "subtle", color: "gray", size: "sm", "aria-label": label, title: label, loading: busy, disabled, onClick: handleClick }, /* @__PURE__ */ React311.createElement(Icon, { size: 16 }));
|
|
31394
31429
|
};
|
|
31430
|
+
var DownloadCsvButton = ({ onDownload, disabled, label = "Download CSV", onError }) => /* @__PURE__ */ React311.createElement(DownloadIconButton, { onDownload, disabled, label, Icon: IconDownload4, onError });
|
|
31431
|
+
var DownloadZipButton = ({ onDownload, disabled, label = "Download CSV + media (ZIP)", onError }) => /* @__PURE__ */ React311.createElement(DownloadIconButton, { onDownload, disabled, label, Icon: IconFileZip, onError });
|
|
31432
|
+
|
|
31433
|
+
// src/mantine/utils/bidStatus.ts
|
|
31434
|
+
var STATUS_META2 = {
|
|
31435
|
+
approved: { label: "Approved", color: "green", isTerminal: true },
|
|
31436
|
+
rejected: { label: "Rejected", color: "red", isTerminal: true },
|
|
31437
|
+
pending: { label: "Pending", color: "yellow", isTerminal: false }
|
|
31438
|
+
};
|
|
31439
|
+
function parseStatusKey(value) {
|
|
31440
|
+
const normalized = String(value ?? "").trim().toLowerCase();
|
|
31441
|
+
if (normalized === "approved" || normalized === "approve") return "approved";
|
|
31442
|
+
if (normalized === "rejected" || normalized === "reject") return "rejected";
|
|
31443
|
+
if (normalized === "pending") return "pending";
|
|
31444
|
+
return null;
|
|
31445
|
+
}
|
|
31446
|
+
function granteeRoleForBid(bid) {
|
|
31447
|
+
const role = String(bid?.role || "").toLowerCase();
|
|
31448
|
+
return role === "evaluation_agent" || role === "ea" ? "evaluate" : "submit";
|
|
31449
|
+
}
|
|
31450
|
+
function getBidStatusInfo(bid, context = {}) {
|
|
31451
|
+
const asInfo = (key, source) => ({ key, ...STATUS_META2[key], source });
|
|
31452
|
+
const session = context.evaluatedByBidId?.[bid?.id ?? ""];
|
|
31453
|
+
if (session) return asInfo(session, "session");
|
|
31454
|
+
const direct = parseStatusKey(bid?.status);
|
|
31455
|
+
if (direct) return asInfo(direct, "payload");
|
|
31456
|
+
try {
|
|
31457
|
+
const data = typeof bid?.data === "string" ? JSON.parse(bid.data) : bid?.data;
|
|
31458
|
+
const embedded = parseStatusKey(data?.status);
|
|
31459
|
+
if (embedded) return asInfo(embedded, "payload");
|
|
31460
|
+
} catch {
|
|
31461
|
+
}
|
|
31462
|
+
const grantees = context.grantees;
|
|
31463
|
+
if (grantees?.length) {
|
|
31464
|
+
const wanted = granteeRoleForBid(bid);
|
|
31465
|
+
if (grantees.some((grantee) => grantee.address === bid?.address && grantee.role === wanted)) {
|
|
31466
|
+
return asInfo("approved", "grant");
|
|
31467
|
+
}
|
|
31468
|
+
}
|
|
31469
|
+
return asInfo("pending", "default");
|
|
31470
|
+
}
|
|
31471
|
+
function describeGrantState(address, grantees) {
|
|
31472
|
+
const grants = grantees.filter((grantee) => grantee.address === address);
|
|
31473
|
+
if (grants.length === 0) return "none";
|
|
31474
|
+
return grants.map((grant) => `${grant.role} (quota ${grant.agentQuota ?? "\u2014"})`).join("; ");
|
|
31475
|
+
}
|
|
31476
|
+
var BID_GRANT_STATE_LABELS = {
|
|
31477
|
+
open: "Open \u2014 awaiting decision",
|
|
31478
|
+
granted: "Granted \u2014 active",
|
|
31479
|
+
granted_other_role: "Granted \u2014 different role",
|
|
31480
|
+
lapsed: "No active grant"
|
|
31481
|
+
};
|
|
31482
|
+
function classifyBidGrantState(bid, grantees, context = {}) {
|
|
31483
|
+
const decided = getBidStatusInfo(bid, { ...context, grantees: void 0 }).key !== "pending" || !!bid.decided;
|
|
31484
|
+
if (!decided) return "open";
|
|
31485
|
+
const wanted = granteeRoleForBid(bid);
|
|
31486
|
+
const onCollection = grantees.filter((grantee) => grantee.address === bid.address);
|
|
31487
|
+
if (onCollection.some((grantee) => grantee.role === wanted)) return "granted";
|
|
31488
|
+
if (onCollection.length > 0) return "granted_other_role";
|
|
31489
|
+
return "lapsed";
|
|
31490
|
+
}
|
|
31395
31491
|
|
|
31396
31492
|
// src/mantine/blocks/action/actionTypes/_shared/dataExport/buildBidRows.ts
|
|
31397
|
-
function
|
|
31398
|
-
|
|
31399
|
-
const
|
|
31400
|
-
|
|
31401
|
-
|
|
31402
|
-
try {
|
|
31403
|
-
const parsed = typeof bid.data === "string" ? JSON.parse(bid.data) : bid.data;
|
|
31404
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
31405
|
-
answers = parsed;
|
|
31406
|
-
}
|
|
31407
|
-
} catch {
|
|
31408
|
-
answers = { data: bid.data };
|
|
31493
|
+
function bidAnswers(bid) {
|
|
31494
|
+
try {
|
|
31495
|
+
const parsed = typeof bid.data === "string" ? JSON.parse(bid.data) : bid.data;
|
|
31496
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
31497
|
+
return parsed;
|
|
31409
31498
|
}
|
|
31499
|
+
} catch {
|
|
31500
|
+
return { data: bid.data };
|
|
31501
|
+
}
|
|
31502
|
+
return {};
|
|
31503
|
+
}
|
|
31504
|
+
function buildBidRows(bids, grantees, options = {}) {
|
|
31505
|
+
const statusContext = { grantees, evaluatedByBidId: options.evaluatedByBidId };
|
|
31506
|
+
return bids.map((bid) => {
|
|
31507
|
+
const answers = options.answersByBidId?.[bid.id] ?? bidAnswers(bid);
|
|
31508
|
+
const status = getBidStatusInfo(bid, statusContext);
|
|
31509
|
+
const grantState = classifyBidGrantState(bid, grantees, statusContext);
|
|
31410
31510
|
return {
|
|
31411
31511
|
bidId: bid.id,
|
|
31512
|
+
name: options.namesByDid?.[bid.did] || "",
|
|
31412
31513
|
did: bid.did,
|
|
31413
31514
|
address: bid.address,
|
|
31414
31515
|
role: bid.role,
|
|
31415
31516
|
created: bid.created,
|
|
31416
|
-
|
|
31517
|
+
status: status.key,
|
|
31518
|
+
statusSource: status.source,
|
|
31519
|
+
// The column that answers "did anything come of this bid?". `lapsed`
|
|
31520
|
+
// means the account submitted, was decided, and holds no grant today —
|
|
31521
|
+
// a population that appears in neither the bids list nor the grant list.
|
|
31522
|
+
bidState: grantState,
|
|
31523
|
+
bidStateNote: BID_GRANT_STATE_LABELS[grantState],
|
|
31524
|
+
activeGrant: grantState === "granted" || grantState === "granted_other_role" ? "yes" : "no",
|
|
31525
|
+
grantDetail: describeGrantState(bid.address, grantees),
|
|
31417
31526
|
...answers
|
|
31418
31527
|
};
|
|
31419
31528
|
});
|
|
@@ -31435,30 +31544,489 @@ function buildGranteeRows(grantees, namesByDid = {}) {
|
|
|
31435
31544
|
}
|
|
31436
31545
|
|
|
31437
31546
|
// src/mantine/blocks/action/actionTypes/_shared/dataExport/buildClaimRows.ts
|
|
31438
|
-
function
|
|
31439
|
-
|
|
31440
|
-
|
|
31441
|
-
|
|
31442
|
-
return "pending";
|
|
31547
|
+
function claimAnswers(contents) {
|
|
31548
|
+
const raw = contents;
|
|
31549
|
+
const subject = raw?.credentialSubject ?? raw;
|
|
31550
|
+
return subject && typeof subject === "object" && !Array.isArray(subject) ? subject : {};
|
|
31443
31551
|
}
|
|
31444
|
-
function buildClaimRows(claims, contentsByClaimId) {
|
|
31552
|
+
function buildClaimRows(claims, contentsByClaimId, options = {}) {
|
|
31445
31553
|
return claims.map((claim) => {
|
|
31446
|
-
const
|
|
31447
|
-
const
|
|
31448
|
-
const answers = subject && typeof subject === "object" && !Array.isArray(subject) ? subject : {};
|
|
31554
|
+
const answers = options.answersByClaimId?.[claim.claimId] ?? claimAnswers(contentsByClaimId[claim.claimId]);
|
|
31555
|
+
const status = getClaimStatusInfo(claim);
|
|
31449
31556
|
return {
|
|
31450
31557
|
claimId: claim.claimId,
|
|
31451
31558
|
collectionId: claim.collectionId,
|
|
31452
31559
|
agentDid: claim.agentDid,
|
|
31453
31560
|
agentAddress: claim.agentAddress,
|
|
31454
31561
|
submissionDate: claim.submissionDate,
|
|
31455
|
-
status:
|
|
31562
|
+
status: status.key,
|
|
31563
|
+
// A terminal decision outranks a dispute in `status`, but the dispute
|
|
31564
|
+
// record stays on chain — keep it visible rather than losing it.
|
|
31565
|
+
hasDispute: !!claim.disputeBySubjectId,
|
|
31456
31566
|
schemaType: claim.schemaType ?? "",
|
|
31457
31567
|
...answers
|
|
31458
31568
|
};
|
|
31459
31569
|
});
|
|
31460
31570
|
}
|
|
31461
31571
|
|
|
31572
|
+
// src/mantine/blocks/action/actionTypes/_shared/dataExport/buildCollectionMembersSections.ts
|
|
31573
|
+
var OPEN_ONLY_NOTE = "Open bids only \u2014 the bids service drops a bid from its query response once it is approved or rejected, and this host cannot read decided bids from the collection room.";
|
|
31574
|
+
var FULL_HISTORY_NOTE = "All bids, open and decided. See bidState: open = awaiting decision, granted = decided with a live grant, lapsed = decided with NO active grant.";
|
|
31575
|
+
function buildCollectionMembersSections(params) {
|
|
31576
|
+
const { grantees, bids, namesByDid = {}, collectionId, bidsTruncated, decidedBidsIncluded } = params;
|
|
31577
|
+
const label = collectionId ? ` (collection ${collectionId})` : "";
|
|
31578
|
+
const scopeNote = decidedBidsIncluded ? FULL_HISTORY_NOTE : OPEN_ONLY_NOTE;
|
|
31579
|
+
const truncationNote = bidsTruncated ? " WARNING: paging stopped early \u2014 this list is incomplete." : "";
|
|
31580
|
+
return [
|
|
31581
|
+
{
|
|
31582
|
+
title: `PART 1 \u2014 ACTIVE GRANTS${label}`,
|
|
31583
|
+
rows: buildGranteeRows(grantees, namesByDid),
|
|
31584
|
+
emptyNote: "No active grants on this collection."
|
|
31585
|
+
},
|
|
31586
|
+
{
|
|
31587
|
+
title: `PART 2 \u2014 ${decidedBidsIncluded ? "BIDS" : "OPEN BIDS"}${label} \u2014 ${scopeNote}${truncationNote}`,
|
|
31588
|
+
rows: buildBidRows(bids, grantees, { namesByDid, ...params.bidOptions }),
|
|
31589
|
+
emptyNote: decidedBidsIncluded ? "No bids have been submitted to this collection." : "No open bids on this collection."
|
|
31590
|
+
}
|
|
31591
|
+
];
|
|
31592
|
+
}
|
|
31593
|
+
|
|
31594
|
+
// src/core/utils/zip.ts
|
|
31595
|
+
var MAX_ENTRIES = 65535;
|
|
31596
|
+
var MAX_ARCHIVE_BYTES = 4294967295;
|
|
31597
|
+
var CRC_TABLE = (() => {
|
|
31598
|
+
const table = new Uint32Array(256);
|
|
31599
|
+
for (let i = 0; i < 256; i += 1) {
|
|
31600
|
+
let c = i;
|
|
31601
|
+
for (let k = 0; k < 8; k += 1) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
31602
|
+
table[i] = c >>> 0;
|
|
31603
|
+
}
|
|
31604
|
+
return table;
|
|
31605
|
+
})();
|
|
31606
|
+
function crc32(bytes) {
|
|
31607
|
+
let c = 4294967295;
|
|
31608
|
+
for (let i = 0; i < bytes.length; i += 1) c = CRC_TABLE[(c ^ bytes[i]) & 255] ^ c >>> 8;
|
|
31609
|
+
return (c ^ 4294967295) >>> 0;
|
|
31610
|
+
}
|
|
31611
|
+
function dosDateTime(date) {
|
|
31612
|
+
const year = Math.max(1980, date.getFullYear());
|
|
31613
|
+
return {
|
|
31614
|
+
time: (date.getHours() & 31) << 11 | (date.getMinutes() & 63) << 5 | date.getSeconds() >> 1 & 31,
|
|
31615
|
+
date: (year - 1980 & 127) << 9 | (date.getMonth() + 1 & 15) << 5 | date.getDate() & 31
|
|
31616
|
+
};
|
|
31617
|
+
}
|
|
31618
|
+
function toBytes(data, encoder) {
|
|
31619
|
+
return typeof data === "string" ? encoder.encode(data) : data;
|
|
31620
|
+
}
|
|
31621
|
+
function createZipBlob(entries, options) {
|
|
31622
|
+
if (entries.length > MAX_ENTRIES) {
|
|
31623
|
+
throw new Error(`ZIP archives are limited to ${MAX_ENTRIES} entries (got ${entries.length}).`);
|
|
31624
|
+
}
|
|
31625
|
+
const encoder = new TextEncoder();
|
|
31626
|
+
const { time, date } = dosDateTime(options?.modifiedAt ?? /* @__PURE__ */ new Date());
|
|
31627
|
+
const seen = /* @__PURE__ */ new Set();
|
|
31628
|
+
const prepared = entries.map((entry) => {
|
|
31629
|
+
const path = entry.path.replace(/^\/+/, "");
|
|
31630
|
+
if (seen.has(path)) throw new Error(`Duplicate ZIP entry path: ${path}`);
|
|
31631
|
+
seen.add(path);
|
|
31632
|
+
const nameBytes = encoder.encode(path);
|
|
31633
|
+
const dataBytes = toBytes(entry.data, encoder);
|
|
31634
|
+
return { nameBytes, dataBytes, crc: crc32(dataBytes), offset: 0 };
|
|
31635
|
+
});
|
|
31636
|
+
const localSize = prepared.reduce((sum, e) => sum + 30 + e.nameBytes.length + e.dataBytes.length, 0);
|
|
31637
|
+
const centralSize = prepared.reduce((sum, e) => sum + 46 + e.nameBytes.length, 0);
|
|
31638
|
+
const total = localSize + centralSize + 22;
|
|
31639
|
+
if (total > MAX_ARCHIVE_BYTES) {
|
|
31640
|
+
throw new Error(`Archive would be ${Math.round(total / 1024 / 1024)} MB, over the 4 GB ZIP limit. Export a smaller selection.`);
|
|
31641
|
+
}
|
|
31642
|
+
const buffer = new Uint8Array(total);
|
|
31643
|
+
const view = new DataView(buffer.buffer);
|
|
31644
|
+
let cursor = 0;
|
|
31645
|
+
const u16 = (value) => {
|
|
31646
|
+
view.setUint16(cursor, value, true);
|
|
31647
|
+
cursor += 2;
|
|
31648
|
+
};
|
|
31649
|
+
const u32 = (value) => {
|
|
31650
|
+
view.setUint32(cursor, value >>> 0, true);
|
|
31651
|
+
cursor += 4;
|
|
31652
|
+
};
|
|
31653
|
+
const raw = (bytes) => {
|
|
31654
|
+
buffer.set(bytes, cursor);
|
|
31655
|
+
cursor += bytes.length;
|
|
31656
|
+
};
|
|
31657
|
+
for (const entry of prepared) {
|
|
31658
|
+
entry.offset = cursor;
|
|
31659
|
+
u32(67324752);
|
|
31660
|
+
u16(20);
|
|
31661
|
+
u16(2048);
|
|
31662
|
+
u16(0);
|
|
31663
|
+
u16(time);
|
|
31664
|
+
u16(date);
|
|
31665
|
+
u32(entry.crc);
|
|
31666
|
+
u32(entry.dataBytes.length);
|
|
31667
|
+
u32(entry.dataBytes.length);
|
|
31668
|
+
u16(entry.nameBytes.length);
|
|
31669
|
+
u16(0);
|
|
31670
|
+
raw(entry.nameBytes);
|
|
31671
|
+
raw(entry.dataBytes);
|
|
31672
|
+
}
|
|
31673
|
+
const centralStart = cursor;
|
|
31674
|
+
for (const entry of prepared) {
|
|
31675
|
+
u32(33639248);
|
|
31676
|
+
u16(20);
|
|
31677
|
+
u16(20);
|
|
31678
|
+
u16(2048);
|
|
31679
|
+
u16(0);
|
|
31680
|
+
u16(time);
|
|
31681
|
+
u16(date);
|
|
31682
|
+
u32(entry.crc);
|
|
31683
|
+
u32(entry.dataBytes.length);
|
|
31684
|
+
u32(entry.dataBytes.length);
|
|
31685
|
+
u16(entry.nameBytes.length);
|
|
31686
|
+
u16(0);
|
|
31687
|
+
u16(0);
|
|
31688
|
+
u16(0);
|
|
31689
|
+
u16(0);
|
|
31690
|
+
u32(0);
|
|
31691
|
+
u32(entry.offset);
|
|
31692
|
+
raw(entry.nameBytes);
|
|
31693
|
+
}
|
|
31694
|
+
const centralEnd = cursor;
|
|
31695
|
+
u32(101010256);
|
|
31696
|
+
u16(0);
|
|
31697
|
+
u16(0);
|
|
31698
|
+
u16(prepared.length);
|
|
31699
|
+
u16(prepared.length);
|
|
31700
|
+
u32(centralEnd - centralStart);
|
|
31701
|
+
u32(centralStart);
|
|
31702
|
+
u16(0);
|
|
31703
|
+
return new Blob([buffer], { type: "application/zip" });
|
|
31704
|
+
}
|
|
31705
|
+
|
|
31706
|
+
// src/mantine/blocks/action/actionTypes/_shared/media/resolveClaimFileRef.ts
|
|
31707
|
+
var IPFS_GATEWAY = "https://ipfs.gateway.ixo.world/ipfs/";
|
|
31708
|
+
var CID_REGEX = /(baf[a-z0-9]{20,})/i;
|
|
31709
|
+
function extractCid(source) {
|
|
31710
|
+
const m = source.match(CID_REGEX);
|
|
31711
|
+
return m ? m[1] : null;
|
|
31712
|
+
}
|
|
31713
|
+
function resolveClaimFileRef(raw) {
|
|
31714
|
+
if (raw == null) return null;
|
|
31715
|
+
if (typeof raw === "string") {
|
|
31716
|
+
const trimmed = raw.trim();
|
|
31717
|
+
if (!trimmed) return null;
|
|
31718
|
+
if (/^https?:/i.test(trimmed)) return trimmed;
|
|
31719
|
+
if (trimmed.startsWith("data:")) return trimmed;
|
|
31720
|
+
if (/^ipfs:/i.test(trimmed)) {
|
|
31721
|
+
const cid = extractCid(trimmed.replace(/^ipfs:\/*/i, ""));
|
|
31722
|
+
return cid ? `${IPFS_GATEWAY}${cid}` : null;
|
|
31723
|
+
}
|
|
31724
|
+
if (trimmed.startsWith("{")) {
|
|
31725
|
+
try {
|
|
31726
|
+
return resolveClaimFileRef(JSON.parse(trimmed));
|
|
31727
|
+
} catch {
|
|
31728
|
+
return null;
|
|
31729
|
+
}
|
|
31730
|
+
}
|
|
31731
|
+
if (/^did:/i.test(trimmed)) {
|
|
31732
|
+
const cid = extractCid(trimmed);
|
|
31733
|
+
return cid ? `${IPFS_GATEWAY}${cid}` : null;
|
|
31734
|
+
}
|
|
31735
|
+
if (/^baf[a-z0-9]/i.test(trimmed) && trimmed.length < 200 && !trimmed.includes(" ")) {
|
|
31736
|
+
const cid = extractCid(trimmed);
|
|
31737
|
+
return cid ? `${IPFS_GATEWAY}${cid}` : null;
|
|
31738
|
+
}
|
|
31739
|
+
return null;
|
|
31740
|
+
}
|
|
31741
|
+
if (typeof raw === "object") {
|
|
31742
|
+
const obj = raw;
|
|
31743
|
+
if (typeof obj.serviceEndpoint === "string" && /^https?:/i.test(obj.serviceEndpoint)) {
|
|
31744
|
+
return obj.serviceEndpoint;
|
|
31745
|
+
}
|
|
31746
|
+
if (typeof obj.proof === "string") {
|
|
31747
|
+
const cid = extractCid(obj.proof);
|
|
31748
|
+
if (cid) return `${IPFS_GATEWAY}${cid}`;
|
|
31749
|
+
}
|
|
31750
|
+
if (typeof obj.id === "string") {
|
|
31751
|
+
const hashIdx = obj.id.indexOf("#");
|
|
31752
|
+
const tail = hashIdx >= 0 ? obj.id.slice(hashIdx + 1) : obj.id;
|
|
31753
|
+
const cid = extractCid(tail);
|
|
31754
|
+
if (cid) return `${IPFS_GATEWAY}${cid}`;
|
|
31755
|
+
}
|
|
31756
|
+
if (typeof obj.content === "string") {
|
|
31757
|
+
return resolveClaimFileRef(obj.content);
|
|
31758
|
+
}
|
|
31759
|
+
if (typeof obj.url === "string" && /^https?:/i.test(obj.url)) {
|
|
31760
|
+
return obj.url;
|
|
31761
|
+
}
|
|
31762
|
+
}
|
|
31763
|
+
return null;
|
|
31764
|
+
}
|
|
31765
|
+
function isFileLike(value) {
|
|
31766
|
+
if (Array.isArray(value)) {
|
|
31767
|
+
return value.length > 0 && value.every((v) => v && typeof v === "object" && typeof v.content === "string");
|
|
31768
|
+
}
|
|
31769
|
+
return !!value && typeof value === "object" && typeof value.content === "string";
|
|
31770
|
+
}
|
|
31771
|
+
function resolveOneFileEntry(entry) {
|
|
31772
|
+
const resolved = resolveClaimFileRef(entry.content);
|
|
31773
|
+
if (resolved && resolved !== entry.content) {
|
|
31774
|
+
return { ...entry, content: resolved };
|
|
31775
|
+
}
|
|
31776
|
+
return entry;
|
|
31777
|
+
}
|
|
31778
|
+
function resolveFilesInCredentialSubject(subject) {
|
|
31779
|
+
if (!subject || typeof subject !== "object") return subject;
|
|
31780
|
+
const out = Array.isArray(subject) ? [...subject] : { ...subject };
|
|
31781
|
+
for (const [key, value] of Object.entries(subject)) {
|
|
31782
|
+
if (!isFileLike(value)) continue;
|
|
31783
|
+
if (Array.isArray(value)) {
|
|
31784
|
+
out[key] = value.map((v) => resolveOneFileEntry(v));
|
|
31785
|
+
} else {
|
|
31786
|
+
out[key] = resolveOneFileEntry(value);
|
|
31787
|
+
}
|
|
31788
|
+
}
|
|
31789
|
+
return out;
|
|
31790
|
+
}
|
|
31791
|
+
|
|
31792
|
+
// src/mantine/blocks/action/actionTypes/_shared/media/mediaNaming.ts
|
|
31793
|
+
var MEDIA_DIR = "media";
|
|
31794
|
+
var MEDIA_SEPARATOR = "__";
|
|
31795
|
+
var SEQ_DIGITS = 4;
|
|
31796
|
+
var REF_MAX = 14;
|
|
31797
|
+
var FIELD_MAX = 32;
|
|
31798
|
+
var NAME_MAX = 48;
|
|
31799
|
+
var WINDOWS_RESERVED = /^(con|prn|aux|nul|com\d|lpt\d)$/i;
|
|
31800
|
+
function sanitizeSegment(value, maxLength) {
|
|
31801
|
+
const out = String(value ?? "").replace(/[^A-Za-z0-9.-]+/g, "-").replace(/-{2,}/g, "-").replace(/^[-.]+|[-.]+$/g, "").slice(0, maxLength).replace(/[-.]+$/g, "");
|
|
31802
|
+
return out;
|
|
31803
|
+
}
|
|
31804
|
+
function splitExtension(fileName) {
|
|
31805
|
+
const dot = fileName.lastIndexOf(".");
|
|
31806
|
+
if (dot <= 0 || dot === fileName.length - 1) return { stem: fileName, ext: "" };
|
|
31807
|
+
const ext = fileName.slice(dot + 1);
|
|
31808
|
+
if (!/^[A-Za-z0-9]{1,5}$/.test(ext)) return { stem: fileName, ext: "" };
|
|
31809
|
+
return { stem: fileName.slice(0, dot), ext };
|
|
31810
|
+
}
|
|
31811
|
+
var MIME_EXTENSIONS = {
|
|
31812
|
+
"image/jpeg": "jpg",
|
|
31813
|
+
"image/jpg": "jpg",
|
|
31814
|
+
"image/png": "png",
|
|
31815
|
+
"image/gif": "gif",
|
|
31816
|
+
"image/webp": "webp",
|
|
31817
|
+
"image/svg+xml": "svg",
|
|
31818
|
+
"image/bmp": "bmp",
|
|
31819
|
+
"image/heic": "heic",
|
|
31820
|
+
"application/pdf": "pdf",
|
|
31821
|
+
"application/msword": "doc",
|
|
31822
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
|
|
31823
|
+
"application/vnd.ms-excel": "xls",
|
|
31824
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
|
|
31825
|
+
"text/plain": "txt",
|
|
31826
|
+
"text/csv": "csv",
|
|
31827
|
+
"video/mp4": "mp4",
|
|
31828
|
+
"video/webm": "webm",
|
|
31829
|
+
"video/quicktime": "mov",
|
|
31830
|
+
"audio/mpeg": "mp3",
|
|
31831
|
+
"audio/wav": "wav",
|
|
31832
|
+
"audio/ogg": "ogg"
|
|
31833
|
+
};
|
|
31834
|
+
function resolveExtension(originalName, mimeType) {
|
|
31835
|
+
const key = String(mimeType || "").split(";")[0].trim().toLowerCase();
|
|
31836
|
+
const fromMime = MIME_EXTENSIONS[key];
|
|
31837
|
+
if (fromMime) return fromMime;
|
|
31838
|
+
const fromName = splitExtension(originalName).ext;
|
|
31839
|
+
return fromName ? fromName.toLowerCase() : "bin";
|
|
31840
|
+
}
|
|
31841
|
+
function buildMediaFileName(parts) {
|
|
31842
|
+
const seq = String(Math.max(0, Math.trunc(parts.seq))).padStart(SEQ_DIGITS, "0");
|
|
31843
|
+
const ref = sanitizeSegment(parts.recordId, REF_MAX) || "record";
|
|
31844
|
+
const field = sanitizeSegment(parts.fieldName, FIELD_MAX) || "field";
|
|
31845
|
+
const idx = String(Math.max(1, Math.trunc(parts.fileIndex))).padStart(2, "0");
|
|
31846
|
+
const original = String(parts.originalName || "").trim();
|
|
31847
|
+
const { stem } = splitExtension(original);
|
|
31848
|
+
let name = sanitizeSegment(stem, NAME_MAX);
|
|
31849
|
+
if (!name || WINDOWS_RESERVED.test(name)) name = "file";
|
|
31850
|
+
const ext = resolveExtension(original, parts.mimeType);
|
|
31851
|
+
return [seq, ref, field, idx, name].join(MEDIA_SEPARATOR) + `.${ext}`;
|
|
31852
|
+
}
|
|
31853
|
+
function buildMediaPath(parts) {
|
|
31854
|
+
return `${MEDIA_DIR}/${buildMediaFileName(parts)}`;
|
|
31855
|
+
}
|
|
31856
|
+
function dedupeMediaPath(path, taken) {
|
|
31857
|
+
if (!taken.has(path)) {
|
|
31858
|
+
taken.add(path);
|
|
31859
|
+
return path;
|
|
31860
|
+
}
|
|
31861
|
+
const dot = path.lastIndexOf(".");
|
|
31862
|
+
const stem = dot > 0 ? path.slice(0, dot) : path;
|
|
31863
|
+
const ext = dot > 0 ? path.slice(dot) : "";
|
|
31864
|
+
for (let n = 2; n < 1e3; n += 1) {
|
|
31865
|
+
const candidate = `${stem}-${n}${ext}`;
|
|
31866
|
+
if (!taken.has(candidate)) {
|
|
31867
|
+
taken.add(candidate);
|
|
31868
|
+
return candidate;
|
|
31869
|
+
}
|
|
31870
|
+
}
|
|
31871
|
+
throw new Error(`Unable to find a unique archive path for ${path}`);
|
|
31872
|
+
}
|
|
31873
|
+
|
|
31874
|
+
// src/mantine/blocks/action/actionTypes/_shared/media/collectMedia.ts
|
|
31875
|
+
function isFileEntry(value) {
|
|
31876
|
+
return !!value && typeof value === "object" && typeof value.content === "string";
|
|
31877
|
+
}
|
|
31878
|
+
function fileEntriesOf(value) {
|
|
31879
|
+
if (Array.isArray(value)) return value.filter(isFileEntry);
|
|
31880
|
+
return isFileEntry(value) ? [value] : [];
|
|
31881
|
+
}
|
|
31882
|
+
function collectRecordMedia(answers, record, options = {}) {
|
|
31883
|
+
if (!answers || typeof answers !== "object") return [];
|
|
31884
|
+
const taken = options.takenPaths ?? /* @__PURE__ */ new Set();
|
|
31885
|
+
const titles = options.titlesByFieldName ?? {};
|
|
31886
|
+
const refs = [];
|
|
31887
|
+
for (const [fieldName, value] of Object.entries(answers)) {
|
|
31888
|
+
const entries = fileEntriesOf(value);
|
|
31889
|
+
if (entries.length === 0) continue;
|
|
31890
|
+
entries.forEach((entry, index) => {
|
|
31891
|
+
const sourceUrl = resolveClaimFileRef(entry.content);
|
|
31892
|
+
if (!sourceUrl) return;
|
|
31893
|
+
const originalName = typeof entry.name === "string" ? entry.name : "";
|
|
31894
|
+
const mimeType = typeof entry.type === "string" ? entry.type : "";
|
|
31895
|
+
const fileIndex = index + 1;
|
|
31896
|
+
const archivePath = dedupeMediaPath(buildMediaPath({ seq: record.seq, recordId: record.recordId, fieldName, fileIndex, originalName, mimeType }), taken);
|
|
31897
|
+
refs.push({
|
|
31898
|
+
seq: record.seq,
|
|
31899
|
+
recordId: record.recordId,
|
|
31900
|
+
fieldName,
|
|
31901
|
+
fieldTitle: titles[fieldName] || fieldName,
|
|
31902
|
+
fileIndex,
|
|
31903
|
+
originalName,
|
|
31904
|
+
mimeType,
|
|
31905
|
+
sourceUrl,
|
|
31906
|
+
archivePath
|
|
31907
|
+
});
|
|
31908
|
+
});
|
|
31909
|
+
}
|
|
31910
|
+
return refs;
|
|
31911
|
+
}
|
|
31912
|
+
function replaceFileValuesWithPaths(answers, refs, failedPaths) {
|
|
31913
|
+
if (refs.length === 0) return answers;
|
|
31914
|
+
const byField = /* @__PURE__ */ new Map();
|
|
31915
|
+
for (const ref of refs) {
|
|
31916
|
+
const list = byField.get(ref.fieldName) || [];
|
|
31917
|
+
list.push(failedPaths?.has(ref.archivePath) ? `${ref.originalName || ref.archivePath} (download failed \u2014 not in archive)` : ref.archivePath);
|
|
31918
|
+
byField.set(ref.fieldName, list);
|
|
31919
|
+
}
|
|
31920
|
+
const out = { ...answers };
|
|
31921
|
+
for (const [fieldName, paths] of byField) out[fieldName] = paths.join("; ");
|
|
31922
|
+
return out;
|
|
31923
|
+
}
|
|
31924
|
+
|
|
31925
|
+
// src/mantine/blocks/action/actionTypes/_shared/dataExport/buildExportBundle.ts
|
|
31926
|
+
var DEFAULT_CONCURRENCY = 6;
|
|
31927
|
+
async function mapWithLimit(items, limit, worker) {
|
|
31928
|
+
const results = new Array(items.length);
|
|
31929
|
+
let cursor = 0;
|
|
31930
|
+
const runners = Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, async () => {
|
|
31931
|
+
for (; ; ) {
|
|
31932
|
+
const index = cursor;
|
|
31933
|
+
cursor += 1;
|
|
31934
|
+
if (index >= items.length) return;
|
|
31935
|
+
results[index] = await worker(items[index], index);
|
|
31936
|
+
}
|
|
31937
|
+
});
|
|
31938
|
+
await Promise.all(runners);
|
|
31939
|
+
return results;
|
|
31940
|
+
}
|
|
31941
|
+
async function downloadMedia(ref, fetchMedia) {
|
|
31942
|
+
try {
|
|
31943
|
+
let blob;
|
|
31944
|
+
if (fetchMedia) {
|
|
31945
|
+
blob = await fetchMedia(ref.sourceUrl);
|
|
31946
|
+
} else {
|
|
31947
|
+
const response = await fetch(ref.sourceUrl);
|
|
31948
|
+
if (!response.ok) throw new Error(`gateway returned ${response.status} ${response.statusText}`.trim());
|
|
31949
|
+
blob = await response.blob();
|
|
31950
|
+
}
|
|
31951
|
+
return { bytes: new Uint8Array(await blob.arrayBuffer()), reason: "" };
|
|
31952
|
+
} catch (err) {
|
|
31953
|
+
return { bytes: null, reason: err instanceof Error ? err.message : "download failed" };
|
|
31954
|
+
}
|
|
31955
|
+
}
|
|
31956
|
+
async function buildExportBundle(params) {
|
|
31957
|
+
const takenPaths = /* @__PURE__ */ new Set();
|
|
31958
|
+
const refs = [];
|
|
31959
|
+
const refsByRecordId = /* @__PURE__ */ new Map();
|
|
31960
|
+
params.records.forEach((record, index) => {
|
|
31961
|
+
const recordRefs = collectRecordMedia(record.answers, { seq: index + 1, recordId: record.recordId }, { titlesByFieldName: params.titlesByFieldName, takenPaths });
|
|
31962
|
+
refs.push(...recordRefs);
|
|
31963
|
+
refsByRecordId.set(record.recordId, recordRefs);
|
|
31964
|
+
});
|
|
31965
|
+
const manifestByRecordId = new Map(params.records.map((record) => [record.recordId, record.manifest ?? {}]));
|
|
31966
|
+
const downloads = await mapWithLimit(refs, params.concurrency ?? DEFAULT_CONCURRENCY, (ref) => downloadMedia(ref, params.fetchMedia));
|
|
31967
|
+
const failedPaths = new Set(refs.filter((_, index) => !downloads[index].bytes).map((ref) => ref.archivePath));
|
|
31968
|
+
const answersByRecordId = {};
|
|
31969
|
+
for (const record of params.records) {
|
|
31970
|
+
answersByRecordId[record.recordId] = replaceFileValuesWithPaths(record.answers, refsByRecordId.get(record.recordId) ?? [], failedPaths);
|
|
31971
|
+
}
|
|
31972
|
+
const entries = [];
|
|
31973
|
+
const manifestRows = [];
|
|
31974
|
+
const failures = [];
|
|
31975
|
+
refs.forEach((ref, index) => {
|
|
31976
|
+
const { bytes, reason } = downloads[index];
|
|
31977
|
+
if (bytes) {
|
|
31978
|
+
entries.push({ path: ref.archivePath, data: bytes });
|
|
31979
|
+
} else {
|
|
31980
|
+
failures.push({ archivePath: ref.archivePath, sourceUrl: ref.sourceUrl, reason });
|
|
31981
|
+
}
|
|
31982
|
+
manifestRows.push({
|
|
31983
|
+
archivePath: bytes ? ref.archivePath : "",
|
|
31984
|
+
...manifestByRecordId.get(ref.recordId),
|
|
31985
|
+
recordId: ref.recordId,
|
|
31986
|
+
fieldName: ref.fieldName,
|
|
31987
|
+
fieldTitle: ref.fieldTitle,
|
|
31988
|
+
fileIndex: ref.fileIndex,
|
|
31989
|
+
originalName: ref.originalName,
|
|
31990
|
+
mimeType: ref.mimeType,
|
|
31991
|
+
sizeBytes: bytes ? bytes.length : "",
|
|
31992
|
+
sourceUrl: ref.sourceUrl,
|
|
31993
|
+
downloadStatus: bytes ? "ok" : "failed",
|
|
31994
|
+
downloadError: reason
|
|
31995
|
+
});
|
|
31996
|
+
});
|
|
31997
|
+
entries.unshift({ path: params.csvName, data: UTF8_BOM + params.renderCsv(answersByRecordId) });
|
|
31998
|
+
entries.splice(1, 0, {
|
|
31999
|
+
path: params.manifestName || "media-manifest.csv",
|
|
32000
|
+
data: UTF8_BOM + (manifestRows.length > 0 ? rowsToCsv(manifestRows) : "note\r\nNo media was submitted for these records.")
|
|
32001
|
+
});
|
|
32002
|
+
return { blob: createZipBlob(entries), mediaTotal: refs.length, mediaFailed: failures.length, failures };
|
|
32003
|
+
}
|
|
32004
|
+
|
|
32005
|
+
// src/mantine/blocks/action/actionTypes/_shared/dataExport/exportFileNames.ts
|
|
32006
|
+
var slug = (value, fallback) => value ? String(value).replace(/[^A-Za-z0-9._-]+/g, "-") : fallback;
|
|
32007
|
+
var exportFileNames = {
|
|
32008
|
+
claims(collectionId) {
|
|
32009
|
+
const id = slug(collectionId, "collection");
|
|
32010
|
+
return { csv: `claims-${id}.csv`, manifest: `media-manifest-${id}.csv`, zip: `claims-${id}-${timestampSuffix()}.zip` };
|
|
32011
|
+
},
|
|
32012
|
+
claim(claimId) {
|
|
32013
|
+
const id = slug(claimId, "claim").slice(0, 20);
|
|
32014
|
+
return { csv: `claim-${id}.csv`, manifest: `media-manifest-${id}.csv`, zip: `claim-${id}-${timestampSuffix()}.zip` };
|
|
32015
|
+
},
|
|
32016
|
+
bids(collectionId) {
|
|
32017
|
+
const id = slug(collectionId, "collection");
|
|
32018
|
+
return { csv: `bids-${id}.csv`, manifest: `media-manifest-${id}.csv`, zip: `bids-${id}-${timestampSuffix()}.zip` };
|
|
32019
|
+
},
|
|
32020
|
+
bid(bidId) {
|
|
32021
|
+
const id = slug(bidId, "bid").slice(0, 20);
|
|
32022
|
+
return { csv: `bid-${id}.csv`, manifest: `media-manifest-${id}.csv`, zip: `bid-${id}-${timestampSuffix()}.zip` };
|
|
32023
|
+
},
|
|
32024
|
+
collectionMembers(collectionId) {
|
|
32025
|
+
const id = slug(collectionId, "collection");
|
|
32026
|
+
return { csv: `collection-members-${id}.csv`, manifest: `media-manifest-${id}.csv`, zip: `collection-members-${id}-${timestampSuffix()}.zip` };
|
|
32027
|
+
}
|
|
32028
|
+
};
|
|
32029
|
+
|
|
31462
32030
|
// src/mantine/blocks/action/actionTypes/_shared/ReadableKeyValues.tsx
|
|
31463
32031
|
import React313, { useState as useState163 } from "react";
|
|
31464
32032
|
import { Group as Group110, Stack as Stack204, Text as Text192, UnstyledButton as UnstyledButton3 } from "@mantine/core";
|
|
@@ -31609,6 +32177,34 @@ var ReadableKeyValues = ({ data }) => {
|
|
|
31609
32177
|
return /* @__PURE__ */ React313.createElement(React313.Fragment, null, /* @__PURE__ */ React313.createElement(Stack204, { gap: "xs" }, Object.entries(data).map(([key, value]) => /* @__PURE__ */ React313.createElement(Group110, { key, justify: "space-between", align: "flex-start", wrap: "nowrap", gap: "md" }, /* @__PURE__ */ React313.createElement(Text192, { size: "xs", c: "dimmed", style: { flexShrink: 0 } }, humanizeKey(key)), renderValue(value, setActiveFile)))), /* @__PURE__ */ React313.createElement(MediaPreviewModal, { file: activeFile, onClose: () => setActiveFile(null) }));
|
|
31610
32178
|
};
|
|
31611
32179
|
|
|
32180
|
+
// src/mantine/blocks/action/actionTypes/_shared/bids/fetchAllBids.ts
|
|
32181
|
+
var MAX_PAGES = 200;
|
|
32182
|
+
async function fetchAllBids(queryBids, params, options) {
|
|
32183
|
+
const maxPages = options?.maxPages ?? MAX_PAGES;
|
|
32184
|
+
const bids = [];
|
|
32185
|
+
const seenTokens = /* @__PURE__ */ new Set();
|
|
32186
|
+
let nextPageToken;
|
|
32187
|
+
let pages = 0;
|
|
32188
|
+
for (; ; ) {
|
|
32189
|
+
const response = await queryBids({ ...params, ...nextPageToken ? { pagination: { nextPageToken } } : {} });
|
|
32190
|
+
pages += 1;
|
|
32191
|
+
if (Array.isArray(response?.data)) bids.push(...response.data);
|
|
32192
|
+
nextPageToken = response?.nextPageToken;
|
|
32193
|
+
if (!nextPageToken) return { bids, truncated: false, pages };
|
|
32194
|
+
if (seenTokens.has(nextPageToken)) return { bids, truncated: true, pages };
|
|
32195
|
+
seenTokens.add(nextPageToken);
|
|
32196
|
+
if (pages >= maxPages) return { bids, truncated: true, pages };
|
|
32197
|
+
}
|
|
32198
|
+
}
|
|
32199
|
+
function dedupeBids(bids) {
|
|
32200
|
+
const seen = /* @__PURE__ */ new Set();
|
|
32201
|
+
return bids.filter((bid) => {
|
|
32202
|
+
if (seen.has(bid.id)) return false;
|
|
32203
|
+
seen.add(bid.id);
|
|
32204
|
+
return true;
|
|
32205
|
+
});
|
|
32206
|
+
}
|
|
32207
|
+
|
|
31612
32208
|
// src/mantine/blocks/action/actionTypes/evaluateBid/EvaluateBidFlowDetail.tsx
|
|
31613
32209
|
function getRoleColor2(role) {
|
|
31614
32210
|
const r = String(role || "").toLowerCase();
|
|
@@ -31656,14 +32252,14 @@ function truncateAddress2(address) {
|
|
|
31656
32252
|
if (address.length <= 14) return address;
|
|
31657
32253
|
return `${address.slice(0, 8)}...${address.slice(-3)}`;
|
|
31658
32254
|
}
|
|
31659
|
-
function getBidStatus(bid, translate) {
|
|
31660
|
-
|
|
31661
|
-
|
|
31662
|
-
|
|
31663
|
-
|
|
31664
|
-
|
|
31665
|
-
}
|
|
31666
|
-
return { label:
|
|
32255
|
+
function getBidStatus(bid, translate, context) {
|
|
32256
|
+
const info = getBidStatusInfo(bid, context);
|
|
32257
|
+
const labels = {
|
|
32258
|
+
approved: translate("actionTypes.evaluateBid.flow.status.approved", { defaultValue: "Approved" }),
|
|
32259
|
+
rejected: translate("actionTypes.evaluateBid.flow.status.rejected", { defaultValue: "Rejected" }),
|
|
32260
|
+
pending: translate("actionTypes.evaluateBid.flow.status.pending", { defaultValue: "Pending" })
|
|
32261
|
+
};
|
|
32262
|
+
return { label: labels[info.key], key: info.key, color: info.color };
|
|
31667
32263
|
}
|
|
31668
32264
|
var EvaluateBidFlowDetail = ({
|
|
31669
32265
|
inputs,
|
|
@@ -31700,33 +32296,56 @@ var EvaluateBidFlowDetail = ({
|
|
|
31700
32296
|
const [activeFilter, setActiveFilter] = useState164("pending");
|
|
31701
32297
|
const [paymentRows, setPaymentRows] = useState164([createPaymentRow()]);
|
|
31702
32298
|
const [profilesByDid, setProfilesByDid] = useState164({});
|
|
32299
|
+
const [grantees, setGrantees] = useState164([]);
|
|
31703
32300
|
const selectedBid = useMemo114(() => bids.find((bid) => bid.id === selectedBidId) || null, [bids, selectedBidId]);
|
|
32301
|
+
const statusContext = useMemo114(() => ({ grantees }), [grantees]);
|
|
32302
|
+
const statusCounts = useMemo114(() => {
|
|
32303
|
+
const counts = { approved: 0, rejected: 0, pending: 0 };
|
|
32304
|
+
for (const bid of bids) counts[getBidStatusInfo(bid, statusContext).key] += 1;
|
|
32305
|
+
return counts;
|
|
32306
|
+
}, [bids, statusContext]);
|
|
31704
32307
|
const filteredBids = useMemo114(() => {
|
|
31705
32308
|
if (activeFilter === "all") return bids;
|
|
31706
|
-
return bids.filter((bid) => getBidStatus(bid, t).key === activeFilter);
|
|
31707
|
-
}, [bids, activeFilter]);
|
|
32309
|
+
return bids.filter((bid) => getBidStatus(bid, t, statusContext).key === activeFilter);
|
|
32310
|
+
}, [bids, activeFilter, t, statusContext]);
|
|
32311
|
+
const fetchGrantees = useCallback106(
|
|
32312
|
+
async (adminAddressForList) => {
|
|
32313
|
+
const listGrantees = handlersRef.current.collectionUsers?.list;
|
|
32314
|
+
if (typeof listGrantees !== "function" || !adminAddressForList) return [];
|
|
32315
|
+
try {
|
|
32316
|
+
const result = await listGrantees({ granterAdminAddress: adminAddressForList, collectionId });
|
|
32317
|
+
return Array.isArray(result?.grantees) ? result.grantees : [];
|
|
32318
|
+
} catch {
|
|
32319
|
+
return [];
|
|
32320
|
+
}
|
|
32321
|
+
},
|
|
32322
|
+
[collectionId]
|
|
32323
|
+
);
|
|
31708
32324
|
const refreshBids = useCallback106(async () => {
|
|
31709
32325
|
if (!deedDid || !collectionId) return;
|
|
31710
32326
|
const handlers2 = handlersRef.current;
|
|
31711
32327
|
setLoadingBids(true);
|
|
31712
32328
|
setError(null);
|
|
31713
32329
|
try {
|
|
31714
|
-
const [
|
|
31715
|
-
const fetchedBids =
|
|
32330
|
+
const [bidsResult, collectionsResponse] = await Promise.all([fetchAllBids(handlers2.queryBids, { collectionId, entityDid: deedDid }), handlers2.getClaimCollections(deedDid)]);
|
|
32331
|
+
const fetchedBids = dedupeBids(bidsResult.bids);
|
|
31716
32332
|
setBids(fetchedBids);
|
|
32333
|
+
if (bidsResult.truncated) setError("Bid paging stopped early \u2014 this list may be incomplete.");
|
|
31717
32334
|
if (selectedBidId && !fetchedBids.some((bid) => bid.id === selectedBidId)) {
|
|
31718
32335
|
setSelectedBidId("");
|
|
31719
32336
|
}
|
|
31720
32337
|
const resolvedAdmin = collectionsResponse?.collections?.find?.((c) => c?.id === collectionId)?.admin || collectionsResponse?.adminAddress || "";
|
|
31721
32338
|
setAdminAddress(resolvedAdmin);
|
|
32339
|
+
setGrantees(await fetchGrantees(resolvedAdmin));
|
|
31722
32340
|
} catch (err) {
|
|
31723
32341
|
setBids([]);
|
|
31724
32342
|
setAdminAddress("");
|
|
32343
|
+
setGrantees([]);
|
|
31725
32344
|
setError(err instanceof Error ? err.message : t("actionTypes.evaluateBid.flow.errors.loadBids", { defaultValue: "Failed to load bids" }));
|
|
31726
32345
|
} finally {
|
|
31727
32346
|
setLoadingBids(false);
|
|
31728
32347
|
}
|
|
31729
|
-
}, [deedDid, collectionId, selectedBidId]);
|
|
32348
|
+
}, [deedDid, collectionId, selectedBidId, fetchGrantees]);
|
|
31730
32349
|
useEffect109(() => {
|
|
31731
32350
|
setSelectedBidId("");
|
|
31732
32351
|
setRejectReason("");
|
|
@@ -31741,23 +32360,52 @@ var EvaluateBidFlowDetail = ({
|
|
|
31741
32360
|
if (!deedDid || !collectionId) return;
|
|
31742
32361
|
refreshBids();
|
|
31743
32362
|
}, [deedDid, collectionId, refreshBids]);
|
|
32363
|
+
const bidRowOptions = useCallback106(
|
|
32364
|
+
(freshGrantees) => ({
|
|
32365
|
+
namesByDid: Object.fromEntries(Object.entries(profilesByDid).map(([did, profile]) => [did, profile?.displayname || ""])),
|
|
32366
|
+
grantees: freshGrantees
|
|
32367
|
+
}),
|
|
32368
|
+
[profilesByDid]
|
|
32369
|
+
);
|
|
31744
32370
|
const downloadBidsCsv = useCallback106(
|
|
31745
32371
|
async (subset, filename) => {
|
|
31746
|
-
|
|
31747
|
-
|
|
31748
|
-
|
|
31749
|
-
|
|
31750
|
-
|
|
31751
|
-
|
|
31752
|
-
|
|
31753
|
-
|
|
31754
|
-
|
|
32372
|
+
const freshGrantees = await fetchGrantees(adminAddress) || grantees;
|
|
32373
|
+
downloadArrayAsCsv(buildBidRows(subset, freshGrantees, bidRowOptions(freshGrantees)), { filename });
|
|
32374
|
+
},
|
|
32375
|
+
[adminAddress, fetchGrantees, grantees, bidRowOptions]
|
|
32376
|
+
);
|
|
32377
|
+
const downloadBidsZip = useCallback106(
|
|
32378
|
+
async (subset, names) => {
|
|
32379
|
+
const handlers2 = handlersRef.current;
|
|
32380
|
+
const freshGrantees = await fetchGrantees(adminAddress) || grantees;
|
|
32381
|
+
const fetchMedia = handlers2.fetchClaimMedia ? (url) => handlers2.fetchClaimMedia(url, { entityDid: deedDid }) : void 0;
|
|
32382
|
+
const { blob, mediaTotal, mediaFailed } = await buildExportBundle({
|
|
32383
|
+
records: subset.map((bid) => ({
|
|
32384
|
+
recordId: bid.id,
|
|
32385
|
+
answers: bidAnswers(bid),
|
|
32386
|
+
manifest: {
|
|
32387
|
+
bidId: bid.id,
|
|
32388
|
+
did: bid.did,
|
|
32389
|
+
address: bid.address,
|
|
32390
|
+
role: bid.role,
|
|
32391
|
+
created: bid.created,
|
|
32392
|
+
status: getBidStatusInfo(bid, { grantees: freshGrantees }).key
|
|
32393
|
+
}
|
|
32394
|
+
})),
|
|
32395
|
+
fetchMedia,
|
|
32396
|
+
renderCsv: (answersByBidId) => rowsToCsv(buildBidRows(subset, freshGrantees, { ...bidRowOptions(freshGrantees), answersByBidId })),
|
|
32397
|
+
csvName: names.csv,
|
|
32398
|
+
manifestName: names.manifest
|
|
32399
|
+
});
|
|
32400
|
+
downloadBlob(blob, names.zip);
|
|
32401
|
+
if (mediaFailed > 0) {
|
|
32402
|
+
setError(`${mediaFailed} of ${mediaTotal} media files could not be downloaded \u2014 see downloadStatus in ${names.manifest}.`);
|
|
31755
32403
|
}
|
|
31756
|
-
downloadArrayAsCsv(buildBidRows(subset, grantees), { filename });
|
|
31757
32404
|
},
|
|
31758
|
-
[adminAddress,
|
|
32405
|
+
[adminAddress, fetchGrantees, grantees, bidRowOptions, deedDid]
|
|
31759
32406
|
);
|
|
31760
|
-
const handleDownloadBidsCsv = useCallback106(() => downloadBidsCsv(bids,
|
|
32407
|
+
const handleDownloadBidsCsv = useCallback106(() => downloadBidsCsv(bids, exportFileNames.bids(collectionId).csv), [downloadBidsCsv, bids, collectionId]);
|
|
32408
|
+
const handleDownloadBidsZip = useCallback106(() => downloadBidsZip(bids, exportFileNames.bids(collectionId)), [downloadBidsZip, bids, collectionId]);
|
|
31761
32409
|
useEffect109(() => {
|
|
31762
32410
|
let mounted = true;
|
|
31763
32411
|
const dids = Array.from(new Set(bids.map((bid) => bid.did).filter(Boolean)));
|
|
@@ -31887,7 +32535,7 @@ var EvaluateBidFlowDetail = ({
|
|
|
31887
32535
|
});
|
|
31888
32536
|
}, [provideSigningHandler, selectedBid, decision, adminAddress, rejectReason, collectionId, deedDid, buildMaxAmounts2, refreshBids, executeAction]);
|
|
31889
32537
|
if (selectedBid) {
|
|
31890
|
-
const bidStatus = getBidStatus(selectedBid, t);
|
|
32538
|
+
const bidStatus = getBidStatus(selectedBid, t, statusContext);
|
|
31891
32539
|
const bidRole = String(selectedBid.role || "").toLowerCase();
|
|
31892
32540
|
const bidIsEvaluator = bidRole === "evaluation_agent" || bidRole === "ea";
|
|
31893
32541
|
const selectedBidProfile = profilesByDid[selectedBid.did];
|
|
@@ -31898,7 +32546,7 @@ var EvaluateBidFlowDetail = ({
|
|
|
31898
32546
|
bidData = typeof selectedBid.data === "string" ? JSON.parse(selectedBid.data) : selectedBid.data;
|
|
31899
32547
|
} catch {
|
|
31900
32548
|
}
|
|
31901
|
-
return /* @__PURE__ */ React314.createElement(Stack205, { gap: "md" }, /* @__PURE__ */ React314.createElement(Group111, { gap: "xs", align: "center" }, /* @__PURE__ */ React314.createElement(ActionIcon45, { variant: "subtle", color: "gray", size: "sm", onClick: () => setSelectedBidId("") }, /* @__PURE__ */ React314.createElement(IconArrowLeft8, { size: 16 })), /* @__PURE__ */ React314.createElement(Text193, { fw: 500, size: "sm", truncate: true, style: { flex: 1, minWidth: 0 } }, t("actionTypes.evaluateBid.flow.bidNumber", { id: selectedBid.id, defaultValue: `Bid #${selectedBid.id}` })), /* @__PURE__ */ React314.createElement(DownloadCsvButton, { onDownload: () => downloadBidsCsv([selectedBid],
|
|
32549
|
+
return /* @__PURE__ */ React314.createElement(Stack205, { gap: "md" }, /* @__PURE__ */ React314.createElement(Group111, { gap: "xs", align: "center" }, /* @__PURE__ */ React314.createElement(ActionIcon45, { variant: "subtle", color: "gray", size: "sm", onClick: () => setSelectedBidId("") }, /* @__PURE__ */ React314.createElement(IconArrowLeft8, { size: 16 })), /* @__PURE__ */ React314.createElement(Text193, { fw: 500, size: "sm", truncate: true, style: { flex: 1, minWidth: 0 } }, t("actionTypes.evaluateBid.flow.bidNumber", { id: selectedBid.id, defaultValue: `Bid #${selectedBid.id}` })), /* @__PURE__ */ React314.createElement(DownloadCsvButton, { onDownload: () => downloadBidsCsv([selectedBid], exportFileNames.bid(selectedBid.id).csv), label: "Download bid CSV", onError: setError }), /* @__PURE__ */ React314.createElement(DownloadZipButton, { onDownload: () => downloadBidsZip([selectedBid], exportFileNames.bid(selectedBid.id)), label: "Download bid + media (ZIP)", onError: setError })), /* @__PURE__ */ React314.createElement(Group111, { gap: 16, align: "center", style: { width: "100%" } }, /* @__PURE__ */ React314.createElement(
|
|
31902
32550
|
Box57,
|
|
31903
32551
|
{
|
|
31904
32552
|
style: {
|
|
@@ -31973,7 +32621,12 @@ var EvaluateBidFlowDetail = ({
|
|
|
31973
32621
|
}
|
|
31974
32622
|
))), /* @__PURE__ */ React314.createElement(Button62, { variant: "light", size: "xs", onClick: addPaymentRow, disabled: isDisabled || submitting }, t("actionTypes.evaluateClaim.flow.payment.addPayment", { defaultValue: "Add Payment" }))))), error && /* @__PURE__ */ React314.createElement(DismissibleAlert, { color: "red", styles: actionAlertStyles }, error));
|
|
31975
32623
|
}
|
|
31976
|
-
const filterTabs = [
|
|
32624
|
+
const filterTabs = [
|
|
32625
|
+
{ value: "pending", label: t("actionTypes.evaluateBid.flow.status.pending", { defaultValue: "Pending" }) },
|
|
32626
|
+
...statusCounts.approved > 0 ? [{ value: "approved", label: t("actionTypes.evaluateBid.flow.status.approved", { defaultValue: "Approved" }) }] : [],
|
|
32627
|
+
...statusCounts.rejected > 0 ? [{ value: "rejected", label: t("actionTypes.evaluateBid.flow.status.rejected", { defaultValue: "Rejected" }) }] : [],
|
|
32628
|
+
...statusCounts.approved > 0 || statusCounts.rejected > 0 ? [{ value: "all", label: t("actionTypes.evaluateBid.flow.status.all", { defaultValue: "All" }) }] : []
|
|
32629
|
+
];
|
|
31977
32630
|
return /* @__PURE__ */ React314.createElement(Stack205, { gap: "md" }, /* @__PURE__ */ React314.createElement(GroupProposalStatus, { editor, block, runtime }), runtime?.state !== "awaiting_readback" && /* @__PURE__ */ React314.createElement(ActAsGroupSection, { value: actAs, onChange: setActAs, isDisabled, actionLabel: "decide this application" }), !deedDid || !collectionId ? /* @__PURE__ */ React314.createElement(DismissibleAlert, { color: "yellow", styles: actionAlertStyles }, t("actionTypes.shared.errors.configRequired", {
|
|
31978
32631
|
defaultValue: "Configure {{did}} and {{claimCollection}} in template mode before running this action.",
|
|
31979
32632
|
did: "DID",
|
|
@@ -31992,8 +32645,8 @@ var EvaluateBidFlowDetail = ({
|
|
|
31992
32645
|
}
|
|
31993
32646
|
},
|
|
31994
32647
|
/* @__PURE__ */ React314.createElement(Text193, { size: "sm", fw: 500, c: activeFilter === tab.value ? "var(--mantine-color-text)" : "dimmed" }, tab.label)
|
|
31995
|
-
))), /* @__PURE__ */ React314.createElement(Group111, { gap: 4 }, /* @__PURE__ */ React314.createElement(DownloadCsvButton, { onDownload: handleDownloadBidsCsv, disabled: loadingBids || bids.length === 0, label: "Download bids CSV" }), /* @__PURE__ */ React314.createElement(ActionIcon45, { variant: "subtle", color: "gray", size: "sm" }, /* @__PURE__ */ React314.createElement(IconFilter, { size: 16 })))), loadingBids && /* @__PURE__ */ React314.createElement(Group111, { gap: "xs", justify: "center", py: "md" }, /* @__PURE__ */ React314.createElement(Loader55, { size: "xs" }), /* @__PURE__ */ React314.createElement(Text193, { size: "xs", c: "dimmed" }, t("actionTypes.evaluateBid.flow.loadingBids", { defaultValue: "Loading bids..." }))), !loadingBids && filteredBids.length === 0 && /* @__PURE__ */ React314.createElement(Text193, { size: "sm", c: "dimmed", ta: "center", py: "md" }, bids.length === 0 ? t("actionTypes.evaluateBid.flow.empty.allCollections", { defaultValue: "No bids available for this collection." }) : t("actionTypes.evaluateBid.flow.empty.filtered", { filter: activeFilter, defaultValue: `No ${activeFilter} bids found.` })), filteredBids.length > 0 && /* @__PURE__ */ React314.createElement(Stack205, { gap: 12 }, filteredBids.map((bid) => {
|
|
31996
|
-
const status = getBidStatus(bid, t);
|
|
32648
|
+
))), /* @__PURE__ */ React314.createElement(Group111, { gap: 4 }, /* @__PURE__ */ React314.createElement(DownloadCsvButton, { onDownload: handleDownloadBidsCsv, disabled: loadingBids || bids.length === 0, label: "Download bids CSV", onError: setError }), /* @__PURE__ */ React314.createElement(DownloadZipButton, { onDownload: handleDownloadBidsZip, disabled: loadingBids || bids.length === 0, label: "Download bids + media (ZIP)", onError: setError }), /* @__PURE__ */ React314.createElement(ActionIcon45, { variant: "subtle", color: "gray", size: "sm" }, /* @__PURE__ */ React314.createElement(IconFilter, { size: 16 })))), loadingBids && /* @__PURE__ */ React314.createElement(Group111, { gap: "xs", justify: "center", py: "md" }, /* @__PURE__ */ React314.createElement(Loader55, { size: "xs" }), /* @__PURE__ */ React314.createElement(Text193, { size: "xs", c: "dimmed" }, t("actionTypes.evaluateBid.flow.loadingBids", { defaultValue: "Loading bids..." }))), !loadingBids && filteredBids.length === 0 && /* @__PURE__ */ React314.createElement(Text193, { size: "sm", c: "dimmed", ta: "center", py: "md" }, bids.length === 0 ? t("actionTypes.evaluateBid.flow.empty.allCollections", { defaultValue: "No bids available for this collection." }) : t("actionTypes.evaluateBid.flow.empty.filtered", { filter: activeFilter, defaultValue: `No ${activeFilter} bids found.` })), filteredBids.length > 0 && /* @__PURE__ */ React314.createElement(Stack205, { gap: 12 }, filteredBids.map((bid) => {
|
|
32649
|
+
const status = getBidStatus(bid, t, statusContext);
|
|
31997
32650
|
const profile = profilesByDid[bid.did];
|
|
31998
32651
|
const displayName = profile?.displayname || bid.did || bid.address;
|
|
31999
32652
|
const avatarLabel = (profile?.displayname || bid.did || bid.address || "?")[0]?.toUpperCase();
|
|
@@ -32219,94 +32872,6 @@ import React316, { useCallback as useCallback108, useEffect as useEffect111, use
|
|
|
32219
32872
|
import { ActionIcon as ActionIcon46, Box as Box58, Collapse as Collapse9, Group as Group112, Loader as Loader57, Stack as Stack207, Text as Text195, UnstyledButton as UnstyledButton5 } from "@mantine/core";
|
|
32220
32873
|
import { IconArrowLeft as IconArrowLeft9, IconCheck as IconCheck22, IconChevronRight as IconChevronRight12, IconPlayerPlay as IconPlayerPlay6 } from "@tabler/icons-react";
|
|
32221
32874
|
import { SurveyModel as SurveyModel10 } from "@ixo/surveys";
|
|
32222
|
-
|
|
32223
|
-
// src/mantine/blocks/action/actionTypes/evaluateClaim/resolveClaimFileRef.ts
|
|
32224
|
-
var IPFS_GATEWAY = "https://ipfs.gateway.ixo.world/ipfs/";
|
|
32225
|
-
var CID_REGEX = /(baf[a-z0-9]{20,})/i;
|
|
32226
|
-
function extractCid(source) {
|
|
32227
|
-
const m = source.match(CID_REGEX);
|
|
32228
|
-
return m ? m[1] : null;
|
|
32229
|
-
}
|
|
32230
|
-
function resolveClaimFileRef(raw) {
|
|
32231
|
-
if (raw == null) return null;
|
|
32232
|
-
if (typeof raw === "string") {
|
|
32233
|
-
const trimmed = raw.trim();
|
|
32234
|
-
if (!trimmed) return null;
|
|
32235
|
-
if (/^https?:/i.test(trimmed)) return trimmed;
|
|
32236
|
-
if (trimmed.startsWith("data:")) return trimmed;
|
|
32237
|
-
if (/^ipfs:/i.test(trimmed)) {
|
|
32238
|
-
const cid = extractCid(trimmed.replace(/^ipfs:\/*/i, ""));
|
|
32239
|
-
return cid ? `${IPFS_GATEWAY}${cid}` : null;
|
|
32240
|
-
}
|
|
32241
|
-
if (trimmed.startsWith("{")) {
|
|
32242
|
-
try {
|
|
32243
|
-
return resolveClaimFileRef(JSON.parse(trimmed));
|
|
32244
|
-
} catch {
|
|
32245
|
-
return null;
|
|
32246
|
-
}
|
|
32247
|
-
}
|
|
32248
|
-
if (/^did:/i.test(trimmed)) {
|
|
32249
|
-
const cid = extractCid(trimmed);
|
|
32250
|
-
return cid ? `${IPFS_GATEWAY}${cid}` : null;
|
|
32251
|
-
}
|
|
32252
|
-
if (/^baf[a-z0-9]/i.test(trimmed) && trimmed.length < 200 && !trimmed.includes(" ")) {
|
|
32253
|
-
const cid = extractCid(trimmed);
|
|
32254
|
-
return cid ? `${IPFS_GATEWAY}${cid}` : null;
|
|
32255
|
-
}
|
|
32256
|
-
return null;
|
|
32257
|
-
}
|
|
32258
|
-
if (typeof raw === "object") {
|
|
32259
|
-
const obj = raw;
|
|
32260
|
-
if (typeof obj.serviceEndpoint === "string" && /^https?:/i.test(obj.serviceEndpoint)) {
|
|
32261
|
-
return obj.serviceEndpoint;
|
|
32262
|
-
}
|
|
32263
|
-
if (typeof obj.proof === "string") {
|
|
32264
|
-
const cid = extractCid(obj.proof);
|
|
32265
|
-
if (cid) return `${IPFS_GATEWAY}${cid}`;
|
|
32266
|
-
}
|
|
32267
|
-
if (typeof obj.id === "string") {
|
|
32268
|
-
const hashIdx = obj.id.indexOf("#");
|
|
32269
|
-
const tail = hashIdx >= 0 ? obj.id.slice(hashIdx + 1) : obj.id;
|
|
32270
|
-
const cid = extractCid(tail);
|
|
32271
|
-
if (cid) return `${IPFS_GATEWAY}${cid}`;
|
|
32272
|
-
}
|
|
32273
|
-
if (typeof obj.content === "string") {
|
|
32274
|
-
return resolveClaimFileRef(obj.content);
|
|
32275
|
-
}
|
|
32276
|
-
if (typeof obj.url === "string" && /^https?:/i.test(obj.url)) {
|
|
32277
|
-
return obj.url;
|
|
32278
|
-
}
|
|
32279
|
-
}
|
|
32280
|
-
return null;
|
|
32281
|
-
}
|
|
32282
|
-
function isFileLike(value) {
|
|
32283
|
-
if (Array.isArray(value)) {
|
|
32284
|
-
return value.length > 0 && value.every((v) => v && typeof v === "object" && typeof v.content === "string");
|
|
32285
|
-
}
|
|
32286
|
-
return !!value && typeof value === "object" && typeof value.content === "string";
|
|
32287
|
-
}
|
|
32288
|
-
function resolveOneFileEntry(entry) {
|
|
32289
|
-
const resolved = resolveClaimFileRef(entry.content);
|
|
32290
|
-
if (resolved && resolved !== entry.content) {
|
|
32291
|
-
return { ...entry, content: resolved };
|
|
32292
|
-
}
|
|
32293
|
-
return entry;
|
|
32294
|
-
}
|
|
32295
|
-
function resolveFilesInCredentialSubject(subject) {
|
|
32296
|
-
if (!subject || typeof subject !== "object") return subject;
|
|
32297
|
-
const out = Array.isArray(subject) ? [...subject] : { ...subject };
|
|
32298
|
-
for (const [key, value] of Object.entries(subject)) {
|
|
32299
|
-
if (!isFileLike(value)) continue;
|
|
32300
|
-
if (Array.isArray(value)) {
|
|
32301
|
-
out[key] = value.map((v) => resolveOneFileEntry(v));
|
|
32302
|
-
} else {
|
|
32303
|
-
out[key] = resolveOneFileEntry(value);
|
|
32304
|
-
}
|
|
32305
|
-
}
|
|
32306
|
-
return out;
|
|
32307
|
-
}
|
|
32308
|
-
|
|
32309
|
-
// src/mantine/blocks/action/actionTypes/claim/ClaimFlowDetail.tsx
|
|
32310
32875
|
function getTimeAgo2(dateString) {
|
|
32311
32876
|
if (!dateString) return "";
|
|
32312
32877
|
try {
|
|
@@ -33858,7 +34423,120 @@ import React320, { useCallback as useCallback112, useEffect as useEffect115, use
|
|
|
33858
34423
|
import { ActionIcon as ActionIcon47, Alert as MantineAlert, Badge as Badge52, Box as Box60, Button as Button67, Divider as Divider22, Group as Group116, Loader as Loader61, Radio as Radio5, SegmentedControl as SegmentedControl16, Stack as Stack211, Text as Text199 } from "@mantine/core";
|
|
33859
34424
|
import { useDebouncedValue } from "@mantine/hooks";
|
|
33860
34425
|
import { IconAlertCircle as IconAlertCircle28, IconArrowLeft as IconArrowLeft10, IconCheck as IconCheck24, IconRefresh as IconRefresh9, IconTrash as IconTrash10 } from "@tabler/icons-react";
|
|
34426
|
+
|
|
34427
|
+
// src/core/utils/accountList.ts
|
|
34428
|
+
var IXO_HRP = "ixo";
|
|
34429
|
+
var TOKEN_SEPARATORS = /[\s,;|]+/;
|
|
34430
|
+
var CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
34431
|
+
var GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
34432
|
+
function polymod(values) {
|
|
34433
|
+
let chk = 1;
|
|
34434
|
+
for (const value of values) {
|
|
34435
|
+
const top = chk >> 25;
|
|
34436
|
+
chk = (chk & 33554431) << 5 ^ value;
|
|
34437
|
+
for (let i = 0; i < 5; i += 1) {
|
|
34438
|
+
if (top >> i & 1) chk ^= GENERATOR[i];
|
|
34439
|
+
}
|
|
34440
|
+
}
|
|
34441
|
+
return chk;
|
|
34442
|
+
}
|
|
34443
|
+
function hrpExpand(hrp) {
|
|
34444
|
+
const high = [];
|
|
34445
|
+
const low = [];
|
|
34446
|
+
for (let i = 0; i < hrp.length; i += 1) {
|
|
34447
|
+
high.push(hrp.charCodeAt(i) >> 5);
|
|
34448
|
+
low.push(hrp.charCodeAt(i) & 31);
|
|
34449
|
+
}
|
|
34450
|
+
return [...high, 0, ...low];
|
|
34451
|
+
}
|
|
34452
|
+
function isValidBech32Address(value, hrp = IXO_HRP) {
|
|
34453
|
+
if (!value) return false;
|
|
34454
|
+
if (value !== value.toLowerCase() && value !== value.toUpperCase()) return false;
|
|
34455
|
+
const address = value.toLowerCase();
|
|
34456
|
+
if (address.length < hrp.length + 8 || address.length > 90) return false;
|
|
34457
|
+
if (!address.startsWith(`${hrp}1`)) return false;
|
|
34458
|
+
const dataPart = address.slice(hrp.length + 1);
|
|
34459
|
+
const data = [];
|
|
34460
|
+
for (const char of dataPart) {
|
|
34461
|
+
const index = CHARSET.indexOf(char);
|
|
34462
|
+
if (index === -1) return false;
|
|
34463
|
+
data.push(index);
|
|
34464
|
+
}
|
|
34465
|
+
return polymod([...hrpExpand(hrp), ...data]) === 1;
|
|
34466
|
+
}
|
|
34467
|
+
function normalizeToken(token) {
|
|
34468
|
+
let value = token.trim();
|
|
34469
|
+
value = value.replace(/^["'`]+|["'`]+$/g, "");
|
|
34470
|
+
value = value.replace(/^[([{<]+|[)\]}>.,;:]+$/g, "");
|
|
34471
|
+
if (/^did:ixo:/i.test(value)) value = value.slice("did:ixo:".length);
|
|
34472
|
+
return value.trim();
|
|
34473
|
+
}
|
|
34474
|
+
function looksLikeAddress(token) {
|
|
34475
|
+
return /^ixo1/i.test(token);
|
|
34476
|
+
}
|
|
34477
|
+
function parseAccountList(text) {
|
|
34478
|
+
const rows = [];
|
|
34479
|
+
const addresses = [];
|
|
34480
|
+
const seen = /* @__PURE__ */ new Set();
|
|
34481
|
+
let duplicates = 0;
|
|
34482
|
+
const lines = String(text ?? "").split(/\r\n|\n|\r/);
|
|
34483
|
+
lines.forEach((line, index) => {
|
|
34484
|
+
const raw = line.replace(/\t/g, " ").trim();
|
|
34485
|
+
if (!raw) return;
|
|
34486
|
+
const row = { line: index + 1, raw };
|
|
34487
|
+
const tokens = line.split(TOKEN_SEPARATORS).map(normalizeToken).filter(Boolean);
|
|
34488
|
+
const candidates = tokens.filter(looksLikeAddress);
|
|
34489
|
+
if (candidates.length === 0) {
|
|
34490
|
+
row.problem = "no-address";
|
|
34491
|
+
rows.push(row);
|
|
34492
|
+
return;
|
|
34493
|
+
}
|
|
34494
|
+
const valid = candidates.map((candidate) => candidate.toLowerCase()).filter((candidate) => isValidBech32Address(candidate));
|
|
34495
|
+
if (valid.length === 0) {
|
|
34496
|
+
row.problem = "invalid-address";
|
|
34497
|
+
rows.push(row);
|
|
34498
|
+
return;
|
|
34499
|
+
}
|
|
34500
|
+
const [address, ...extras] = valid;
|
|
34501
|
+
row.address = address;
|
|
34502
|
+
if (seen.has(address)) {
|
|
34503
|
+
duplicates += 1;
|
|
34504
|
+
row.problem = "duplicate";
|
|
34505
|
+
} else {
|
|
34506
|
+
seen.add(address);
|
|
34507
|
+
addresses.push(address);
|
|
34508
|
+
}
|
|
34509
|
+
rows.push(row);
|
|
34510
|
+
for (const extra of extras) {
|
|
34511
|
+
rows.push({ line: index + 1, raw: extra, address: extra, problem: "extra-in-row" });
|
|
34512
|
+
}
|
|
34513
|
+
});
|
|
34514
|
+
return {
|
|
34515
|
+
addresses,
|
|
34516
|
+
rows,
|
|
34517
|
+
// Duplicates are excluded: they are not a loss (the account is in the list
|
|
34518
|
+
// once already) and they are counted separately.
|
|
34519
|
+
rejected: rows.filter((row) => !!row.problem && row.problem !== "duplicate"),
|
|
34520
|
+
duplicates
|
|
34521
|
+
};
|
|
34522
|
+
}
|
|
34523
|
+
|
|
34524
|
+
// src/mantine/blocks/action/actionTypes/_shared/bids/decidedBids.ts
|
|
34525
|
+
async function fetchDecidedBids(handlers, params) {
|
|
34526
|
+
const queryDecided = handlers?.bids?.queryDecided;
|
|
34527
|
+
if (typeof queryDecided !== "function") return { bids: [], supported: false };
|
|
34528
|
+
try {
|
|
34529
|
+
const result = await queryDecided(params);
|
|
34530
|
+
const list = Array.isArray(result) ? result : result?.data ?? [];
|
|
34531
|
+
return { bids: list.map((bid) => ({ ...bid, decided: true })), supported: true };
|
|
34532
|
+
} catch {
|
|
34533
|
+
return { bids: [], supported: false };
|
|
34534
|
+
}
|
|
34535
|
+
}
|
|
34536
|
+
|
|
34537
|
+
// src/mantine/blocks/action/actionTypes/collectionUsers/CollectionUsersFlowDetail.tsx
|
|
33861
34538
|
var LOG2 = "[collection.users]";
|
|
34539
|
+
var MAX_LISTED_REJECTIONS = 8;
|
|
33862
34540
|
function roleLabel(role) {
|
|
33863
34541
|
return role === "submit" ? "Submit (Contributor)" : "Evaluate (Evaluator)";
|
|
33864
34542
|
}
|
|
@@ -33933,6 +34611,72 @@ function MaxAmountsInput({ value, onChange, disabled }) {
|
|
|
33933
34611
|
}
|
|
33934
34612
|
)));
|
|
33935
34613
|
}
|
|
34614
|
+
function broadcastTxCount(output) {
|
|
34615
|
+
if (Array.isArray(output?.transactionHashes)) return output.transactionHashes.length;
|
|
34616
|
+
return output?.batched === false ? Number(output?.grantedCount) || 1 : 1;
|
|
34617
|
+
}
|
|
34618
|
+
function grantBroadcastSummary(output) {
|
|
34619
|
+
const count = Number(output?.grantedCount);
|
|
34620
|
+
if (!Number.isFinite(count) || count <= 1) return "Grant broadcast";
|
|
34621
|
+
const transactions = broadcastTxCount(output);
|
|
34622
|
+
return transactions === 1 ? `${count} accounts granted in one transaction` : `${count} accounts granted in ${transactions} transactions`;
|
|
34623
|
+
}
|
|
34624
|
+
function rejectionReason(problem) {
|
|
34625
|
+
if (problem === "invalid-address") return "not a valid ixo1\u2026 address";
|
|
34626
|
+
if (problem === "extra-in-row") return "a second account on the same row \u2014 only the first one on a row is granted";
|
|
34627
|
+
return "no account found in this row";
|
|
34628
|
+
}
|
|
34629
|
+
function signingPlan(count, canBatchGrants) {
|
|
34630
|
+
if (count <= 1) return null;
|
|
34631
|
+
if (!canBatchGrants) {
|
|
34632
|
+
return { color: "yellow", message: `This host cannot bundle grants \u2014 it will ask you to sign ${count} separate transactions, one per account.` };
|
|
34633
|
+
}
|
|
34634
|
+
const batches = collectionUsersBatchCount(count);
|
|
34635
|
+
if (batches === 1) return { color: "blue", message: `All ${count} grants go in one transaction \u2014 you sign once.` };
|
|
34636
|
+
return {
|
|
34637
|
+
color: "yellow",
|
|
34638
|
+
message: `${count} grants exceed the ${COLLECTION_USERS_MAX_GRANTS_PER_TX} per transaction limit, so they are split into ${batches} batches \u2014 you will be asked to sign ${batches} times, one after the other.`
|
|
34639
|
+
};
|
|
34640
|
+
}
|
|
34641
|
+
function BulkAccountsInput({
|
|
34642
|
+
text,
|
|
34643
|
+
onChange,
|
|
34644
|
+
parsed,
|
|
34645
|
+
isDisabled,
|
|
34646
|
+
canBatchGrants,
|
|
34647
|
+
actingAsGroup
|
|
34648
|
+
}) {
|
|
34649
|
+
const { addresses, rejected, duplicates } = parsed;
|
|
34650
|
+
const listed = rejected.slice(0, MAX_LISTED_REJECTIONS);
|
|
34651
|
+
const plan = signingPlan(addresses.length, canBatchGrants);
|
|
34652
|
+
return /* @__PURE__ */ React320.createElement(Stack211, { gap: "xs" }, /* @__PURE__ */ React320.createElement(
|
|
34653
|
+
BaseTextArea,
|
|
34654
|
+
{
|
|
34655
|
+
label: "Accounts",
|
|
34656
|
+
description: "Paste (Ctrl+V) a column copied from Google Sheets or Excel \u2014 one account per row. Other columns, headers and blank rows are ignored.",
|
|
34657
|
+
placeholder: "ixo1\u2026\nixo1\u2026\nixo1\u2026",
|
|
34658
|
+
minRows: 4,
|
|
34659
|
+
maxRows: 12,
|
|
34660
|
+
value: text,
|
|
34661
|
+
onChange: (event) => onChange(event.currentTarget.value),
|
|
34662
|
+
disabled: isDisabled,
|
|
34663
|
+
styles: { input: { fontFamily: "var(--mantine-font-family-monospace)" } }
|
|
34664
|
+
}
|
|
34665
|
+
), /* @__PURE__ */ React320.createElement(Group116, { justify: "space-between", align: "center" }, /* @__PURE__ */ React320.createElement(Group116, { gap: "xs" }, /* @__PURE__ */ React320.createElement(Badge52, { size: "sm", variant: "light", color: addresses.length > 0 ? "green" : "gray" }, addresses.length, " account", addresses.length === 1 ? "" : "s", " to grant"), duplicates > 0 && /* @__PURE__ */ React320.createElement(Badge52, { size: "sm", variant: "light", color: "gray" }, duplicates, " duplicate", duplicates === 1 ? "" : "s", " removed"), rejected.length > 0 && /* @__PURE__ */ React320.createElement(Badge52, { size: "sm", variant: "light", color: "yellow" }, rejected.length, " row", rejected.length === 1 ? "" : "s", " skipped")), !!text.trim() && /* @__PURE__ */ React320.createElement(Button67, { size: "compact-xs", variant: "subtle", color: "gray", onClick: () => onChange(""), disabled: isDisabled }, "Clear")), rejected.length > 0 && /* @__PURE__ */ React320.createElement(DismissibleAlert, { color: "yellow", styles: actionAlertStyles }, /* @__PURE__ */ React320.createElement(Stack211, { gap: 2 }, /* @__PURE__ */ React320.createElement(Text199, { size: "xs", fw: 600 }, "These rows will NOT be granted:"), listed.map((row) => /* @__PURE__ */ React320.createElement(Text199, { key: row.line, size: "xs" }, "Row ", row.line, ": \u201C", row.raw.length > 60 ? `${row.raw.slice(0, 60)}\u2026` : row.raw, "\u201D \u2014 ", rejectionReason(row.problem))), rejected.length > listed.length && /* @__PURE__ */ React320.createElement(Text199, { size: "xs", c: "dimmed" }, "\u2026and ", rejected.length - listed.length, " more."))), addresses.length > 0 && /* @__PURE__ */ React320.createElement(
|
|
34666
|
+
Box60,
|
|
34667
|
+
{
|
|
34668
|
+
style: {
|
|
34669
|
+
border: "1px solid var(--mantine-color-neutralColor-6)",
|
|
34670
|
+
borderRadius: 8,
|
|
34671
|
+
padding: 8,
|
|
34672
|
+
maxHeight: 160,
|
|
34673
|
+
overflowY: "auto",
|
|
34674
|
+
background: "var(--mantine-color-neutralColor-5)"
|
|
34675
|
+
}
|
|
34676
|
+
},
|
|
34677
|
+
/* @__PURE__ */ React320.createElement(Stack211, { gap: 2 }, addresses.map((address, index) => /* @__PURE__ */ React320.createElement(Text199, { key: address, size: "xs", ff: "monospace", truncate: true }, index + 1, ". ", address)))
|
|
34678
|
+
), actingAsGroup && addresses.length > COLLECTION_USERS_MAX_GRANTS_PER_TX && /* @__PURE__ */ React320.createElement(DismissibleAlert, { color: "red", styles: actionAlertStyles }, "Acting as a POD puts every grant in one proposal, which executes as a single transaction \u2014 so this list cannot be split. Reduce it to ", COLLECTION_USERS_MAX_GRANTS_PER_TX, " ", "accounts or fewer, or grant without acting as a POD."), !actingAsGroup && plan && /* @__PURE__ */ React320.createElement(DismissibleAlert, { color: plan.color, styles: actionAlertStyles }, plan.message));
|
|
34679
|
+
}
|
|
33936
34680
|
function toQuotaString(value) {
|
|
33937
34681
|
const n = Number(value);
|
|
33938
34682
|
if (!Number.isFinite(n) || n < MIN_AGENT_QUOTA) return String(MIN_AGENT_QUOTA);
|
|
@@ -34053,7 +34797,28 @@ var CollectionUsersFlowDetail = ({
|
|
|
34053
34797
|
const [addMaxAmounts, setAddMaxAmounts] = useState170(EMPTY_MAX_AMOUNTS);
|
|
34054
34798
|
const [granteeKind, setGranteeKind] = useState170("user");
|
|
34055
34799
|
const [members, setMembers] = useState170([]);
|
|
34800
|
+
const [addMode, setAddMode] = useState170("single");
|
|
34801
|
+
const [bulkText, setBulkText] = useState170("");
|
|
34802
|
+
const parsedAccounts = useMemo120(() => parseAccountList(bulkText), [bulkText]);
|
|
34803
|
+
const bulkAddresses = parsedAccounts.addresses;
|
|
34804
|
+
const canBatchGrants = typeof handlers.collectionUsers?.grantMany === "function";
|
|
34056
34805
|
const [revokeTarget, setRevokeTarget] = useState170(null);
|
|
34806
|
+
const handleBulkPaste = useCallback112(
|
|
34807
|
+
(text) => {
|
|
34808
|
+
const carried = addAddress.trim();
|
|
34809
|
+
setActiveOp("add");
|
|
34810
|
+
setRevokeTarget(null);
|
|
34811
|
+
setAddAddress("");
|
|
34812
|
+
setAddMode("list");
|
|
34813
|
+
setBulkText((prev) => [prev.replace(/\s+$/, ""), carried, text].filter((part) => part.trim()).join("\n"));
|
|
34814
|
+
},
|
|
34815
|
+
[addAddress]
|
|
34816
|
+
);
|
|
34817
|
+
const handleAddModeChange = useCallback112((mode) => {
|
|
34818
|
+
setActiveOp("add");
|
|
34819
|
+
setRevokeTarget(null);
|
|
34820
|
+
setAddMode(mode);
|
|
34821
|
+
}, []);
|
|
34057
34822
|
const classifyHandler = handlers.classifyAddress;
|
|
34058
34823
|
const enumerateHandler = handlers.enumerateMembers;
|
|
34059
34824
|
const canClassify = typeof classifyHandler === "function";
|
|
@@ -34116,6 +34881,8 @@ var CollectionUsersFlowDetail = ({
|
|
|
34116
34881
|
}, [addRole]);
|
|
34117
34882
|
const isGroup = !!classification?.daodao;
|
|
34118
34883
|
const canExerciseGrant = !!classification?.daodao?.canExerciseGrant;
|
|
34884
|
+
const pendingGranteeCount = addMode === "list" ? bulkAddresses.length : granteeKind === "group-members" ? members.length : 1;
|
|
34885
|
+
const memberSigningPlan = useMemo120(() => signingPlan(members.length, canBatchGrants), [members.length, canBatchGrants]);
|
|
34119
34886
|
const listOnLoadRef = useRef42(false);
|
|
34120
34887
|
const runList = useCallback112(async () => {
|
|
34121
34888
|
if (!executeAction) {
|
|
@@ -34158,13 +34925,85 @@ var CollectionUsersFlowDetail = ({
|
|
|
34158
34925
|
const handleBidEvaluated = useCallback112((bidId, outcome) => {
|
|
34159
34926
|
setEvaluatedBids((prev) => ({ ...prev, [bidId]: outcome }));
|
|
34160
34927
|
}, []);
|
|
34161
|
-
const
|
|
34928
|
+
const granteeNamesByDid = useMemo120(() => {
|
|
34162
34929
|
const namesByDid = {};
|
|
34163
34930
|
for (const [did, profile] of Object.entries(granteeProfilesByDid)) {
|
|
34164
34931
|
if (profile?.displayname) namesByDid[did] = profile.displayname;
|
|
34165
34932
|
}
|
|
34166
|
-
|
|
34167
|
-
}, [
|
|
34933
|
+
return namesByDid;
|
|
34934
|
+
}, [granteeProfilesByDid]);
|
|
34935
|
+
const fetchCollectionBids = useCallback112(async () => {
|
|
34936
|
+
if (!deedDid || !collectionId) return { bids: [], truncated: false, decidedIncluded: false };
|
|
34937
|
+
const handlers2 = handlersRef.current;
|
|
34938
|
+
let open = [];
|
|
34939
|
+
let truncated = false;
|
|
34940
|
+
try {
|
|
34941
|
+
const result = await fetchAllBids(handlers2.queryBids, { collectionId, entityDid: deedDid });
|
|
34942
|
+
open = result.bids;
|
|
34943
|
+
truncated = result.truncated;
|
|
34944
|
+
} catch {
|
|
34945
|
+
open = [];
|
|
34946
|
+
}
|
|
34947
|
+
const decided = await fetchDecidedBids(handlers2, { collectionId, entityDid: deedDid });
|
|
34948
|
+
return { bids: dedupeBids([...open, ...decided.bids]), truncated, decidedIncluded: decided.supported };
|
|
34949
|
+
}, [deedDid, collectionId]);
|
|
34950
|
+
const [membersExportError, setMembersExportError] = useState170(null);
|
|
34951
|
+
const handleDownloadGranteesCsv = useCallback112(async () => {
|
|
34952
|
+
const { bids, truncated, decidedIncluded } = await fetchCollectionBids();
|
|
34953
|
+
downloadSectionedCsv(
|
|
34954
|
+
buildCollectionMembersSections({
|
|
34955
|
+
grantees: listGrantees,
|
|
34956
|
+
bids,
|
|
34957
|
+
namesByDid: granteeNamesByDid,
|
|
34958
|
+
bidOptions: { evaluatedByBidId: evaluatedBids },
|
|
34959
|
+
collectionId,
|
|
34960
|
+
bidsTruncated: truncated,
|
|
34961
|
+
decidedBidsIncluded: decidedIncluded
|
|
34962
|
+
}),
|
|
34963
|
+
{ filename: exportFileNames.collectionMembers(collectionId).csv }
|
|
34964
|
+
);
|
|
34965
|
+
setMembersExportError(truncated ? "Bid paging stopped early \u2014 part 2 of the export is incomplete." : null);
|
|
34966
|
+
}, [fetchCollectionBids, listGrantees, granteeNamesByDid, evaluatedBids, collectionId]);
|
|
34967
|
+
const handleDownloadGranteesZip = useCallback112(async () => {
|
|
34968
|
+
const { bids, truncated, decidedIncluded } = await fetchCollectionBids();
|
|
34969
|
+
const names = exportFileNames.collectionMembers(collectionId);
|
|
34970
|
+
const handlers2 = handlersRef.current;
|
|
34971
|
+
const fetchMedia = handlers2.fetchClaimMedia ? (url) => handlers2.fetchClaimMedia(url, { entityDid: deedDid }) : void 0;
|
|
34972
|
+
const { blob, mediaTotal, mediaFailed } = await buildExportBundle({
|
|
34973
|
+
records: bids.map((bid) => ({
|
|
34974
|
+
recordId: bid.id,
|
|
34975
|
+
answers: bidAnswers(bid),
|
|
34976
|
+
manifest: {
|
|
34977
|
+
bidId: bid.id,
|
|
34978
|
+
did: bid.did,
|
|
34979
|
+
address: bid.address,
|
|
34980
|
+
role: bid.role,
|
|
34981
|
+
created: bid.created,
|
|
34982
|
+
status: getBidStatusInfo(bid, { grantees: listGrantees, evaluatedByBidId: evaluatedBids }).key
|
|
34983
|
+
}
|
|
34984
|
+
})),
|
|
34985
|
+
fetchMedia,
|
|
34986
|
+
renderCsv: (answersByBidId) => sectionsToCsv(
|
|
34987
|
+
buildCollectionMembersSections({
|
|
34988
|
+
grantees: listGrantees,
|
|
34989
|
+
bids,
|
|
34990
|
+
namesByDid: granteeNamesByDid,
|
|
34991
|
+
bidOptions: { evaluatedByBidId: evaluatedBids, answersByBidId },
|
|
34992
|
+
collectionId,
|
|
34993
|
+
bidsTruncated: truncated,
|
|
34994
|
+
decidedBidsIncluded: decidedIncluded
|
|
34995
|
+
})
|
|
34996
|
+
),
|
|
34997
|
+
csvName: names.csv,
|
|
34998
|
+
manifestName: names.manifest
|
|
34999
|
+
});
|
|
35000
|
+
downloadBlob(blob, names.zip);
|
|
35001
|
+
const notes = [
|
|
35002
|
+
truncated ? "Bid paging stopped early \u2014 part 2 of the export is incomplete." : "",
|
|
35003
|
+
mediaFailed > 0 ? `${mediaFailed} of ${mediaTotal} bid media files could not be downloaded \u2014 see downloadStatus in ${names.manifest}.` : ""
|
|
35004
|
+
].filter(Boolean);
|
|
35005
|
+
setMembersExportError(notes.length > 0 ? notes.join(" ") : null);
|
|
35006
|
+
}, [fetchCollectionBids, listGrantees, granteeNamesByDid, evaluatedBids, collectionId, deedDid]);
|
|
34168
35007
|
useEffect115(() => {
|
|
34169
35008
|
let mounted = true;
|
|
34170
35009
|
const dids = Array.from(new Set(listGrantees.map(getGranteeDid).filter(Boolean)));
|
|
@@ -34208,20 +35047,49 @@ var CollectionUsersFlowDetail = ({
|
|
|
34208
35047
|
if (!revokeTarget?.address) return { ok: false, error: "Pick a grantee to revoke from the list." };
|
|
34209
35048
|
return { ok: true };
|
|
34210
35049
|
}
|
|
34211
|
-
|
|
34212
|
-
|
|
34213
|
-
|
|
34214
|
-
|
|
35050
|
+
if (addMode === "list") {
|
|
35051
|
+
if (bulkAddresses.length === 0) {
|
|
35052
|
+
return { ok: false, error: parsedAccounts.rows.length > 0 ? "No valid ixo1\u2026 accounts in the pasted list." : "Paste a list of accounts to grant." };
|
|
35053
|
+
}
|
|
35054
|
+
} else {
|
|
35055
|
+
const address = addAddress.trim();
|
|
35056
|
+
if (!address) return { ok: false, error: "Enter a grantee address." };
|
|
35057
|
+
if (granteeKind === "group-account" && !canExerciseGrant) {
|
|
35058
|
+
return { ok: false, error: "This group cannot hold the authorization. Grant its members individually instead." };
|
|
35059
|
+
}
|
|
35060
|
+
if (granteeKind === "group-members") {
|
|
35061
|
+
if (members.length === 0) return { ok: false, error: "No group members resolved yet." };
|
|
35062
|
+
}
|
|
34215
35063
|
}
|
|
34216
|
-
if (
|
|
34217
|
-
|
|
35064
|
+
if (actAs.actAsGroup && pendingGranteeCount > COLLECTION_USERS_MAX_GRANTS_PER_TX) {
|
|
35065
|
+
return {
|
|
35066
|
+
ok: false,
|
|
35067
|
+
error: `Acting as a POD allows at most ${COLLECTION_USERS_MAX_GRANTS_PER_TX} accounts per proposal; this grants ${pendingGranteeCount}. Remove ${pendingGranteeCount - COLLECTION_USERS_MAX_GRANTS_PER_TX}, or grant without acting as a POD.`
|
|
35068
|
+
};
|
|
34218
35069
|
}
|
|
34219
35070
|
const quotaNum = Number(addQuota);
|
|
34220
35071
|
if (!Number.isFinite(quotaNum) || quotaNum < MIN_AGENT_QUOTA) {
|
|
34221
35072
|
return { ok: false, error: `Agent quota must be at least ${MIN_AGENT_QUOTA}.` };
|
|
34222
35073
|
}
|
|
34223
35074
|
return { ok: true };
|
|
34224
|
-
}, [
|
|
35075
|
+
}, [
|
|
35076
|
+
section,
|
|
35077
|
+
collectionId,
|
|
35078
|
+
adminAddress,
|
|
35079
|
+
adminError,
|
|
35080
|
+
activeOp,
|
|
35081
|
+
revokeTarget,
|
|
35082
|
+
addMode,
|
|
35083
|
+
bulkAddresses.length,
|
|
35084
|
+
parsedAccounts.rows.length,
|
|
35085
|
+
actAs.actAsGroup,
|
|
35086
|
+
pendingGranteeCount,
|
|
35087
|
+
addAddress,
|
|
35088
|
+
granteeKind,
|
|
35089
|
+
canExerciseGrant,
|
|
35090
|
+
members.length,
|
|
35091
|
+
addQuota
|
|
35092
|
+
]);
|
|
34225
35093
|
const buildRuntimeInputs = useCallback112(() => {
|
|
34226
35094
|
if (section === "bids") {
|
|
34227
35095
|
return { operation: "list", collectionId, adminAddress };
|
|
@@ -34237,19 +35105,21 @@ var CollectionUsersFlowDetail = ({
|
|
|
34237
35105
|
};
|
|
34238
35106
|
}
|
|
34239
35107
|
const maxAmounts = buildMaxAmounts(addMaxAmounts);
|
|
35108
|
+
const isBulk = addMode === "list";
|
|
34240
35109
|
return {
|
|
34241
35110
|
operation: "add",
|
|
34242
35111
|
collectionId,
|
|
34243
35112
|
adminAddress,
|
|
34244
35113
|
deedDid: deedDid || void 0,
|
|
34245
|
-
granteeAddress: addAddress.trim(),
|
|
35114
|
+
granteeAddress: isBulk ? void 0 : addAddress.trim(),
|
|
34246
35115
|
role: addRole,
|
|
34247
|
-
granteeKind,
|
|
35116
|
+
granteeKind: isBulk ? "address-list" : granteeKind,
|
|
34248
35117
|
agentQuota: toQuotaString(addQuota),
|
|
34249
35118
|
maxAmount: addRole === "evaluate" && maxAmounts.length > 0 ? maxAmounts : void 0,
|
|
34250
|
-
members: granteeKind === "group-members" ? members : void 0
|
|
35119
|
+
members: !isBulk && granteeKind === "group-members" ? members : void 0,
|
|
35120
|
+
granteeAddresses: isBulk ? bulkAddresses : void 0
|
|
34251
35121
|
};
|
|
34252
|
-
}, [section, activeOp, collectionId, adminAddress, deedDid, revokeTarget, addAddress, addRole, granteeKind, addQuota, addMaxAmounts, members]);
|
|
35122
|
+
}, [section, activeOp, collectionId, adminAddress, deedDid, revokeTarget, addMode, bulkAddresses, addAddress, addRole, granteeKind, addQuota, addMaxAmounts, members]);
|
|
34253
35123
|
useEffect115(() => {
|
|
34254
35124
|
if (!registerRuntimeInputs) return;
|
|
34255
35125
|
registerRuntimeInputs(buildRuntimeInputs());
|
|
@@ -34273,6 +35143,7 @@ var CollectionUsersFlowDetail = ({
|
|
|
34273
35143
|
collectionId,
|
|
34274
35144
|
granteeAddress: runtimeInputs.granteeAddress,
|
|
34275
35145
|
granteeKind: runtimeInputs.granteeKind,
|
|
35146
|
+
granteeCount: runtimeInputs.granteeAddresses?.length,
|
|
34276
35147
|
listener: isListener
|
|
34277
35148
|
});
|
|
34278
35149
|
try {
|
|
@@ -34287,6 +35158,7 @@ var CollectionUsersFlowDetail = ({
|
|
|
34287
35158
|
console.log(`${LOG2} execute success`, { operation: runtimeInputs.operation, transactionHash: payload.transactionHash });
|
|
34288
35159
|
if (runtimeInputs.operation === "add") {
|
|
34289
35160
|
setAddAddress("");
|
|
35161
|
+
setBulkText("");
|
|
34290
35162
|
setAddQuota(String(runtimeInputs.role === "evaluate" ? DEFAULT_EVALUATOR_QUOTA : DEFAULT_CONTRIBUTOR_QUOTA));
|
|
34291
35163
|
setAddMaxAmounts(EMPTY_MAX_AMOUNTS);
|
|
34292
35164
|
setGranteeKind("user");
|
|
@@ -34337,7 +35209,7 @@ var CollectionUsersFlowDetail = ({
|
|
|
34337
35209
|
defaultValue: "Configure the {{did}} and {{claimCollection}} in template mode before running this action.",
|
|
34338
35210
|
did: "DID",
|
|
34339
35211
|
claimCollection: "claim collection"
|
|
34340
|
-
})), isStale && /* @__PURE__ */ React320.createElement(DismissibleAlert, { icon: /* @__PURE__ */ React320.createElement(IconAlertCircle28, { size: 16 }), color: "yellow", title: "Inconsistent State" }, /* @__PURE__ */ React320.createElement(Stack211, { gap: "xs" }, /* @__PURE__ */ React320.createElement(Text199, { size: "sm" }, "Block was marked completed but no result was recorded. This is stale state from a previous run \u2014 reset and re-run."), /* @__PURE__ */ React320.createElement(Group116, null, /* @__PURE__ */ React320.createElement(Button67, { variant: "outline", size: "xs", onClick: handleReset }, "Reset"), /* @__PURE__ */ React320.createElement(Button67, { variant: "filled", size: "xs", onClick: handleForceRun, disabled: !validation.ok }, "Force Run Now")))), isFailed && /* @__PURE__ */ React320.createElement(DismissibleAlert, { icon: /* @__PURE__ */ React320.createElement(IconAlertCircle28, { size: 16 }), color: "red", title: "Action Failed", styles: actionAlertStyles }, /* @__PURE__ */ React320.createElement(Stack211, { gap: "xs" }, errorMessage && /* @__PURE__ */ React320.createElement(Text199, { size: "sm" }, errorMessage), /* @__PURE__ */ React320.createElement(Group116, null, /* @__PURE__ */ React320.createElement(Button67, { variant: "outline", size: "xs", onClick: handleReset }, "Reset"), !!collectionId && !!adminAddress && /* @__PURE__ */ React320.createElement(Button67, { variant: "filled", size: "xs", leftSection: /* @__PURE__ */ React320.createElement(IconRefresh9, { size: 14 }), onClick: handleManualRefreshList }, "Refresh List")))), isCompletedWithProof && hasTxProof && (lastOp === "add" || lastOp === "revoke") && /* @__PURE__ */ React320.createElement(DismissibleAlert, { icon: /* @__PURE__ */ React320.createElement(IconCheck24, { size: 16 }), color: "green", styles: actionAlertStyles }, lastOp === "add" ?
|
|
35212
|
+
})), isStale && /* @__PURE__ */ React320.createElement(DismissibleAlert, { icon: /* @__PURE__ */ React320.createElement(IconAlertCircle28, { size: 16 }), color: "yellow", title: "Inconsistent State" }, /* @__PURE__ */ React320.createElement(Stack211, { gap: "xs" }, /* @__PURE__ */ React320.createElement(Text199, { size: "sm" }, "Block was marked completed but no result was recorded. This is stale state from a previous run \u2014 reset and re-run."), /* @__PURE__ */ React320.createElement(Group116, null, /* @__PURE__ */ React320.createElement(Button67, { variant: "outline", size: "xs", onClick: handleReset }, "Reset"), /* @__PURE__ */ React320.createElement(Button67, { variant: "filled", size: "xs", onClick: handleForceRun, disabled: !validation.ok }, "Force Run Now")))), isFailed && /* @__PURE__ */ React320.createElement(DismissibleAlert, { icon: /* @__PURE__ */ React320.createElement(IconAlertCircle28, { size: 16 }), color: "red", title: "Action Failed", styles: actionAlertStyles }, /* @__PURE__ */ React320.createElement(Stack211, { gap: "xs" }, errorMessage && /* @__PURE__ */ React320.createElement(Text199, { size: "sm" }, errorMessage), /* @__PURE__ */ React320.createElement(Group116, null, /* @__PURE__ */ React320.createElement(Button67, { variant: "outline", size: "xs", onClick: handleReset }, "Reset"), !!collectionId && !!adminAddress && /* @__PURE__ */ React320.createElement(Button67, { variant: "filled", size: "xs", leftSection: /* @__PURE__ */ React320.createElement(IconRefresh9, { size: 14 }), onClick: handleManualRefreshList }, "Refresh List")))), isCompletedWithProof && hasTxProof && (lastOp === "add" || lastOp === "revoke") && /* @__PURE__ */ React320.createElement(DismissibleAlert, { icon: /* @__PURE__ */ React320.createElement(IconCheck24, { size: 16 }), color: "green", styles: actionAlertStyles }, lastOp === "add" ? grantBroadcastSummary(output) : "Revoke broadcast", " \u2014 ", broadcastTxCount(output) > 1 ? "last tx" : "tx", " ", truncateAddress4(String(output?.transactionHash || "")), "."), !configMissing && /* @__PURE__ */ React320.createElement(
|
|
34341
35213
|
SegmentedControl16,
|
|
34342
35214
|
{
|
|
34343
35215
|
fullWidth: true,
|
|
@@ -34350,7 +35222,7 @@ var CollectionUsersFlowDetail = ({
|
|
|
34350
35222
|
{ label: "Bids", value: "bids" }
|
|
34351
35223
|
]
|
|
34352
35224
|
}
|
|
34353
|
-
), !configMissing && section === "list" && /* @__PURE__ */ React320.createElement(Stack211, { gap: "sm" }, /* @__PURE__ */ React320.createElement(Group116, { justify: "space-between", align: "center" }, /* @__PURE__ */ React320.createElement(Text199, { size: "sm", fw: 600 }, "Grantees"), /* @__PURE__ */ React320.createElement(Group116, { gap: 4 }, /* @__PURE__ */ React320.createElement(DownloadCsvButton, { onDownload: handleDownloadGranteesCsv, disabled: isRunning
|
|
35225
|
+
), !configMissing && section === "list" && /* @__PURE__ */ React320.createElement(Stack211, { gap: "sm" }, /* @__PURE__ */ React320.createElement(Group116, { justify: "space-between", align: "center" }, /* @__PURE__ */ React320.createElement(Text199, { size: "sm", fw: 600 }, "Grantees"), /* @__PURE__ */ React320.createElement(Group116, { gap: 4 }, /* @__PURE__ */ React320.createElement(DownloadCsvButton, { onDownload: handleDownloadGranteesCsv, disabled: isRunning, label: "Download members CSV (grants + bids)", onError: setMembersExportError }), /* @__PURE__ */ React320.createElement(DownloadZipButton, { onDownload: handleDownloadGranteesZip, disabled: isRunning, label: "Download members + bid media (ZIP)", onError: setMembersExportError }), /* @__PURE__ */ React320.createElement(ActionIcon47, { variant: "subtle", color: "gray", size: "sm", onClick: handleManualRefreshList, disabled: isRunning || !adminAddress }, /* @__PURE__ */ React320.createElement(IconRefresh9, { size: 16 })))), membersExportError && /* @__PURE__ */ React320.createElement(DismissibleAlert, { color: "yellow", styles: actionAlertStyles, onClose: () => setMembersExportError(null) }, membersExportError), isRunning && lastOp !== "add" && lastOp !== "revoke" && /* @__PURE__ */ React320.createElement(Group116, { gap: "xs", justify: "center", py: "sm" }, /* @__PURE__ */ React320.createElement(Loader61, { size: "xs" }), /* @__PURE__ */ React320.createElement(Text199, { size: "xs", c: "dimmed" }, "Loading grantees\u2026")), !isRunning && listGrantees.length === 0 && /* @__PURE__ */ React320.createElement(Text199, { size: "sm", c: "dimmed", ta: "center", py: "sm" }, "No grantees hold a constraint for this collection yet."), listGrantees.map((grantee) => {
|
|
34354
35226
|
const isTarget = revokeTarget?.address === grantee.address && revokeTarget?.role === grantee.role;
|
|
34355
35227
|
const granteeDid = getGranteeDid(grantee);
|
|
34356
35228
|
const profile = granteeProfilesByDid[granteeDid];
|
|
@@ -34379,7 +35251,30 @@ var CollectionUsersFlowDetail = ({
|
|
|
34379
35251
|
"Revoke"
|
|
34380
35252
|
))
|
|
34381
35253
|
);
|
|
34382
|
-
}), revokeTarget && /* @__PURE__ */ React320.createElement(DismissibleAlert, { color: "red", styles: actionAlertStyles }, "Slide to sign to revoke ", roleLabel(revokeTarget.role), " from ", truncateAddress4(revokeTarget.address), ".")), !configMissing && section === "add" && /* @__PURE__ */ React320.createElement(Stack211, { gap: "sm" }, revokeTarget && /* @__PURE__ */ React320.createElement(DismissibleAlert, { color: "yellow", styles: actionAlertStyles }, "A revoke is currently armed. Switch to the Users tab to sign it, or change the grantee below to arm an add instead."), /* @__PURE__ */ React320.createElement(
|
|
35254
|
+
}), revokeTarget && /* @__PURE__ */ React320.createElement(DismissibleAlert, { color: "red", styles: actionAlertStyles }, "Slide to sign to revoke ", roleLabel(revokeTarget.role), " from ", truncateAddress4(revokeTarget.address), ".")), !configMissing && section === "add" && /* @__PURE__ */ React320.createElement(Stack211, { gap: "sm" }, revokeTarget && /* @__PURE__ */ React320.createElement(DismissibleAlert, { color: "yellow", styles: actionAlertStyles }, "A revoke is currently armed. Switch to the Users tab to sign it, or change the grantee below to arm an add instead."), /* @__PURE__ */ React320.createElement(
|
|
35255
|
+
SegmentedControl16,
|
|
35256
|
+
{
|
|
35257
|
+
fullWidth: true,
|
|
35258
|
+
size: "xs",
|
|
35259
|
+
value: addMode,
|
|
35260
|
+
onChange: (value) => handleAddModeChange(value),
|
|
35261
|
+
disabled: isDisabled || isRunning,
|
|
35262
|
+
data: [
|
|
35263
|
+
{ label: "One account", value: "single" },
|
|
35264
|
+
{ label: "Paste a list", value: "list" }
|
|
35265
|
+
]
|
|
35266
|
+
}
|
|
35267
|
+
), addMode === "list" && /* @__PURE__ */ React320.createElement(
|
|
35268
|
+
BulkAccountsInput,
|
|
35269
|
+
{
|
|
35270
|
+
text: bulkText,
|
|
35271
|
+
onChange: setBulkText,
|
|
35272
|
+
parsed: parsedAccounts,
|
|
35273
|
+
isDisabled: isDisabled || isRunning,
|
|
35274
|
+
canBatchGrants,
|
|
35275
|
+
actingAsGroup: actAs.actAsGroup
|
|
35276
|
+
}
|
|
35277
|
+
), addMode === "single" && /* @__PURE__ */ React320.createElement(Stack211, { gap: 4 }, /* @__PURE__ */ React320.createElement(Text199, { size: "sm", fw: 500 }, "Grantee address"), /* @__PURE__ */ React320.createElement(
|
|
34383
35278
|
RecipientInput,
|
|
34384
35279
|
{
|
|
34385
35280
|
value: addAddress,
|
|
@@ -34388,10 +35283,11 @@ var CollectionUsersFlowDetail = ({
|
|
|
34388
35283
|
setRevokeTarget(null);
|
|
34389
35284
|
setAddAddress(address);
|
|
34390
35285
|
},
|
|
35286
|
+
onBulkPaste: handleBulkPaste,
|
|
34391
35287
|
isDisabled: isDisabled || isRunning,
|
|
34392
35288
|
placeholder: "Search by name / @user:\u2026, or paste an ixo1\u2026 address"
|
|
34393
35289
|
}
|
|
34394
|
-
)), canClassify ? /* @__PURE__ */ React320.createElement(Button67, { size: "xs", variant: "light", onClick: runClassify, disabled: !addAddress.trim() || classifying || isRunning, loading: classifying }, "Check address") : /* @__PURE__ */ React320.createElement(Text199, { size: "xs", c: "dimmed" }, "Address classification is unavailable in this host \u2014 the grantee will be added as a plain account."), classifyError && /* @__PURE__ */ React320.createElement(DismissibleAlert, { color: "red", styles: actionAlertStyles }, classifyError), isGroup && /* @__PURE__ */ React320.createElement(Box60, { style: { border: "1px solid var(--mantine-color-neutralColor-6)", borderRadius: 8, padding: 12 } }, /* @__PURE__ */ React320.createElement(Stack211, { gap: "xs" }, /* @__PURE__ */ React320.createElement(Text199, { size: "sm", fw: 600 }, "Add the group, or all the members of the POD?"), /* @__PURE__ */ React320.createElement(Text199, { size: "xs", c: "dimmed" }, "Detected a DAO DAO group (", classification?.daodao?.type, "). Choose how to grant access."), /* @__PURE__ */ React320.createElement(Radio5.Group, { value: granteeKind, onChange: (value) => setGranteeKind(value) }, /* @__PURE__ */ React320.createElement(Stack211, { gap: "xs", mt: "xs" }, /* @__PURE__ */ React320.createElement(
|
|
35290
|
+
)), addMode === "single" && (canClassify ? /* @__PURE__ */ React320.createElement(Button67, { size: "xs", variant: "light", onClick: runClassify, disabled: !addAddress.trim() || classifying || isRunning, loading: classifying }, "Check address") : /* @__PURE__ */ React320.createElement(Text199, { size: "xs", c: "dimmed" }, "Address classification is unavailable in this host \u2014 the grantee will be added as a plain account.")), addMode === "single" && classifyError && /* @__PURE__ */ React320.createElement(DismissibleAlert, { color: "red", styles: actionAlertStyles }, classifyError), addMode === "single" && isGroup && /* @__PURE__ */ React320.createElement(Box60, { style: { border: "1px solid var(--mantine-color-neutralColor-6)", borderRadius: 8, padding: 12 } }, /* @__PURE__ */ React320.createElement(Stack211, { gap: "xs" }, /* @__PURE__ */ React320.createElement(Text199, { size: "sm", fw: 600 }, "Add the group, or all the members of the POD?"), /* @__PURE__ */ React320.createElement(Text199, { size: "xs", c: "dimmed" }, "Detected a DAO DAO group (", classification?.daodao?.type, "). Choose how to grant access."), /* @__PURE__ */ React320.createElement(Radio5.Group, { value: granteeKind, onChange: (value) => setGranteeKind(value) }, /* @__PURE__ */ React320.createElement(Stack211, { gap: "xs", mt: "xs" }, /* @__PURE__ */ React320.createElement(
|
|
34395
35291
|
Radio5,
|
|
34396
35292
|
{
|
|
34397
35293
|
value: "group-account",
|
|
@@ -34405,7 +35301,7 @@ var CollectionUsersFlowDetail = ({
|
|
|
34405
35301
|
disabled: isDisabled || isRunning,
|
|
34406
35302
|
label: /* @__PURE__ */ React320.createElement(Stack211, { gap: 0 }, /* @__PURE__ */ React320.createElement(Text199, { size: "sm" }, "Add all members of the POD"), /* @__PURE__ */ React320.createElement(Text199, { size: "xs", c: "dimmed" }, canEnumerate ? `Fan out: grant each member individually${members.length ? ` (${members.length} resolved)` : ""}.` : "Member enumeration is unavailable in this host."))
|
|
34407
35303
|
}
|
|
34408
|
-
))))), /* @__PURE__ */ React320.createElement(
|
|
35304
|
+
))), granteeKind === "group-members" && !actAs.actAsGroup && memberSigningPlan && /* @__PURE__ */ React320.createElement(DismissibleAlert, { color: memberSigningPlan.color, styles: actionAlertStyles }, memberSigningPlan.message))), addMode === "list" && bulkAddresses.length > 0 && /* @__PURE__ */ React320.createElement(Text199, { size: "xs", c: "dimmed" }, "The role, quota and limits below apply to all ", bulkAddresses.length, " accounts."), /* @__PURE__ */ React320.createElement(
|
|
34409
35305
|
BaseSelect,
|
|
34410
35306
|
{
|
|
34411
35307
|
label: "Role",
|
|
@@ -34471,31 +35367,64 @@ var BidInboxSection = ({
|
|
|
34471
35367
|
const role = String(selectedBid?.role || "").toLowerCase();
|
|
34472
35368
|
return role === "evaluation_agent" || role === "ea";
|
|
34473
35369
|
}, [selectedBid]);
|
|
35370
|
+
const bidStatusContext = useMemo120(() => ({ grantees, evaluatedByBidId }), [grantees, evaluatedByBidId]);
|
|
34474
35371
|
const bidEvaluatedStatus = useCallback112(
|
|
34475
35372
|
(bid) => {
|
|
34476
|
-
const
|
|
34477
|
-
|
|
34478
|
-
const role = String(bid.role || "").toLowerCase();
|
|
34479
|
-
const grantRole = role === "evaluation_agent" || role === "ea" ? "evaluate" : "submit";
|
|
34480
|
-
return grantees.some((g) => g.address === bid.address && g.role === grantRole) ? "approved" : null;
|
|
35373
|
+
const info = getBidStatusInfo(bid, bidStatusContext);
|
|
35374
|
+
return info.key === "pending" ? null : info.key;
|
|
34481
35375
|
},
|
|
34482
|
-
[
|
|
35376
|
+
[bidStatusContext]
|
|
35377
|
+
);
|
|
35378
|
+
const bidRowOptions = useMemo120(
|
|
35379
|
+
() => ({
|
|
35380
|
+
evaluatedByBidId,
|
|
35381
|
+
namesByDid: Object.fromEntries(Object.entries(profilesByDid).map(([did, profile]) => [did, profile?.displayname || ""]))
|
|
35382
|
+
}),
|
|
35383
|
+
[evaluatedByBidId, profilesByDid]
|
|
34483
35384
|
);
|
|
34484
35385
|
const downloadBidsCsv = useCallback112(
|
|
34485
35386
|
(subset, filename) => {
|
|
34486
|
-
downloadArrayAsCsv(buildBidRows(subset, grantees), { filename });
|
|
35387
|
+
downloadArrayAsCsv(buildBidRows(subset, grantees, bidRowOptions), { filename });
|
|
35388
|
+
},
|
|
35389
|
+
[grantees, bidRowOptions]
|
|
35390
|
+
);
|
|
35391
|
+
const downloadBidsZip = useCallback112(
|
|
35392
|
+
async (subset, names) => {
|
|
35393
|
+
const handlers = handlersRef.current;
|
|
35394
|
+
const fetchMedia = handlers.fetchClaimMedia ? (url) => handlers.fetchClaimMedia(url, { entityDid: deedDid }) : void 0;
|
|
35395
|
+
const { blob, mediaTotal, mediaFailed } = await buildExportBundle({
|
|
35396
|
+
records: subset.map((bid) => ({
|
|
35397
|
+
recordId: bid.id,
|
|
35398
|
+
answers: bidAnswers(bid),
|
|
35399
|
+
manifest: {
|
|
35400
|
+
bidId: bid.id,
|
|
35401
|
+
did: bid.did,
|
|
35402
|
+
address: bid.address,
|
|
35403
|
+
role: bid.role,
|
|
35404
|
+
created: bid.created,
|
|
35405
|
+
status: getBidStatusInfo(bid, bidStatusContext).key
|
|
35406
|
+
}
|
|
35407
|
+
})),
|
|
35408
|
+
fetchMedia,
|
|
35409
|
+
renderCsv: (answersByBidId) => rowsToCsv(buildBidRows(subset, grantees, { ...bidRowOptions, answersByBidId })),
|
|
35410
|
+
csvName: names.csv,
|
|
35411
|
+
manifestName: names.manifest
|
|
35412
|
+
});
|
|
35413
|
+
downloadBlob(blob, names.zip);
|
|
35414
|
+
setError(mediaFailed > 0 ? `${mediaFailed} of ${mediaTotal} media files could not be downloaded \u2014 see downloadStatus in ${names.manifest}.` : null);
|
|
34487
35415
|
},
|
|
34488
|
-
[grantees]
|
|
35416
|
+
[grantees, bidRowOptions, bidStatusContext, deedDid, handlersRef]
|
|
34489
35417
|
);
|
|
34490
|
-
const handleDownloadBidsCsv = useCallback112(() => downloadBidsCsv(bids,
|
|
35418
|
+
const handleDownloadBidsCsv = useCallback112(() => downloadBidsCsv(bids, exportFileNames.bids(collectionId).csv), [downloadBidsCsv, bids, collectionId]);
|
|
35419
|
+
const handleDownloadBidsZip = useCallback112(() => downloadBidsZip(bids, exportFileNames.bids(collectionId)), [downloadBidsZip, bids, collectionId]);
|
|
34491
35420
|
const refreshBids = useCallback112(async () => {
|
|
34492
35421
|
if (!deedDid || !collectionId) return;
|
|
34493
35422
|
setLoading(true);
|
|
34494
35423
|
setError(null);
|
|
34495
35424
|
try {
|
|
34496
|
-
const
|
|
34497
|
-
|
|
34498
|
-
|
|
35425
|
+
const result = await fetchAllBids(handlersRef.current.queryBids, { collectionId, entityDid: deedDid });
|
|
35426
|
+
setBids(dedupeBids(result.bids));
|
|
35427
|
+
setError(result.truncated ? "Bid paging stopped early \u2014 this list may be incomplete." : null);
|
|
34499
35428
|
} catch {
|
|
34500
35429
|
setBids([]);
|
|
34501
35430
|
setError(null);
|
|
@@ -34681,7 +35610,7 @@ var BidInboxSection = ({
|
|
|
34681
35610
|
}
|
|
34682
35611
|
] : []
|
|
34683
35612
|
];
|
|
34684
|
-
return /* @__PURE__ */ React320.createElement(Stack211, { gap: "md" }, /* @__PURE__ */ React320.createElement(Group116, { gap: "xs", align: "center" }, /* @__PURE__ */ React320.createElement(ActionIcon47, { variant: "subtle", color: "gray", size: "sm", onClick: () => setSelectedBidId("") }, /* @__PURE__ */ React320.createElement(IconArrowLeft10, { size: 16 })), /* @__PURE__ */ React320.createElement(Text199, { fw: 500, size: "sm", truncate: true, style: { flex: 1, minWidth: 0 } }, "Bid #", selectedBid.id), /* @__PURE__ */ React320.createElement(DownloadCsvButton, { onDownload: () => downloadBidsCsv([selectedBid],
|
|
35613
|
+
return /* @__PURE__ */ React320.createElement(Stack211, { gap: "md" }, /* @__PURE__ */ React320.createElement(Group116, { gap: "xs", align: "center" }, /* @__PURE__ */ React320.createElement(ActionIcon47, { variant: "subtle", color: "gray", size: "sm", onClick: () => setSelectedBidId("") }, /* @__PURE__ */ React320.createElement(IconArrowLeft10, { size: 16 })), /* @__PURE__ */ React320.createElement(Text199, { fw: 500, size: "sm", truncate: true, style: { flex: 1, minWidth: 0 } }, "Bid #", selectedBid.id), /* @__PURE__ */ React320.createElement(DownloadCsvButton, { onDownload: () => downloadBidsCsv([selectedBid], exportFileNames.bid(selectedBid.id).csv), label: "Download bid CSV", onError: setError }), /* @__PURE__ */ React320.createElement(DownloadZipButton, { onDownload: () => downloadBidsZip([selectedBid], exportFileNames.bid(selectedBid.id)), label: "Download bid + media (ZIP)", onError: setError })), /* @__PURE__ */ React320.createElement(Stack211, { gap: 4 }, /* @__PURE__ */ React320.createElement(Text199, { size: "sm", fw: 600, truncate: true }, displayName), /* @__PURE__ */ React320.createElement(Group116, { gap: "xs" }, /* @__PURE__ */ React320.createElement(Badge52, { size: "xs", variant: "light", color: getRoleColor3(selectedBid.role) }, getBidRoleLabel(selectedBid.role)), /* @__PURE__ */ React320.createElement(Text199, { size: "xs", c: "dimmed" }, truncateAddress4(selectedBid.address)))), /* @__PURE__ */ React320.createElement(CollapsibleSection, { title: "Inputs" }, bidData && typeof bidData === "object" && Object.keys(bidData).length > 0 ? /* @__PURE__ */ React320.createElement(ReadableKeyValues, { data: bidData }) : /* @__PURE__ */ React320.createElement(Text199, { size: "xs", c: "dimmed" }, "No input data available.")), evaluatedStatus ? /* @__PURE__ */ React320.createElement(
|
|
34685
35614
|
MantineAlert,
|
|
34686
35615
|
{
|
|
34687
35616
|
color: evaluatedStatus === "approved" ? "green" : "red",
|
|
@@ -34745,7 +35674,7 @@ var BidInboxSection = ({
|
|
|
34745
35674
|
styles: actionAlertStyles
|
|
34746
35675
|
},
|
|
34747
35676
|
lastDecision.kind === "proposed" ? `Proposal #${lastDecision.proposalId} asks the POD to grant ${lastDecision.roleLabel} access to ${lastDecision.name}. Nothing is granted until the vote passes \u2014 the bid stays pending until then.` : lastDecision.kind === "approved" ? `${lastDecision.roleLabel} access granted to ${lastDecision.name}. They can now ${lastDecision.roleLabel === "Evaluator" ? "evaluate" : "submit"} claims in this collection.` : `${lastDecision.name}'s application was declined.`
|
|
34748
|
-
), /* @__PURE__ */ React320.createElement(Group116, { justify: "space-between", align: "center" }, /* @__PURE__ */ React320.createElement(Text199, { size: "sm", fw: 600 }, "Incoming bids"), /* @__PURE__ */ React320.createElement(Group116, { gap: 4 }, /* @__PURE__ */ React320.createElement(DownloadCsvButton, { onDownload: handleDownloadBidsCsv, disabled: loading || bids.length === 0, label: "Download bids CSV" }), /* @__PURE__ */ React320.createElement(ActionIcon47, { variant: "subtle", color: "gray", size: "sm", onClick: refreshBids, disabled: loading }, /* @__PURE__ */ React320.createElement(IconRefresh9, { size: 16 })))), /* @__PURE__ */ React320.createElement(Divider22, { color: "color-mix(in srgb, var(--mantine-color-text) 6%, transparent)" }), loading && /* @__PURE__ */ React320.createElement(Group116, { gap: "xs", justify: "center", py: "sm" }, /* @__PURE__ */ React320.createElement(Loader61, { size: "xs" }), /* @__PURE__ */ React320.createElement(Text199, { size: "xs", c: "dimmed" }, "Loading bids\u2026")), !loading && bids.length === 0 && /* @__PURE__ */ React320.createElement(Text199, { size: "sm", c: "dimmed", ta: "center", py: "sm" }, "No bids available for this collection."), bids.map((bid) => {
|
|
35677
|
+
), /* @__PURE__ */ React320.createElement(Group116, { justify: "space-between", align: "center" }, /* @__PURE__ */ React320.createElement(Text199, { size: "sm", fw: 600 }, "Incoming bids"), /* @__PURE__ */ React320.createElement(Group116, { gap: 4 }, /* @__PURE__ */ React320.createElement(DownloadCsvButton, { onDownload: handleDownloadBidsCsv, disabled: loading || bids.length === 0, label: "Download bids CSV", onError: setError }), /* @__PURE__ */ React320.createElement(DownloadZipButton, { onDownload: handleDownloadBidsZip, disabled: loading || bids.length === 0, label: "Download bids + media (ZIP)", onError: setError }), /* @__PURE__ */ React320.createElement(ActionIcon47, { variant: "subtle", color: "gray", size: "sm", onClick: refreshBids, disabled: loading }, /* @__PURE__ */ React320.createElement(IconRefresh9, { size: 16 })))), /* @__PURE__ */ React320.createElement(Divider22, { color: "color-mix(in srgb, var(--mantine-color-text) 6%, transparent)" }), loading && /* @__PURE__ */ React320.createElement(Group116, { gap: "xs", justify: "center", py: "sm" }, /* @__PURE__ */ React320.createElement(Loader61, { size: "xs" }), /* @__PURE__ */ React320.createElement(Text199, { size: "xs", c: "dimmed" }, "Loading bids\u2026")), !loading && bids.length === 0 && /* @__PURE__ */ React320.createElement(Text199, { size: "sm", c: "dimmed", ta: "center", py: "sm" }, "No bids available for this collection."), bids.map((bid) => {
|
|
34749
35678
|
const profile = profilesByDid[bid.did];
|
|
34750
35679
|
const displayName = profile?.displayname || bid.did || bid.address;
|
|
34751
35680
|
const status = bidEvaluatedStatus(bid) || "pending";
|
|
@@ -41121,8 +42050,8 @@ var EvaluateClaimFlowDetail = ({
|
|
|
41121
42050
|
if (!deedDid || !collectionId) return;
|
|
41122
42051
|
void refreshClaims();
|
|
41123
42052
|
}, [deedDid, collectionId, refreshClaims]);
|
|
41124
|
-
const
|
|
41125
|
-
async (subset
|
|
42053
|
+
const fetchClaimContents = useCallback119(
|
|
42054
|
+
async (subset) => {
|
|
41126
42055
|
const handlers2 = handlersRef.current;
|
|
41127
42056
|
const contentsByClaimId = {};
|
|
41128
42057
|
await Promise.all(
|
|
@@ -41134,11 +42063,60 @@ var EvaluateClaimFlowDetail = ({
|
|
|
41134
42063
|
}
|
|
41135
42064
|
})
|
|
41136
42065
|
);
|
|
41137
|
-
|
|
42066
|
+
return contentsByClaimId;
|
|
41138
42067
|
},
|
|
41139
42068
|
[collectionId, deedDid]
|
|
41140
42069
|
);
|
|
41141
|
-
const
|
|
42070
|
+
const downloadClaimsCsv = useCallback119(
|
|
42071
|
+
async (subset, filename) => {
|
|
42072
|
+
downloadArrayAsCsv(buildClaimRows(subset, await fetchClaimContents(subset)), { filename });
|
|
42073
|
+
},
|
|
42074
|
+
[fetchClaimContents]
|
|
42075
|
+
);
|
|
42076
|
+
const titlesByFieldName = useMemo132(() => {
|
|
42077
|
+
const titles = {};
|
|
42078
|
+
if (!surveyJson) return titles;
|
|
42079
|
+
try {
|
|
42080
|
+
for (const question of new SurveyModel11(surveyJson).getAllQuestions()) {
|
|
42081
|
+
if (question.name) titles[question.name] = question.title || question.name;
|
|
42082
|
+
}
|
|
42083
|
+
} catch {
|
|
42084
|
+
return titles;
|
|
42085
|
+
}
|
|
42086
|
+
return titles;
|
|
42087
|
+
}, [surveyJson]);
|
|
42088
|
+
const downloadClaimsZip = useCallback119(
|
|
42089
|
+
async (subset, names) => {
|
|
42090
|
+
const handlers2 = handlersRef.current;
|
|
42091
|
+
const contentsByClaimId = await fetchClaimContents(subset);
|
|
42092
|
+
const fetchMedia = handlers2.fetchClaimMedia ? (url) => handlers2.fetchClaimMedia(url, { entityDid: deedDid }) : void 0;
|
|
42093
|
+
const { blob, mediaTotal, mediaFailed } = await buildExportBundle({
|
|
42094
|
+
records: subset.map((claim) => ({
|
|
42095
|
+
recordId: claim.claimId,
|
|
42096
|
+
answers: claimAnswers(contentsByClaimId[claim.claimId]),
|
|
42097
|
+
manifest: {
|
|
42098
|
+
claimId: claim.claimId,
|
|
42099
|
+
collectionId: claim.collectionId,
|
|
42100
|
+
agentAddress: claim.agentAddress,
|
|
42101
|
+
submissionDate: claim.submissionDate,
|
|
42102
|
+
status: getClaimStatusInfo(claim).key
|
|
42103
|
+
}
|
|
42104
|
+
})),
|
|
42105
|
+
titlesByFieldName,
|
|
42106
|
+
fetchMedia,
|
|
42107
|
+
renderCsv: (answersByClaimId) => rowsToCsv(buildClaimRows(subset, contentsByClaimId, { answersByClaimId })),
|
|
42108
|
+
csvName: names.csv,
|
|
42109
|
+
manifestName: names.manifest
|
|
42110
|
+
});
|
|
42111
|
+
downloadBlob(blob, names.zip);
|
|
42112
|
+
if (mediaFailed > 0) {
|
|
42113
|
+
setError(`${mediaFailed} of ${mediaTotal} media files could not be downloaded \u2014 see downloadStatus in ${names.manifest}.`);
|
|
42114
|
+
}
|
|
42115
|
+
},
|
|
42116
|
+
[fetchClaimContents, deedDid, titlesByFieldName]
|
|
42117
|
+
);
|
|
42118
|
+
const handleDownloadClaimsCsv = useCallback119(() => downloadClaimsCsv(claims, exportFileNames.claims(collectionId).csv), [downloadClaimsCsv, claims, collectionId]);
|
|
42119
|
+
const handleDownloadClaimsZip = useCallback119(() => downloadClaimsZip(claims, exportFileNames.claims(collectionId)), [downloadClaimsZip, claims, collectionId]);
|
|
41142
42120
|
useEffect127(() => {
|
|
41143
42121
|
let mounted = true;
|
|
41144
42122
|
const dids = Array.from(new Set(claims.map((claim) => claim.agentDid).filter(Boolean)));
|
|
@@ -41472,11 +42450,25 @@ var EvaluateClaimFlowDetail = ({
|
|
|
41472
42450
|
]);
|
|
41473
42451
|
const flowManagerContext = /* @__PURE__ */ React347.createElement(FlowManagerContextSection, { record: nodeContext, onOverride: setNodeContextOverride, disabled: isDisabled });
|
|
41474
42452
|
if (selectedClaim) {
|
|
41475
|
-
const
|
|
42453
|
+
const claimStatus = getClaimStatusInfo(selectedClaim);
|
|
41476
42454
|
const selectedClaimProfile = profilesByDid[selectedClaim.agentDid];
|
|
41477
42455
|
const selectedDisplayName = selectedClaimProfile?.displayname || selectedClaim.agentDid || selectedClaim.agentAddress;
|
|
41478
42456
|
const selectedAvatarLabel = (selectedClaimProfile?.displayname || selectedClaim.agentDid || selectedClaim.agentAddress || "?")[0]?.toUpperCase();
|
|
41479
|
-
return /* @__PURE__ */ React347.createElement(Stack236, { gap: "md" }, /* @__PURE__ */ React347.createElement(Group142, { gap: "xs", align: "center" }, /* @__PURE__ */ React347.createElement(ActionIcon57, { variant: "subtle", color: "gray", size: "sm", onClick: () => setSelectedClaimId("") }, /* @__PURE__ */ React347.createElement(IconArrowLeft11, { size: 16 })), /* @__PURE__ */ React347.createElement(Text224, { fw: 500, size: "sm", title: selectedClaim.claimId, truncate: true, style: { flex: 1, minWidth: 0 } }, t("actionTypes.claim.flow.claimNumber", { id: truncateId2(selectedClaim.claimId), defaultValue: `Claim #${truncateId2(selectedClaim.claimId)}` })), /* @__PURE__ */ React347.createElement(
|
|
42457
|
+
return /* @__PURE__ */ React347.createElement(Stack236, { gap: "md" }, /* @__PURE__ */ React347.createElement(Group142, { gap: "xs", align: "center" }, /* @__PURE__ */ React347.createElement(ActionIcon57, { variant: "subtle", color: "gray", size: "sm", onClick: () => setSelectedClaimId("") }, /* @__PURE__ */ React347.createElement(IconArrowLeft11, { size: 16 })), /* @__PURE__ */ React347.createElement(Text224, { fw: 500, size: "sm", title: selectedClaim.claimId, truncate: true, style: { flex: 1, minWidth: 0 } }, t("actionTypes.claim.flow.claimNumber", { id: truncateId2(selectedClaim.claimId), defaultValue: `Claim #${truncateId2(selectedClaim.claimId)}` })), /* @__PURE__ */ React347.createElement(
|
|
42458
|
+
DownloadCsvButton,
|
|
42459
|
+
{
|
|
42460
|
+
onDownload: () => downloadClaimsCsv([selectedClaim], exportFileNames.claim(selectedClaim.claimId).csv),
|
|
42461
|
+
label: "Download claim CSV",
|
|
42462
|
+
onError: setError
|
|
42463
|
+
}
|
|
42464
|
+
), /* @__PURE__ */ React347.createElement(
|
|
42465
|
+
DownloadZipButton,
|
|
42466
|
+
{
|
|
42467
|
+
onDownload: () => downloadClaimsZip([selectedClaim], exportFileNames.claim(selectedClaim.claimId)),
|
|
42468
|
+
label: "Download claim + media (ZIP)",
|
|
42469
|
+
onError: setError
|
|
42470
|
+
}
|
|
42471
|
+
)), /* @__PURE__ */ React347.createElement(Group142, { gap: 16, align: "center", style: { width: "100%" } }, /* @__PURE__ */ React347.createElement(
|
|
41480
42472
|
Box69,
|
|
41481
42473
|
{
|
|
41482
42474
|
style: {
|
|
@@ -41497,7 +42489,7 @@ var EvaluateClaimFlowDetail = ({
|
|
|
41497
42489
|
}
|
|
41498
42490
|
},
|
|
41499
42491
|
selectedClaimProfile?.avatarUrl ? null : selectedAvatarLabel
|
|
41500
|
-
), /* @__PURE__ */ React347.createElement(Stack236, { gap: 0, style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ React347.createElement(Text224, { fw: 500, size: "md", truncate: true }, selectedDisplayName), /* @__PURE__ */ React347.createElement(Text224, { size: "xs", c: "dimmed", truncate: true }, truncateAddress5(selectedClaim.agentAddress))), /* @__PURE__ */ React347.createElement(Text224, { size: "xs", c: "dimmed", style: { flexShrink: 0 } }, getTimeAgo4(selectedClaim.submissionDate || ""))),
|
|
42492
|
+
), /* @__PURE__ */ React347.createElement(Stack236, { gap: 0, style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ React347.createElement(Text224, { fw: 500, size: "md", truncate: true }, selectedDisplayName), /* @__PURE__ */ React347.createElement(Text224, { size: "xs", c: "dimmed", truncate: true }, truncateAddress5(selectedClaim.agentAddress))), /* @__PURE__ */ React347.createElement(Text224, { size: "xs", c: "dimmed", style: { flexShrink: 0 } }, getTimeAgo4(selectedClaim.submissionDate || ""))), claimStatus.key === "disputed" && /* @__PURE__ */ React347.createElement(DismissibleAlert, { color: "orange", title: t("actionTypes.claim.flow.disputed.title", { defaultValue: "Claim disputed" }), styles: actionAlertStyles }, loadingDispute ? /* @__PURE__ */ React347.createElement(Group142, { gap: "xs" }, /* @__PURE__ */ React347.createElement(Loader69, { size: "xs" }), /* @__PURE__ */ React347.createElement(Text224, { size: "xs" }, t("actionTypes.claim.flow.disputed.loadingDetails", { defaultValue: "Loading dispute details\u2026" }))) : disputeDetails ? /* @__PURE__ */ React347.createElement(Stack236, { gap: 6 }, disputeDetails.reason ? /* @__PURE__ */ React347.createElement(Text224, { size: "sm" }, disputeDetails.reason) : /* @__PURE__ */ React347.createElement(Text224, { size: "sm", c: "dimmed" }, t("actionTypes.evaluateClaim.flow.disputed.noMessageAttached", { defaultValue: "A dispute was recorded but no message was attached." })), (disputeDetails.evaluatorDid || disputeDetails.disputedAt) && /* @__PURE__ */ React347.createElement(Text224, { size: "xs", c: "dimmed" }, disputeDetails.evaluatorDid ? t("actionTypes.claim.flow.disputed.byEvaluator", {
|
|
41501
42493
|
address: truncateAddress5(disputeDetails.evaluatorDid),
|
|
41502
42494
|
defaultValue: `By ${truncateAddress5(disputeDetails.evaluatorDid)}`
|
|
41503
42495
|
}) : "", disputeDetails.evaluatorDid && disputeDetails.disputedAt ? " \xB7 " : "", disputeDetails.disputedAt ? new Date(disputeDetails.disputedAt).toLocaleString() : ""), /* @__PURE__ */ React347.createElement(Text224, { size: "xs", c: "dimmed" }, t("actionTypes.evaluateClaim.flow.disputed.amendNeeded", { defaultValue: "The submitter needs to amend and resubmit before this claim can be evaluated." }))) : typeof handlers.getClaimDisputeDetails !== "function" ? /* @__PURE__ */ React347.createElement(Text224, { size: "xs", c: "dimmed" }, t("actionTypes.claim.flow.disputed.unavailable", { defaultValue: "Dispute details unavailable in this environment." })) : /* @__PURE__ */ React347.createElement(Text224, { size: "xs", c: "dimmed" }, t("actionTypes.claim.flow.disputed.noRecord", { defaultValue: "No dispute record found on-chain for this claim." }))), engine.supported && (engine.forbidden ? /* @__PURE__ */ React347.createElement(DismissibleAlert, { color: "gray", styles: actionAlertStyles }, "You need evaluator access on this collection to see the engine's results.") : engine.loading && !engine.record ? /* @__PURE__ */ React347.createElement(Group142, { gap: "xs" }, /* @__PURE__ */ React347.createElement(Loader69, { size: "xs" }), /* @__PURE__ */ React347.createElement(Text224, { size: "xs", c: "dimmed" }, "Checking what the engine knows about this claim\u2026")) : /* @__PURE__ */ React347.createElement(React347.Fragment, null, /* @__PURE__ */ React347.createElement(
|
|
@@ -41602,7 +42594,7 @@ var EvaluateClaimFlowDetail = ({
|
|
|
41602
42594
|
checked: createUdid,
|
|
41603
42595
|
onChange: (event) => setCreateUdid(event.currentTarget.checked)
|
|
41604
42596
|
}
|
|
41605
|
-
))), engine.supported && !engine.forbidden && engine.record && /* @__PURE__ */ React347.createElement(CollapsibleSection, { title: "Technical details" }, /* @__PURE__ */ React347.createElement(TechnicalDetails, { record: engine.record, onChain: onChainDisplay })), outcomeNotReady && !isClaimAlreadyEvaluated && /* @__PURE__ */ React347.createElement(DismissibleAlert, { color: "yellow", styles: actionAlertStyles }, t("actionTypes.evaluateClaim.flow.outcome.completeBeforeAction", { defaultValue: "Complete the Outcome evaluation template before approving or rejecting." })), isClaimAlreadyEvaluated &&
|
|
42597
|
+
))), engine.supported && !engine.forbidden && engine.record && /* @__PURE__ */ React347.createElement(CollapsibleSection, { title: "Technical details" }, /* @__PURE__ */ React347.createElement(TechnicalDetails, { record: engine.record, onChain: onChainDisplay })), outcomeNotReady && !isClaimAlreadyEvaluated && /* @__PURE__ */ React347.createElement(DismissibleAlert, { color: "yellow", styles: actionAlertStyles }, t("actionTypes.evaluateClaim.flow.outcome.completeBeforeAction", { defaultValue: "Complete the Outcome evaluation template before approving or rejecting." })), isClaimAlreadyEvaluated && claimStatus.key !== "disputed" && /* @__PURE__ */ React347.createElement(DismissibleAlert, { color: "yellow", styles: actionAlertStyles }, /* @__PURE__ */ React347.createElement(Stack236, { gap: 4 }, /* @__PURE__ */ React347.createElement(Text224, { size: "sm" }, t("actionTypes.evaluateClaim.flow.alreadyEvaluated", { defaultValue: "This claim is already evaluated." })), evaluationAmount && evaluationAmount.length > 0 && /* @__PURE__ */ React347.createElement(Text224, { size: "xs", c: "dimmed" }, t("actionTypes.evaluateClaim.flow.transferredOnChain", {
|
|
41606
42598
|
amount: evaluationAmount.map(formatCoin).join(", "),
|
|
41607
42599
|
defaultValue: `Transferred on-chain: ${evaluationAmount.map(formatCoin).join(", ")}`
|
|
41608
42600
|
})))), !authChecking && authError && /* @__PURE__ */ React347.createElement(DismissibleAlert, { color: "orange", styles: actionAlertStyles }, /* @__PURE__ */ React347.createElement(Stack236, { gap: "xs" }, /* @__PURE__ */ React347.createElement(Text224, { size: "sm" }, t("actionTypes.claim.flow.authVerifyFailed", { defaultValue: "Couldn't verify your authorization \u2014 the chain RPC is unreachable." })), /* @__PURE__ */ React347.createElement(Text224, { size: "xs", c: "dimmed" }, authError), /* @__PURE__ */ React347.createElement(Button80, { size: "xs", variant: "light", onClick: () => setAuthRetryKey((k) => k + 1) }, t("actionTypes.claim.flow.retry", { defaultValue: "Retry" })))), !authChecking && !authError && !isEvaluatorAuthorized && /* @__PURE__ */ React347.createElement(DismissibleAlert, { color: "yellow", styles: actionAlertStyles }, t("actionTypes.evaluateClaim.flow.notAuthorized", { defaultValue: "You need evaluator authorization for this collection to approve or reject claims." })), !isClaimAlreadyEvaluated && /* @__PURE__ */ React347.createElement(
|
|
@@ -41668,7 +42660,7 @@ var EvaluateClaimFlowDetail = ({
|
|
|
41668
42660
|
}
|
|
41669
42661
|
},
|
|
41670
42662
|
/* @__PURE__ */ React347.createElement(IconRefresh11, { size: 16 })
|
|
41671
|
-
), /* @__PURE__ */ React347.createElement(DownloadCsvButton, { onDownload: handleDownloadClaimsCsv, disabled: loadingClaims || claims.length === 0, label: "Download claims CSV" }), /* @__PURE__ */ React347.createElement(ActionIcon57, { variant: "subtle", color: "gray", size: "sm" }, /* @__PURE__ */ React347.createElement(IconFilter2, { size: 16 })))), engineSummaries.supported && engineSummaries.notEnrolled && /* @__PURE__ */ React347.createElement(EnginePromo, null), loadingClaims && /* @__PURE__ */ React347.createElement(Group142, { gap: "xs", justify: "center", py: "md" }, /* @__PURE__ */ React347.createElement(Loader69, { size: "xs" }), /* @__PURE__ */ React347.createElement(Text224, { size: "xs", c: "dimmed" }, t("actionTypes.evaluateClaim.flow.loadingClaims", { defaultValue: "Loading claims..." }))), !loadingClaims && filteredClaims.length === 0 && /* @__PURE__ */ React347.createElement(Text224, { size: "sm", c: "dimmed", ta: "center", py: "md" }, claims.length === 0 ? t("actionTypes.evaluateClaim.flow.empty.allCollections", { defaultValue: "No claims available for this collection." }) : activeFilter === "owed" ? "No claims are waiting on you right now." : t("actionTypes.evaluateClaim.flow.empty.filtered", { filter: activeFilter, defaultValue: `No ${activeFilter} claims found.` })), filteredClaims.length > 0 && /* @__PURE__ */ React347.createElement(Stack236, { gap: 12 }, filteredClaims.map((claim) => {
|
|
42663
|
+
), /* @__PURE__ */ React347.createElement(DownloadCsvButton, { onDownload: handleDownloadClaimsCsv, disabled: loadingClaims || claims.length === 0, label: "Download claims CSV", onError: setError }), /* @__PURE__ */ React347.createElement(DownloadZipButton, { onDownload: handleDownloadClaimsZip, disabled: loadingClaims || claims.length === 0, label: "Download claims + media (ZIP)", onError: setError }), /* @__PURE__ */ React347.createElement(ActionIcon57, { variant: "subtle", color: "gray", size: "sm" }, /* @__PURE__ */ React347.createElement(IconFilter2, { size: 16 })))), engineSummaries.supported && engineSummaries.notEnrolled && /* @__PURE__ */ React347.createElement(EnginePromo, null), loadingClaims && /* @__PURE__ */ React347.createElement(Group142, { gap: "xs", justify: "center", py: "md" }, /* @__PURE__ */ React347.createElement(Loader69, { size: "xs" }), /* @__PURE__ */ React347.createElement(Text224, { size: "xs", c: "dimmed" }, t("actionTypes.evaluateClaim.flow.loadingClaims", { defaultValue: "Loading claims..." }))), !loadingClaims && filteredClaims.length === 0 && /* @__PURE__ */ React347.createElement(Text224, { size: "sm", c: "dimmed", ta: "center", py: "md" }, claims.length === 0 ? t("actionTypes.evaluateClaim.flow.empty.allCollections", { defaultValue: "No claims available for this collection." }) : activeFilter === "owed" ? "No claims are waiting on you right now." : t("actionTypes.evaluateClaim.flow.empty.filtered", { filter: activeFilter, defaultValue: `No ${activeFilter} claims found.` })), filteredClaims.length > 0 && /* @__PURE__ */ React347.createElement(Stack236, { gap: 12 }, filteredClaims.map((claim) => {
|
|
41672
42664
|
const row = engineSummaries.byClaimId[claim.claimId];
|
|
41673
42665
|
const view = rowViewByClaimId.get(claim.claimId) ?? { tone: "neutral", headline: "", owed: false, action: null, chain: null };
|
|
41674
42666
|
const profile = profilesByDid[claim.agentDid];
|
|
@@ -57934,4 +58926,4 @@ export {
|
|
|
57934
58926
|
ixoGraphQLClient,
|
|
57935
58927
|
getEntity
|
|
57936
58928
|
};
|
|
57937
|
-
//# sourceMappingURL=chunk-
|
|
58929
|
+
//# sourceMappingURL=chunk-37OKRZEK.js.map
|