@ixo/editor 5.28.0 → 5.29.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.
@@ -65,7 +65,7 @@ import {
65
65
  transformSurveyToCredentialSubject,
66
66
  updateXeroWorkReviewPayloadForEditor,
67
67
  upsertXeroWorkItemForEditor
68
- } from "./chunk-KWN34HVF.mjs";
68
+ } from "./chunk-47XOPWSV.mjs";
69
69
 
70
70
  // src/mantine/hooks/useCreateIxoEditor.ts
71
71
  import { useCreateBlockNote } from "@blocknote/react";
@@ -7394,7 +7394,7 @@ var BidViewPanel = ({ editor, block, bid, deedId, adminAddress, onRefresh, execu
7394
7394
  const [maxUsdcAmount, setMaxUsdcAmount] = useState26("");
7395
7395
  const [maxIxoAmount, setMaxIxoAmount] = useState26("");
7396
7396
  const isEvaluator = isEvaluatorRole(bid.role);
7397
- const buildMaxAmounts = () => {
7397
+ const buildMaxAmounts2 = () => {
7398
7398
  if (!isEvaluator) return void 0;
7399
7399
  const coins = [];
7400
7400
  if (maxUsdcAmount !== "" && Number(maxUsdcAmount) > 0) {
@@ -7412,7 +7412,7 @@ var BidViewPanel = ({ editor, block, bid, deedId, adminAddress, onRefresh, execu
7412
7412
  return coins.length > 0 ? coins : void 0;
7413
7413
  };
7414
7414
  const handleApprove = () => {
7415
- const maxAmounts = buildMaxAmounts();
7415
+ const maxAmounts = buildMaxAmounts2();
7416
7416
  approveBid(maxAmounts);
7417
7417
  };
7418
7418
  const surveyContainerStyle = useMemo29(
@@ -26162,7 +26162,7 @@ var EvaluateBidFlowDetail = ({
26162
26162
  const updatePaymentRow = useCallback91((id, patch) => {
26163
26163
  setPaymentRows((prev) => prev.map((row) => row.id === id ? { ...row, ...patch } : row));
26164
26164
  }, []);
26165
- const buildMaxAmounts = useCallback91(() => {
26165
+ const buildMaxAmounts2 = useCallback91(() => {
26166
26166
  return paymentRows.map((row) => {
26167
26167
  const denom = row.denom === CUSTOM_DENOM ? row.customDenom.trim() : row.denom || "";
26168
26168
  const amount = Number(row.amount);
@@ -26186,9 +26186,9 @@ var EvaluateBidFlowDetail = ({
26186
26186
  applicantAddress: selectedBid.address,
26187
26187
  adminAddress,
26188
26188
  rejectReason: decision === "reject" ? selectedBidIsEvaluator ? rejectReason : rejectReason.trim() || "Rejected" : void 0,
26189
- maxAmounts: selectedBidIsEvaluator ? JSON.stringify(buildMaxAmounts()) : void 0
26189
+ maxAmounts: selectedBidIsEvaluator ? JSON.stringify(buildMaxAmounts2()) : void 0
26190
26190
  });
26191
- }, [registerRuntimeInputs, selectedBid, decision, adminAddress, rejectReason, buildMaxAmounts]);
26191
+ }, [registerRuntimeInputs, selectedBid, decision, adminAddress, rejectReason, buildMaxAmounts2]);
26192
26192
  useEffect90(() => {
26193
26193
  if (!unlockSigning) return;
26194
26194
  if (!selectedBid || !decision) {
@@ -26227,7 +26227,7 @@ var EvaluateBidFlowDetail = ({
26227
26227
  applicantDid: selectedBid.did,
26228
26228
  applicantAddress: selectedBid.address,
26229
26229
  adminAddress,
26230
- maxAmounts: selectedBidIsEvaluator ? JSON.stringify(buildMaxAmounts()) : "[]",
26230
+ maxAmounts: selectedBidIsEvaluator ? JSON.stringify(buildMaxAmounts2()) : "[]",
26231
26231
  reason: decision === "reject" ? selectedBidIsEvaluator ? rejectReason : rejectReason.trim() || "Rejected" : ""
26232
26232
  }
26233
26233
  });
@@ -26243,7 +26243,7 @@ var EvaluateBidFlowDetail = ({
26243
26243
  setSubmitting(false);
26244
26244
  }
26245
26245
  });
26246
- }, [provideSigningHandler, selectedBid, decision, adminAddress, rejectReason, collectionId, deedDid, buildMaxAmounts, refreshBids, executeAction]);
26246
+ }, [provideSigningHandler, selectedBid, decision, adminAddress, rejectReason, collectionId, deedDid, buildMaxAmounts2, refreshBids, executeAction]);
26247
26247
  if (selectedBid) {
26248
26248
  const bidStatus = getBidStatus(selectedBid, t);
26249
26249
  const bidRole = String(selectedBid.role || "").toLowerCase();
@@ -26589,6 +26589,94 @@ import React262, { useCallback as useCallback93, useEffect as useEffect92, useMe
26589
26589
  import { ActionIcon as ActionIcon41, Alert as Alert48, Box as Box54, Group as Group98, Loader as Loader45, Stack as Stack178, Text as Text156 } from "@mantine/core";
26590
26590
  import { IconArrowLeft as IconArrowLeft9, IconCheck as IconCheck21, IconPlayerPlay as IconPlayerPlay4 } from "@tabler/icons-react";
26591
26591
  import { SurveyModel as SurveyModel10 } from "@ixo/surveys";
26592
+
26593
+ // src/mantine/blocks/action/actionTypes/evaluateClaim/resolveClaimFileRef.ts
26594
+ var IPFS_GATEWAY = "https://ipfs.gateway.ixo.world/ipfs/";
26595
+ var CID_REGEX = /(baf[a-z0-9]{20,})/i;
26596
+ function extractCid(source) {
26597
+ const m = source.match(CID_REGEX);
26598
+ return m ? m[1] : null;
26599
+ }
26600
+ function resolveClaimFileRef(raw) {
26601
+ if (raw == null) return null;
26602
+ if (typeof raw === "string") {
26603
+ const trimmed = raw.trim();
26604
+ if (!trimmed) return null;
26605
+ if (/^https?:/i.test(trimmed)) return trimmed;
26606
+ if (trimmed.startsWith("data:")) return trimmed;
26607
+ if (/^ipfs:/i.test(trimmed)) {
26608
+ const cid = extractCid(trimmed.replace(/^ipfs:\/*/i, ""));
26609
+ return cid ? `${IPFS_GATEWAY}${cid}` : null;
26610
+ }
26611
+ if (trimmed.startsWith("{")) {
26612
+ try {
26613
+ return resolveClaimFileRef(JSON.parse(trimmed));
26614
+ } catch {
26615
+ return null;
26616
+ }
26617
+ }
26618
+ if (/^did:/i.test(trimmed)) {
26619
+ const cid = extractCid(trimmed);
26620
+ return cid ? `${IPFS_GATEWAY}${cid}` : null;
26621
+ }
26622
+ if (/^baf[a-z0-9]/i.test(trimmed) && trimmed.length < 200 && !trimmed.includes(" ")) {
26623
+ const cid = extractCid(trimmed);
26624
+ return cid ? `${IPFS_GATEWAY}${cid}` : null;
26625
+ }
26626
+ return null;
26627
+ }
26628
+ if (typeof raw === "object") {
26629
+ const obj = raw;
26630
+ if (typeof obj.serviceEndpoint === "string" && /^https?:/i.test(obj.serviceEndpoint)) {
26631
+ return obj.serviceEndpoint;
26632
+ }
26633
+ if (typeof obj.proof === "string") {
26634
+ const cid = extractCid(obj.proof);
26635
+ if (cid) return `${IPFS_GATEWAY}${cid}`;
26636
+ }
26637
+ if (typeof obj.id === "string") {
26638
+ const hashIdx = obj.id.indexOf("#");
26639
+ const tail = hashIdx >= 0 ? obj.id.slice(hashIdx + 1) : obj.id;
26640
+ const cid = extractCid(tail);
26641
+ if (cid) return `${IPFS_GATEWAY}${cid}`;
26642
+ }
26643
+ if (typeof obj.content === "string") {
26644
+ return resolveClaimFileRef(obj.content);
26645
+ }
26646
+ if (typeof obj.url === "string" && /^https?:/i.test(obj.url)) {
26647
+ return obj.url;
26648
+ }
26649
+ }
26650
+ return null;
26651
+ }
26652
+ function isFileLike(value) {
26653
+ if (Array.isArray(value)) {
26654
+ return value.length > 0 && value.every((v) => v && typeof v === "object" && typeof v.content === "string");
26655
+ }
26656
+ return !!value && typeof value === "object" && typeof value.content === "string";
26657
+ }
26658
+ function resolveOneFileEntry(entry) {
26659
+ const resolved = resolveClaimFileRef(entry.content);
26660
+ if (resolved && resolved !== entry.content) {
26661
+ return { ...entry, content: resolved };
26662
+ }
26663
+ return entry;
26664
+ }
26665
+ function resolveFilesInCredentialSubject(subject) {
26666
+ if (!subject || typeof subject !== "object") return subject;
26667
+ const out = Array.isArray(subject) ? [...subject] : { ...subject };
26668
+ for (const [key, value] of Object.entries(subject)) {
26669
+ if (!isFileLike(value)) continue;
26670
+ if (Array.isArray(value)) {
26671
+ out[key] = value.map((v) => resolveOneFileEntry(v));
26672
+ } else {
26673
+ out[key] = resolveOneFileEntry(value);
26674
+ }
26675
+ }
26676
+ return out;
26677
+ }
26678
+
26679
+ // src/mantine/blocks/action/actionTypes/claim/ClaimFlowDetail.tsx
26592
26680
  function getTimeAgo2(dateString) {
26593
26681
  if (!dateString) return "";
26594
26682
  try {
@@ -26686,11 +26774,38 @@ var ClaimFlowDetail = ({
26686
26774
  const reviewMsg = model.getQuestionByName("reviewMessage");
26687
26775
  if (reviewMsg) reviewMsg.visible = false;
26688
26776
  }
26777
+ if (handlersRef.current.uploadClaimFile) {
26778
+ for (const q of model.getAllQuestions()) {
26779
+ if (q.getType?.() === "file") {
26780
+ q.storeDataAsText = false;
26781
+ }
26782
+ }
26783
+ model.onUploadFiles.add((_sender, options) => {
26784
+ const uploader = handlersRef.current.uploadClaimFile;
26785
+ if (!uploader) {
26786
+ options.callback([], ["File upload is not supported"]);
26787
+ return;
26788
+ }
26789
+ Promise.all(options.files.map((file) => uploader(file, collectionId, { entityDid: deedDid }))).then((results) => {
26790
+ options.callback(options.files.map((file, i) => ({ file, content: results[i].content })));
26791
+ }).catch((err) => {
26792
+ console.error("[Claim] file upload failed", err);
26793
+ options.callback([], [err instanceof Error ? err.message : "File upload failed"]);
26794
+ });
26795
+ });
26796
+ }
26689
26797
  if (prefillData) {
26690
26798
  model.data = prefillData?.credentialSubject ?? prefillData;
26691
26799
  }
26692
26800
  return model;
26693
- }, [surveyJson, provideSigningHandler, prefillData]);
26801
+ }, [surveyJson, provideSigningHandler, prefillData, collectionId, deedDid]);
26802
+ const mediaBlobCacheRef = useRef29(/* @__PURE__ */ new Map());
26803
+ useEffect92(() => {
26804
+ return () => {
26805
+ for (const blobUrl of mediaBlobCacheRef.current.values()) URL.revokeObjectURL(blobUrl);
26806
+ mediaBlobCacheRef.current.clear();
26807
+ };
26808
+ }, []);
26694
26809
  const detailSurveyModel = useMemo102(() => {
26695
26810
  if (!surveyJson || !selectedClaimData) return null;
26696
26811
  const model = new SurveyModel10(surveyJson);
@@ -26698,9 +26813,39 @@ var ClaimFlowDetail = ({
26698
26813
  model.showQuestionNumbers = "off";
26699
26814
  model.questionsOnPageMode = "singlePage";
26700
26815
  model.mode = "display";
26701
- model.data = selectedClaimData?.credentialSubject ?? selectedClaimData;
26816
+ const fetcher = handlersRef.current.fetchClaimMedia;
26817
+ if (fetcher) {
26818
+ const cache = mediaBlobCacheRef.current;
26819
+ for (const q of model.getAllQuestions()) {
26820
+ if (q.getType?.() === "file") {
26821
+ q.storeDataAsText = false;
26822
+ }
26823
+ }
26824
+ model.onDownloadFile.add((_sender, options) => {
26825
+ const src = options?.content;
26826
+ if (typeof src !== "string" || !/^https?:/i.test(src)) {
26827
+ options.callback("success", src);
26828
+ return;
26829
+ }
26830
+ const cached = cache.get(src);
26831
+ if (cached) {
26832
+ options.callback("success", cached);
26833
+ return;
26834
+ }
26835
+ fetcher(src, { entityDid: deedDid }).then((blob) => {
26836
+ const blobUrl = URL.createObjectURL(blob);
26837
+ cache.set(src, blobUrl);
26838
+ options.callback("success", blobUrl);
26839
+ }).catch((err) => {
26840
+ console.error("[Claim] fetchClaimMedia failed", src, err);
26841
+ options.callback("error");
26842
+ });
26843
+ });
26844
+ }
26845
+ const cs = selectedClaimData?.credentialSubject ?? selectedClaimData;
26846
+ model.data = cs && typeof cs === "object" ? resolveFilesInCredentialSubject(cs) : cs;
26702
26847
  return model;
26703
- }, [surveyJson, selectedClaimData]);
26848
+ }, [surveyJson, selectedClaimData, deedDid]);
26704
26849
  useRegisterOpenSurvey({
26705
26850
  id: `claim-action:${block.id}:new`,
26706
26851
  title: `Submit Claim${block?.props?.title ? ` \u2014 ${block.props.title}` : ""}`,
@@ -28035,6 +28180,10 @@ function roleLabel(role) {
28035
28180
  return role === "submit" ? "Submit (Contributor)" : "Evaluate (Evaluator)";
28036
28181
  }
28037
28182
  var MIN_AGENT_QUOTA = 1;
28183
+ var DEFAULT_EVALUATOR_QUOTA = 50;
28184
+ var IXO_DENOM5 = "uixo";
28185
+ var USDC_DENOM5 = "ibc/6BBE9BD4246F8E04948D5A4EEE7164B2630263B9EBB5E7DC5F0A46C62A2FF97B";
28186
+ var EMPTY_MAX_AMOUNTS = { ixo: "", usdc: "" };
28038
28187
  function formatQuota2(value) {
28039
28188
  if (value == null || value === "") return "\u2014";
28040
28189
  return value;
@@ -28044,6 +28193,48 @@ function truncateAddress4(address) {
28044
28193
  if (address.length <= 16) return address;
28045
28194
  return `${address.slice(0, 10)}...${address.slice(-4)}`;
28046
28195
  }
28196
+ function toIxoDid(value) {
28197
+ const trimmed = String(value || "").trim();
28198
+ if (!trimmed) return "";
28199
+ return trimmed.startsWith("did:") ? trimmed : `did:ixo:${trimmed}`;
28200
+ }
28201
+ function getGranteeDid(grantee) {
28202
+ return toIxoDid(grantee.did || grantee.address);
28203
+ }
28204
+ function buildMaxAmounts(values) {
28205
+ return [
28206
+ { denom: IXO_DENOM5, amount: values.ixo },
28207
+ { denom: USDC_DENOM5, amount: values.usdc }
28208
+ ].filter((coin) => {
28209
+ const amount = Number(coin.amount);
28210
+ return Number.isFinite(amount) && amount > 0;
28211
+ });
28212
+ }
28213
+ function formatCoin2(coin) {
28214
+ const denom = coin.denom === IXO_DENOM5 ? "IXO" : coin.denom === USDC_DENOM5 ? "USDC" : coin.denom;
28215
+ return `${coin.amount} ${denom}`;
28216
+ }
28217
+ function MaxAmountsInput({ value, onChange, disabled }) {
28218
+ return /* @__PURE__ */ React266.createElement(Stack182, { gap: "xs" }, /* @__PURE__ */ React266.createElement(Text160, { size: "xs", c: "dimmed" }, "Evaluator max amounts"), /* @__PURE__ */ React266.createElement(Group102, { grow: true, align: "flex-start" }, /* @__PURE__ */ React266.createElement(
28219
+ BaseNumberInput,
28220
+ {
28221
+ label: "IXO",
28222
+ min: 0,
28223
+ value: value.ixo === "" ? "" : Number(value.ixo),
28224
+ onChange: (amount) => onChange({ ...value, ixo: amount === "" || amount == null ? "" : String(amount) }),
28225
+ disabled
28226
+ }
28227
+ ), /* @__PURE__ */ React266.createElement(
28228
+ BaseNumberInput,
28229
+ {
28230
+ label: "USDC",
28231
+ min: 0,
28232
+ value: value.usdc === "" ? "" : Number(value.usdc),
28233
+ onChange: (amount) => onChange({ ...value, usdc: amount === "" || amount == null ? "" : String(amount) }),
28234
+ disabled
28235
+ }
28236
+ )));
28237
+ }
28047
28238
  function toQuotaString(value) {
28048
28239
  const n = Number(value);
28049
28240
  if (!Number.isFinite(n) || n < MIN_AGENT_QUOTA) return String(MIN_AGENT_QUOTA);
@@ -28145,6 +28336,7 @@ var CollectionUsersFlowDetail = ({
28145
28336
  const out = output;
28146
28337
  return Array.isArray(out?.grantees) ? out.grantees : [];
28147
28338
  }, [output]);
28339
+ const [granteeProfilesByDid, setGranteeProfilesByDid] = useState120({});
28148
28340
  const isRunning = runtime.state === "running";
28149
28341
  const isFailed = runtime.state === "failed";
28150
28342
  const errorMessage = runtime.error?.message || null;
@@ -28158,6 +28350,7 @@ var CollectionUsersFlowDetail = ({
28158
28350
  const [addAddress, setAddAddress] = useState120("");
28159
28351
  const [addRole, setAddRole] = useState120("submit");
28160
28352
  const [addQuota, setAddQuota] = useState120(String(MIN_AGENT_QUOTA));
28353
+ const [addMaxAmounts, setAddMaxAmounts] = useState120(EMPTY_MAX_AMOUNTS);
28161
28354
  const [granteeKind, setGranteeKind] = useState120("user");
28162
28355
  const [members, setMembers] = useState120([]);
28163
28356
  const [revokeTarget, setRevokeTarget] = useState120(null);
@@ -28218,6 +28411,9 @@ var CollectionUsersFlowDetail = ({
28218
28411
  setMembers([]);
28219
28412
  }
28220
28413
  }, [granteeKind, classification, canEnumerate, enumerateGroupMembers]);
28414
+ useEffect96(() => {
28415
+ setAddQuota(String(addRole === "evaluate" ? DEFAULT_EVALUATOR_QUOTA : MIN_AGENT_QUOTA));
28416
+ }, [addRole]);
28221
28417
  const isGroup = !!classification?.daodao;
28222
28418
  const canExerciseGrant = !!classification?.daodao?.canExerciseGrant;
28223
28419
  const listOnLoadRef = useRef31(false);
@@ -28257,6 +28453,41 @@ var CollectionUsersFlowDetail = ({
28257
28453
  listOnLoadRef.current = false;
28258
28454
  runList();
28259
28455
  }, [runList]);
28456
+ useEffect96(() => {
28457
+ let mounted = true;
28458
+ const dids = Array.from(new Set(listGrantees.map(getGranteeDid).filter(Boolean)));
28459
+ const missing = dids.filter((did) => !granteeProfilesByDid[did]);
28460
+ if (missing.length === 0)
28461
+ return () => {
28462
+ mounted = false;
28463
+ };
28464
+ const loadProfiles = async () => {
28465
+ const results = await Promise.all(
28466
+ missing.map(async (did) => {
28467
+ try {
28468
+ const profile = await handlersRef.current.getMatrixInfoPerDid(did);
28469
+ return [did, profile];
28470
+ } catch {
28471
+ return [did, null];
28472
+ }
28473
+ })
28474
+ );
28475
+ if (!mounted) return;
28476
+ setGranteeProfilesByDid((prev) => {
28477
+ const next = { ...prev };
28478
+ results.forEach(([did, profile]) => {
28479
+ if (profile) {
28480
+ next[did] = profile;
28481
+ }
28482
+ });
28483
+ return next;
28484
+ });
28485
+ };
28486
+ void loadProfiles();
28487
+ return () => {
28488
+ mounted = false;
28489
+ };
28490
+ }, [listGrantees, granteeProfilesByDid]);
28260
28491
  const validation = useMemo106(() => {
28261
28492
  if (section === "bids") return { ok: false };
28262
28493
  if (!collectionId) return { ok: false, error: "No collection configured. Set one in template mode." };
@@ -28293,6 +28524,7 @@ var CollectionUsersFlowDetail = ({
28293
28524
  role: revokeTarget?.role || "submit"
28294
28525
  };
28295
28526
  }
28527
+ const maxAmounts = buildMaxAmounts(addMaxAmounts);
28296
28528
  return {
28297
28529
  operation: "add",
28298
28530
  collectionId,
@@ -28302,9 +28534,10 @@ var CollectionUsersFlowDetail = ({
28302
28534
  role: addRole,
28303
28535
  granteeKind,
28304
28536
  agentQuota: toQuotaString(addQuota),
28537
+ maxAmount: addRole === "evaluate" && maxAmounts.length > 0 ? maxAmounts : void 0,
28305
28538
  members: granteeKind === "group-members" ? members : void 0
28306
28539
  };
28307
- }, [section, activeOp, collectionId, adminAddress, deedDid, revokeTarget, addAddress, addRole, granteeKind, addQuota, members]);
28540
+ }, [section, activeOp, collectionId, adminAddress, deedDid, revokeTarget, addAddress, addRole, granteeKind, addQuota, addMaxAmounts, members]);
28308
28541
  useEffect96(() => {
28309
28542
  if (!registerRuntimeInputs) return;
28310
28543
  registerRuntimeInputs(buildRuntimeInputs());
@@ -28342,7 +28575,8 @@ var CollectionUsersFlowDetail = ({
28342
28575
  console.log(`${LOG2} execute success`, { operation: runtimeInputs.operation, transactionHash: payload.transactionHash });
28343
28576
  if (runtimeInputs.operation === "add") {
28344
28577
  setAddAddress("");
28345
- setAddQuota(String(MIN_AGENT_QUOTA));
28578
+ setAddQuota(String(runtimeInputs.role === "evaluate" ? DEFAULT_EVALUATOR_QUOTA : MIN_AGENT_QUOTA));
28579
+ setAddMaxAmounts(EMPTY_MAX_AMOUNTS);
28346
28580
  setGranteeKind("user");
28347
28581
  setMembers([]);
28348
28582
  setClassification(null);
@@ -28406,6 +28640,9 @@ var CollectionUsersFlowDetail = ({
28406
28640
  }
28407
28641
  ), !configMissing && section === "list" && /* @__PURE__ */ React266.createElement(Stack182, { gap: "sm" }, /* @__PURE__ */ React266.createElement(Group102, { justify: "space-between", align: "center" }, /* @__PURE__ */ React266.createElement(Text160, { size: "sm", fw: 600 }, "Grantees"), /* @__PURE__ */ React266.createElement(ActionIcon42, { variant: "subtle", color: "gray", size: "sm", onClick: handleManualRefreshList, disabled: isRunning || !adminAddress }, /* @__PURE__ */ React266.createElement(IconRefresh9, { size: 16 }))), isRunning && lastOp !== "add" && lastOp !== "revoke" && /* @__PURE__ */ React266.createElement(Group102, { gap: "xs", justify: "center", py: "sm" }, /* @__PURE__ */ React266.createElement(Loader49, { size: "xs" }), /* @__PURE__ */ React266.createElement(Text160, { size: "xs", c: "dimmed" }, "Loading grantees\u2026")), !isRunning && listGrantees.length === 0 && /* @__PURE__ */ React266.createElement(Text160, { size: "sm", c: "dimmed", ta: "center", py: "sm" }, "No grantees hold a constraint for this collection yet."), listGrantees.map((grantee) => {
28408
28642
  const isTarget = revokeTarget?.address === grantee.address && revokeTarget?.role === grantee.role;
28643
+ const granteeDid = getGranteeDid(grantee);
28644
+ const profile = granteeProfilesByDid[granteeDid];
28645
+ const displayName = profile?.displayname || truncateAddress4(grantee.address);
28409
28646
  return /* @__PURE__ */ React266.createElement(
28410
28647
  Box56,
28411
28648
  {
@@ -28417,7 +28654,7 @@ var CollectionUsersFlowDetail = ({
28417
28654
  background: "var(--mantine-color-neutralColor-5)"
28418
28655
  }
28419
28656
  },
28420
- /* @__PURE__ */ React266.createElement(Group102, { justify: "space-between", align: "center", wrap: "nowrap" }, /* @__PURE__ */ React266.createElement(Stack182, { gap: 2, style: { minWidth: 0 } }, /* @__PURE__ */ React266.createElement(Text160, { size: "sm", fw: 600, style: { wordBreak: "break-all", fontFamily: "var(--mantine-font-family-monospace)" } }, truncateAddress4(grantee.address)), /* @__PURE__ */ React266.createElement(Group102, { gap: "xs" }, /* @__PURE__ */ React266.createElement(Badge50, { size: "xs", variant: "light", color: grantee.role === "submit" ? "blue" : "green" }, roleLabel(grantee.role)), /* @__PURE__ */ React266.createElement(Text160, { size: "xs", c: "dimmed" }, "Quota: ", formatQuota2(grantee.agentQuota)))), isTarget ? /* @__PURE__ */ React266.createElement(Button55, { size: "compact-xs", variant: "subtle", color: "gray", onClick: cancelRevoke, disabled: isDisabled || isRunning }, "Cancel") : /* @__PURE__ */ React266.createElement(
28657
+ /* @__PURE__ */ React266.createElement(Group102, { justify: "space-between", align: "center", wrap: "nowrap" }, /* @__PURE__ */ React266.createElement(Stack182, { gap: 2, style: { minWidth: 0 } }, /* @__PURE__ */ React266.createElement(Text160, { size: "sm", fw: 600, truncate: true }, displayName), profile?.displayname && /* @__PURE__ */ React266.createElement(Text160, { size: "xs", c: "dimmed", truncate: true }, truncateAddress4(grantee.address)), /* @__PURE__ */ React266.createElement(Group102, { gap: "xs" }, /* @__PURE__ */ React266.createElement(Badge50, { size: "xs", variant: "light", color: grantee.role === "submit" ? "blue" : "green" }, roleLabel(grantee.role)), /* @__PURE__ */ React266.createElement(Text160, { size: "xs", c: "dimmed" }, "Quota: ", formatQuota2(grantee.agentQuota)))), isTarget ? /* @__PURE__ */ React266.createElement(Button55, { size: "compact-xs", variant: "subtle", color: "gray", onClick: cancelRevoke, disabled: isDisabled || isRunning }, "Cancel") : /* @__PURE__ */ React266.createElement(
28421
28658
  Button55,
28422
28659
  {
28423
28660
  size: "compact-xs",
@@ -28479,7 +28716,7 @@ var CollectionUsersFlowDetail = ({
28479
28716
  onChange: (value) => setAddQuota(value === "" || value == null ? "" : String(value)),
28480
28717
  disabled: isDisabled || isRunning
28481
28718
  }
28482
- ), !validation.ok && validation.error && activeOp === "add" && /* @__PURE__ */ React266.createElement(Alert52, { color: "yellow", styles: actionAlertStyles }, validation.error)), !configMissing && section === "bids" && /* @__PURE__ */ React266.createElement(BidInboxSection, { deedDid, collectionId, adminAddress, isDisabled, handlersRef }), isDisabled && /* @__PURE__ */ React266.createElement(Text160, { size: "xs", c: "dimmed" }, "This block is currently disabled."));
28719
+ ), addRole === "evaluate" && /* @__PURE__ */ React266.createElement(MaxAmountsInput, { value: addMaxAmounts, onChange: setAddMaxAmounts, disabled: isDisabled || isRunning }), !validation.ok && validation.error && activeOp === "add" && /* @__PURE__ */ React266.createElement(Alert52, { color: "yellow", styles: actionAlertStyles }, validation.error)), !configMissing && section === "bids" && /* @__PURE__ */ React266.createElement(BidInboxSection, { deedDid, collectionId, adminAddress, isDisabled, handlersRef }), isDisabled && /* @__PURE__ */ React266.createElement(Text160, { size: "xs", c: "dimmed" }, "This block is currently disabled."));
28483
28720
  };
28484
28721
  var BidInboxSection = ({ deedDid, collectionId, adminAddress, isDisabled, handlersRef }) => {
28485
28722
  const [bids, setBids] = useState120([]);
@@ -28489,9 +28726,14 @@ var BidInboxSection = ({ deedDid, collectionId, adminAddress, isDisabled, handle
28489
28726
  const [decision, setDecision] = useState120("");
28490
28727
  const [rejectReason, setRejectReason] = useState120("");
28491
28728
  const [approveQuota, setApproveQuota] = useState120(String(MIN_AGENT_QUOTA));
28729
+ const [approveMaxAmounts, setApproveMaxAmounts] = useState120(EMPTY_MAX_AMOUNTS);
28492
28730
  const [submitting, setSubmitting] = useState120(false);
28493
28731
  const [profilesByDid, setProfilesByDid] = useState120({});
28494
28732
  const selectedBid = useMemo106(() => bids.find((b) => b.id === selectedBidId) || null, [bids, selectedBidId]);
28733
+ const selectedBidIsEvaluator = useMemo106(() => {
28734
+ const role = String(selectedBid?.role || "").toLowerCase();
28735
+ return role === "evaluation_agent" || role === "ea";
28736
+ }, [selectedBid]);
28495
28737
  const refreshBids = useCallback97(async () => {
28496
28738
  if (!deedDid || !collectionId) return;
28497
28739
  setLoading(true);
@@ -28500,9 +28742,9 @@ var BidInboxSection = ({ deedDid, collectionId, adminAddress, isDisabled, handle
28500
28742
  const response = await handlersRef.current.queryBids({ collectionId, entityDid: deedDid });
28501
28743
  const fetched = Array.isArray(response?.data) ? response.data : [];
28502
28744
  setBids(fetched);
28503
- } catch (err) {
28745
+ } catch {
28504
28746
  setBids([]);
28505
- setError(err instanceof Error ? err.message : "Failed to load bids");
28747
+ setError(null);
28506
28748
  } finally {
28507
28749
  setLoading(false);
28508
28750
  }
@@ -28512,8 +28754,15 @@ var BidInboxSection = ({ deedDid, collectionId, adminAddress, isDisabled, handle
28512
28754
  setDecision("");
28513
28755
  setRejectReason("");
28514
28756
  setApproveQuota(String(MIN_AGENT_QUOTA));
28757
+ setApproveMaxAmounts(EMPTY_MAX_AMOUNTS);
28515
28758
  if (deedDid && collectionId) refreshBids();
28516
28759
  }, [deedDid, collectionId, refreshBids]);
28760
+ useEffect96(() => {
28761
+ setDecision("");
28762
+ setRejectReason("");
28763
+ setApproveMaxAmounts(EMPTY_MAX_AMOUNTS);
28764
+ setApproveQuota(String(selectedBidIsEvaluator ? DEFAULT_EVALUATOR_QUOTA : MIN_AGENT_QUOTA));
28765
+ }, [selectedBidId, selectedBidIsEvaluator]);
28517
28766
  useEffect96(() => {
28518
28767
  let mounted = true;
28519
28768
  const dids = Array.from(new Set(bids.map((b) => b.did).filter(Boolean)));
@@ -28555,7 +28804,15 @@ var BidInboxSection = ({ deedDid, collectionId, adminAddress, isDisabled, handle
28555
28804
  if (!adminAddress) throw new Error("Entity admin account is not resolved yet.");
28556
28805
  const quotaNum = Number(toQuotaString(approveQuota));
28557
28806
  if (isEvaluator) {
28558
- await h.approveEvaluatorApplication({ adminAddress, collectionId, deedDid, evaluatorAddress: selectedBid.address, agentQuota: quotaNum });
28807
+ const maxAmounts = buildMaxAmounts(approveMaxAmounts);
28808
+ await h.approveEvaluatorApplication({
28809
+ adminAddress,
28810
+ collectionId,
28811
+ deedDid,
28812
+ evaluatorAddress: selectedBid.address,
28813
+ agentQuota: quotaNum,
28814
+ maxAmounts: maxAmounts.length > 0 ? maxAmounts : void 0
28815
+ });
28559
28816
  } else {
28560
28817
  const currentUser = h.getCurrentUser?.();
28561
28818
  await h.approveServiceAgentApplication({
@@ -28572,19 +28829,21 @@ var BidInboxSection = ({ deedDid, collectionId, adminAddress, isDisabled, handle
28572
28829
  setSelectedBidId("");
28573
28830
  setDecision("");
28574
28831
  setRejectReason("");
28575
- setApproveQuota("0");
28832
+ setApproveQuota(String(MIN_AGENT_QUOTA));
28833
+ setApproveMaxAmounts(EMPTY_MAX_AMOUNTS);
28576
28834
  await refreshBids();
28577
28835
  } catch (err) {
28578
28836
  setError(err instanceof Error ? err.message : "Failed to evaluate bid");
28579
28837
  } finally {
28580
28838
  setSubmitting(false);
28581
28839
  }
28582
- }, [selectedBid, decision, adminAddress, collectionId, deedDid, rejectReason, approveQuota, handlersRef, refreshBids]);
28840
+ }, [selectedBid, decision, adminAddress, collectionId, deedDid, rejectReason, approveQuota, approveMaxAmounts, handlersRef, refreshBids]);
28583
28841
  if (selectedBid) {
28584
28842
  const profile = profilesByDid[selectedBid.did];
28585
28843
  const displayName = profile?.displayname || selectedBid.did || selectedBid.address;
28586
28844
  const role = String(selectedBid.role || "").toLowerCase();
28587
28845
  const isEvaluator = role === "evaluation_agent" || role === "ea";
28846
+ const maxAmounts = isEvaluator ? buildMaxAmounts(approveMaxAmounts) : [];
28588
28847
  const approvalDiffs = [
28589
28848
  { key: "role", label: "Role", before: null, after: getBidRoleLabel(selectedBid.role), changeType: "add" },
28590
28849
  { key: "grantee", label: "Grantee", before: null, after: displayName, changeType: "add" },
@@ -28596,7 +28855,16 @@ var BidInboxSection = ({ deedDid, collectionId, adminAddress, isDisabled, handle
28596
28855
  after: toQuotaString(approveQuota),
28597
28856
  changeType: "add",
28598
28857
  unit: "claims"
28599
- }
28858
+ },
28859
+ ...isEvaluator ? [
28860
+ {
28861
+ key: "maxAmount",
28862
+ label: "Max Amounts",
28863
+ before: null,
28864
+ after: maxAmounts.length > 0 ? maxAmounts.map(formatCoin2).join(", ") : "None",
28865
+ changeType: maxAmounts.length > 0 ? "add" : "unchanged"
28866
+ }
28867
+ ] : []
28600
28868
  ];
28601
28869
  return /* @__PURE__ */ React266.createElement(Stack182, { gap: "md" }, /* @__PURE__ */ React266.createElement(Group102, { gap: "xs", align: "center" }, /* @__PURE__ */ React266.createElement(ActionIcon42, { variant: "subtle", color: "gray", size: "sm", onClick: () => setSelectedBidId("") }, /* @__PURE__ */ React266.createElement(IconArrowLeft10, { size: 16 })), /* @__PURE__ */ React266.createElement(Text160, { fw: 500, size: "sm", truncate: true, style: { flex: 1, minWidth: 0 } }, "Bid #", selectedBid.id)), /* @__PURE__ */ React266.createElement(Stack182, { gap: 4 }, /* @__PURE__ */ React266.createElement(Text160, { size: "sm", fw: 600, truncate: true }, displayName), /* @__PURE__ */ React266.createElement(Group102, { gap: "xs" }, /* @__PURE__ */ React266.createElement(Badge50, { size: "xs", variant: "light", color: getRoleColor3(selectedBid.role) }, getBidRoleLabel(selectedBid.role)), /* @__PURE__ */ React266.createElement(Text160, { size: "xs", c: "dimmed" }, truncateAddress4(selectedBid.address)))), /* @__PURE__ */ React266.createElement(
28602
28870
  BaseSelect,
@@ -28620,7 +28888,7 @@ var BidInboxSection = ({ deedDid, collectionId, adminAddress, isDisabled, handle
28620
28888
  onChange: (value) => setApproveQuota(value === "" || value == null ? "" : String(value)),
28621
28889
  disabled: isDisabled || submitting
28622
28890
  }
28623
- ), /* @__PURE__ */ React266.createElement(ActionDiffView, { diffs: approvalDiffs })), decision === "reject" && /* @__PURE__ */ React266.createElement(
28891
+ ), isEvaluator && /* @__PURE__ */ React266.createElement(MaxAmountsInput, { value: approveMaxAmounts, onChange: setApproveMaxAmounts, disabled: isDisabled || submitting }), /* @__PURE__ */ React266.createElement(ActionDiffView, { diffs: approvalDiffs })), decision === "reject" && /* @__PURE__ */ React266.createElement(
28624
28892
  BaseTextInput,
28625
28893
  {
28626
28894
  label: `Reason${isEvaluator ? " *" : ""}`,
@@ -28956,92 +29224,6 @@ var MediaPreviewModal = ({ file, onClose }) => {
28956
29224
  );
28957
29225
  };
28958
29226
 
28959
- // src/mantine/blocks/action/actionTypes/evaluateClaim/resolveClaimFileRef.ts
28960
- var IPFS_GATEWAY = "https://ipfs.gateway.ixo.world/ipfs/";
28961
- var CID_REGEX = /(baf[a-z0-9]{20,})/i;
28962
- function extractCid(source) {
28963
- const m = source.match(CID_REGEX);
28964
- return m ? m[1] : null;
28965
- }
28966
- function resolveClaimFileRef(raw) {
28967
- if (raw == null) return null;
28968
- if (typeof raw === "string") {
28969
- const trimmed = raw.trim();
28970
- if (!trimmed) return null;
28971
- if (/^https?:/i.test(trimmed)) return trimmed;
28972
- if (trimmed.startsWith("data:")) return trimmed;
28973
- if (/^ipfs:/i.test(trimmed)) {
28974
- const cid = extractCid(trimmed.replace(/^ipfs:\/*/i, ""));
28975
- return cid ? `${IPFS_GATEWAY}${cid}` : null;
28976
- }
28977
- if (trimmed.startsWith("{")) {
28978
- try {
28979
- return resolveClaimFileRef(JSON.parse(trimmed));
28980
- } catch {
28981
- return null;
28982
- }
28983
- }
28984
- if (/^did:/i.test(trimmed)) {
28985
- const cid = extractCid(trimmed);
28986
- return cid ? `${IPFS_GATEWAY}${cid}` : null;
28987
- }
28988
- if (/^baf[a-z0-9]/i.test(trimmed) && trimmed.length < 200 && !trimmed.includes(" ")) {
28989
- const cid = extractCid(trimmed);
28990
- return cid ? `${IPFS_GATEWAY}${cid}` : null;
28991
- }
28992
- return null;
28993
- }
28994
- if (typeof raw === "object") {
28995
- const obj = raw;
28996
- if (typeof obj.serviceEndpoint === "string" && /^https?:/i.test(obj.serviceEndpoint)) {
28997
- return obj.serviceEndpoint;
28998
- }
28999
- if (typeof obj.proof === "string") {
29000
- const cid = extractCid(obj.proof);
29001
- if (cid) return `${IPFS_GATEWAY}${cid}`;
29002
- }
29003
- if (typeof obj.id === "string") {
29004
- const hashIdx = obj.id.indexOf("#");
29005
- const tail = hashIdx >= 0 ? obj.id.slice(hashIdx + 1) : obj.id;
29006
- const cid = extractCid(tail);
29007
- if (cid) return `${IPFS_GATEWAY}${cid}`;
29008
- }
29009
- if (typeof obj.content === "string") {
29010
- return resolveClaimFileRef(obj.content);
29011
- }
29012
- if (typeof obj.url === "string" && /^https?:/i.test(obj.url)) {
29013
- return obj.url;
29014
- }
29015
- }
29016
- return null;
29017
- }
29018
- function isFileLike(value) {
29019
- if (Array.isArray(value)) {
29020
- return value.length > 0 && value.every((v) => v && typeof v === "object" && typeof v.content === "string");
29021
- }
29022
- return !!value && typeof value === "object" && typeof value.content === "string";
29023
- }
29024
- function resolveOneFileEntry(entry) {
29025
- const resolved = resolveClaimFileRef(entry.content);
29026
- if (resolved && resolved !== entry.content) {
29027
- return { ...entry, content: resolved };
29028
- }
29029
- return entry;
29030
- }
29031
- function resolveFilesInCredentialSubject(subject) {
29032
- if (!subject || typeof subject !== "object") return subject;
29033
- const out = Array.isArray(subject) ? [...subject] : { ...subject };
29034
- for (const [key, value] of Object.entries(subject)) {
29035
- if (!isFileLike(value)) continue;
29036
- if (Array.isArray(value)) {
29037
- out[key] = value.map((v) => resolveOneFileEntry(v));
29038
- } else {
29039
- out[key] = resolveOneFileEntry(value);
29040
- }
29041
- }
29042
- return out;
29043
- }
29044
-
29045
29227
  // src/mantine/blocks/action/actionTypes/evaluateClaim/ClaimAttachments.tsx
29046
29228
  function toMediaFile(raw) {
29047
29229
  if (!raw) return null;
@@ -29236,13 +29418,13 @@ var ClaimAttachments = ({ surveyModel, credentialSubject, entityDid }) => {
29236
29418
  };
29237
29419
 
29238
29420
  // src/mantine/blocks/action/actionTypes/evaluateClaim/EvaluateClaimFlowDetail.tsx
29239
- var USDC_DENOM5 = "ibc/6BBE9BD4246F8E04948D5A4EEE7164B2630263B9EBB5E7DC5F0A46C62A2FF97B";
29240
- var IXO_DENOM5 = "uixo";
29421
+ var USDC_DENOM6 = "ibc/6BBE9BD4246F8E04948D5A4EEE7164B2630263B9EBB5E7DC5F0A46C62A2FF97B";
29422
+ var IXO_DENOM6 = "uixo";
29241
29423
  var CUSTOM_DENOM2 = "__custom__";
29242
29424
  var DECIMALS4 = 6;
29243
29425
  var createPaymentRow2 = () => ({
29244
29426
  id: `payment-${Math.random().toString(36).slice(2, 9)}`,
29245
- denom: USDC_DENOM5,
29427
+ denom: USDC_DENOM6,
29246
29428
  customDenom: "",
29247
29429
  amount: ""
29248
29430
  });
@@ -29454,6 +29636,26 @@ var EvaluateClaimFlowDetail = ({
29454
29636
  model.applyTheme(surveyTheme);
29455
29637
  model.showQuestionNumbers = "off";
29456
29638
  model.questionsOnPageMode = "singlePage";
29639
+ if (handlersRef.current.uploadClaimFile) {
29640
+ for (const q of model.getAllQuestions()) {
29641
+ if (q.getType?.() === "file") {
29642
+ q.storeDataAsText = false;
29643
+ }
29644
+ }
29645
+ model.onUploadFiles.add((_sender, options) => {
29646
+ const uploader = handlersRef.current.uploadClaimFile;
29647
+ if (!uploader) {
29648
+ options.callback([], ["File upload is not supported"]);
29649
+ return;
29650
+ }
29651
+ Promise.all(options.files.map((file) => uploader(file, collectionId, { entityDid: deedDid }))).then((results) => {
29652
+ options.callback(options.files.map((file, i) => ({ file, content: results[i].content })));
29653
+ }).catch((err) => {
29654
+ console.error("[EvaluateClaim] outcome file upload failed", err);
29655
+ options.callback([], [err instanceof Error ? err.message : "File upload failed"]);
29656
+ });
29657
+ });
29658
+ }
29457
29659
  model.onValueChanged.add((sender, options) => {
29458
29660
  console.log("[outcome-patch] SurveyJS onValueChanged", {
29459
29661
  question: options?.name,
@@ -29473,7 +29675,7 @@ var EvaluateClaimFlowDetail = ({
29473
29675
  setOutcomeComplete(true);
29474
29676
  });
29475
29677
  return model;
29476
- }, [outcomeTemplateJson]);
29678
+ }, [outcomeTemplateJson, collectionId, deedDid]);
29477
29679
  useEffect99(() => {
29478
29680
  if (!outcomeSurveyModel) return;
29479
29681
  const evaluated = selectedClaim ? isClaimEvaluated(selectedClaim) : false;
@@ -29841,8 +30043,8 @@ var EvaluateClaimFlowDetail = ({
29841
30043
  value: row.denom,
29842
30044
  onChange: (value) => updatePaymentRow(row.id, { denom: value }),
29843
30045
  data: [
29844
- { value: USDC_DENOM5, label: "USDC" },
29845
- { value: IXO_DENOM5, label: "IXO" },
30046
+ { value: USDC_DENOM6, label: "USDC" },
30047
+ { value: IXO_DENOM6, label: "IXO" },
29846
30048
  { value: CUSTOM_DENOM2, label: t("actionTypes.evaluateClaim.flow.payment.custom", { defaultValue: "Custom" }) }
29847
30049
  ],
29848
30050
  clearable: false,
@@ -46583,4 +46785,4 @@ export {
46583
46785
  getExtraSlashMenuItems,
46584
46786
  useCreateIxoEditor
46585
46787
  };
46586
- //# sourceMappingURL=chunk-AXKLTSPX.mjs.map
46788
+ //# sourceMappingURL=chunk-LWKZRDZO.mjs.map