@rytass/bpm-core-react 0.18.1 → 0.19.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/CHANGELOG.md +20 -0
- package/dist/chunks/{FormBuilderView-vQfVc08Z.js → FormBuilderView-Djlm3y4S.js} +2 -2
- package/dist/chunks/{FormBuilderView-vQfVc08Z.js.map → FormBuilderView-Djlm3y4S.js.map} +1 -1
- package/dist/chunks/{FormBuilderView-CHaAQL5v.cjs → FormBuilderView-G6uRSywl.cjs} +2 -2
- package/dist/chunks/{FormBuilderView-CHaAQL5v.cjs.map → FormBuilderView-G6uRSywl.cjs.map} +1 -1
- package/dist/chunks/{FormRendererView-CTLlG13b.js → FormRendererView-DHfVgbo6.js} +391 -265
- package/dist/chunks/FormRendererView-DHfVgbo6.js.map +1 -0
- package/dist/chunks/FormRendererView-DwfFbaip.cjs +6 -0
- package/dist/chunks/FormRendererView-DwfFbaip.cjs.map +1 -0
- package/dist/chunks/{compose-D9ipJpF_.js → compose-D6zBIc2Z.js} +4 -4
- package/dist/chunks/{compose-D9ipJpF_.js.map → compose-D6zBIc2Z.js.map} +1 -1
- package/dist/chunks/{compose-DtfX8DQ9.cjs → compose-NH6dsFXD.cjs} +2 -2
- package/dist/chunks/{compose-DtfX8DQ9.cjs.map → compose-NH6dsFXD.cjs.map} +1 -1
- package/dist/chunks/{designer-Df79YzUn.cjs → designer-Be9UI9Tg.cjs} +2 -2
- package/dist/chunks/{designer-Df79YzUn.cjs.map → designer-Be9UI9Tg.cjs.map} +1 -1
- package/dist/chunks/{designer-ubnZbP-A.js → designer-uhC_7m2i.js} +3 -3
- package/dist/chunks/{designer-ubnZbP-A.js.map → designer-uhC_7m2i.js.map} +1 -1
- package/dist/chunks/detail-6uw5dmTi.cjs +5 -0
- package/dist/chunks/detail-6uw5dmTi.cjs.map +1 -0
- package/dist/chunks/{detail-C6XKZjlF.js → detail-_GeKqNC-.js} +851 -839
- package/dist/chunks/detail-_GeKqNC-.js.map +1 -0
- package/dist/chunks/{approver-filled-form-B4zPg9kz.cjs → instance-error-message-DTARGbGo.cjs} +2 -2
- package/dist/chunks/instance-error-message-DTARGbGo.cjs.map +1 -0
- package/dist/chunks/{approver-filled-form-Bgazhbvd.js → instance-error-message-q6gy5evy.js} +44 -36
- package/dist/chunks/instance-error-message-q6gy5evy.js.map +1 -0
- package/dist/pages/instances/detail/index.cjs +1 -1
- package/dist/pages/instances/detail/index.js +1 -1
- package/dist/pages/templates/compose/index.cjs +1 -1
- package/dist/pages/templates/compose/index.js +1 -1
- package/dist/pages/templates/designer/index.cjs +1 -1
- package/dist/pages/templates/designer/index.js +1 -1
- package/dist/views/forms/builder/index.cjs +1 -1
- package/dist/views/forms/builder/index.js +1 -1
- package/dist/views/forms/renderer/FormRendererView.d.cts +24 -1
- package/dist/views/forms/renderer/FormRendererView.d.ts +24 -1
- package/dist/views/forms/renderer/file-upload-field.d.cts +84 -0
- package/dist/views/forms/renderer/file-upload-field.d.ts +84 -0
- package/dist/views/forms/renderer/form-value-readers.d.cts +7 -0
- package/dist/views/forms/renderer/form-value-readers.d.ts +7 -0
- package/dist/views/forms/renderer/index.cjs +1 -1
- package/dist/views/forms/renderer/index.d.cts +1 -0
- package/dist/views/forms/renderer/index.d.ts +1 -0
- package/dist/views/forms/renderer/index.js +1 -1
- package/dist/views/instances/detail/index.cjs +1 -1
- package/dist/views/instances/detail/index.js +1 -1
- package/dist/views/instances/detail/sections/InstanceFormSection.d.cts +19 -2
- package/dist/views/instances/detail/sections/InstanceFormSection.d.ts +19 -2
- package/dist/views/instances/detail/sections/shared.d.cts +1 -2
- package/dist/views/instances/detail/sections/shared.d.ts +1 -2
- package/dist/views/instances/instance-error-message.d.cts +5 -0
- package/dist/views/instances/instance-error-message.d.ts +5 -0
- package/dist/views/instances/new/index.cjs +1 -1
- package/dist/views/instances/new/index.cjs.map +1 -1
- package/dist/views/instances/new/index.js +77 -75
- package/dist/views/instances/new/index.js.map +1 -1
- package/dist/views/templates/compose/index.cjs +1 -1
- package/dist/views/templates/compose/index.js +1 -1
- package/dist/views/templates/designer/index.cjs +1 -1
- package/dist/views/templates/designer/index.js +1 -1
- package/package.json +3 -3
- package/dist/chunks/FormRendererView-CTLlG13b.js.map +0 -1
- package/dist/chunks/FormRendererView-ChmM_4Yc.cjs +0 -4
- package/dist/chunks/FormRendererView-ChmM_4Yc.cjs.map +0 -1
- package/dist/chunks/approver-filled-form-B4zPg9kz.cjs.map +0 -1
- package/dist/chunks/approver-filled-form-Bgazhbvd.js.map +0 -1
- package/dist/chunks/detail-BBC9kqXd.cjs +0 -5
- package/dist/chunks/detail-BBC9kqXd.cjs.map +0 -1
- package/dist/chunks/detail-C6XKZjlF.js.map +0 -1
package/dist/chunks/{approver-filled-form-B4zPg9kz.cjs → instance-error-message-DTARGbGo.cjs}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
let e=require("@rytass/bpm-core-shared"),t=require("@rytass/bpm-core-client/form"),n=require("@rytass/bpm-core-shared/form");function r(t,n){let r=(0,e.readApproverFilledFieldKeys)(n);return{...t,fields:t.fields.filter(e=>!r.has(e.fieldKey))}}function i(t,n){return(0,e.omitFormDataKeys)(t,(0,e.readApproverFilledFieldKeys)(n))}function a(t,n){let r=(0,e.readNodeFillableFieldKeys)(n),i=o(t,n);return{...i,fields:i.fields.filter(e=>r.has(e.fieldKey))}}function o(t,n){let r=(0,e.readNodeFillableFieldKeys)(n),i=(0,e.readNodeRequiredFieldKeys)(n);return{...t,fields:t.fields.map(e=>r.has(e.fieldKey)?{...e,required:i.has(e.fieldKey),requiredWhen:void 0}:e)}}var s=e=>e.nodes.filter(e=>e.type===`userTask`);function c(t,n){let r=n===null?new Set:(0,e.readNodeFillableFieldKeys)(n);return s(t).reduce((t,n)=>({...Object.fromEntries([...(0,e.readNodeFillableFieldKeys)(n)].map(e=>[e,r.has(e)?`本關補填`:`${n.data.label||n.id}補填`])),...t}),{})}function l(t,n){return Object.fromEntries([...(0,e.readNodeFillableFieldKeys)(n)].filter(e=>Object.prototype.hasOwnProperty.call(t,e)).map(e=>[e,t[e]??null]))}function u({draft:t,node:r,schema:i,stored:a,values:o}){let s=(0,e.readNodeFillableFieldKeys)(r),c=i.fields.filter(e=>{let t=o[e.fieldKey];return(0,n.isTableFieldDefinition)(e)&&s.has(e.fieldKey)&&!Object.prototype.hasOwnProperty.call(a,e.fieldKey)&&Array.isArray(t)&&t.length>0});return{...Object.fromEntries(c.map(e=>[e.fieldKey,o[e.fieldKey]])),...t}}function d(e){return e.includes(`form data changed; refresh and retry`)}var f=/^formData\.([A-Za-z_][A-Za-z0-9_]*(?:\[\d+\]\.[A-Za-z_][A-Za-z0-9_]*)?) (.+)$/,p=`Form data is missing required fields: `;function m(e,t){let[r,i]=e.split(/\[\d+\]\./),a=t.find(e=>e.fieldKey===r);return i===void 0?a:a&&(0,n.isTableFieldDefinition)(a)?a.columns.find(e=>e.fieldKey===i):void 0}function h(e,t,n){let r=/^must include at least (\d+) row\(s\)$/.exec(t),i=/^must include at most (\d+) row\(s\)$/.exec(t),a=/^must be at least (\d+) characters$/.exec(t),o=/^must be at most (\d+) characters$/.exec(t);if(t===`is required`)return`此欄為必填。`;if(r)return`至少需要 ${r[1]} 列。`;if(i)return`最多 ${i[1]} 列。`;if(a)return`至少需要 ${a[1]} 個字。`;if(o)return`最多 ${o[1]} 個字。`;if(t===`does not match the required format`){let t=m(e,n);return(t&&(t.type===`text`||t.type===`textarea`)?t.patternErrorMessage?.trim():void 0)||`格式不正確。`}return t===`could not be checked against the required format in time`?`格式檢查逾時,請縮短內容後再試,或請表單設計者簡化格式。`:e.includes(`[`)?`此欄內容不正確。`:`此欄位內容不正確。`}function g(t,n,r){let i=n.fields.filter(t=>(0,e.readNodeFillableFieldKeys)(r).has(t.fieldKey));if(t.startsWith(p)){let e=`, ${t.slice(38)}, `,n=i.filter(t=>e.includes(`, ${t.label||t.fieldKey}, `));return n.length>0?Object.fromEntries(n.map(e=>[e.fieldKey,`${e.label||e.fieldKey}為必填欄位。`])):null}let a=t.split(`; `).map(e=>f.exec(e));return a.length===0||a.some(e=>e===null)?null:Object.fromEntries(a.flatMap(e=>e===null?[]:[[e[1],h(e[1],e[2],i)]]))}var _=`未知組織`;function v(e,t){return[...new Set(e.fields.filter(n.isOrgUnitFieldDefinition).map(e=>t[e.fieldKey]).filter(e=>typeof e==`string`&&e.trim().length>0))]}function y(r,i,a,o){if((0,n.isTableFieldDefinition)(r)){let e=(0,t.readFormTableRows)(i),n=r.columns.filter(e=>e.type===`number`||e.type===`money`).map(t=>({label:t.label||t.fieldKey,total:e.reduce((e,n)=>typeof n[t.fieldKey]==`number`&&Number.isFinite(n[t.fieldKey])?e+n[t.fieldKey]:e,0)}));return[`${e.length} 列`,...e.length>0?n.map(({label:e,total:t})=>`${e}合計 ${t.toLocaleString(`zh-TW`)}`):[]].join(`,`)}if((0,e.isFormDataValueEmpty)(i))return`未填寫`;if(typeof i==`boolean`)return i?`是`:`否`;if((0,n.isOrgUnitFieldDefinition)(r))return typeof i==`string`?o.get(i)??`未知組織`:_;let s=Array.isArray(i)?i:[i],c=(0,n.isFormStaticOptionFieldDefinition)(r)?new Map(r.options.map(e=>[e.value,e.label])):r.type===`member`?a:new Map;return s.map(e=>typeof e==`string`?c.get(e)??e:String(e)).join(`、`)}function b(t,n,r,i=new Map,a=new Map){let o=(0,e.readNodeFillableFieldKeys)(n);return t.fields.filter(e=>o.has(e.fieldKey)&&Object.prototype.hasOwnProperty.call(r,e.fieldKey)).map(e=>({fieldKey:e.fieldKey,label:e.label||e.fieldKey,text:y(e,r[e.fieldKey],i,a)}))}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return
|
|
2
|
-
//# sourceMappingURL=
|
|
1
|
+
let e=require("@rytass/bpm-core-shared"),t=require("@rytass/bpm-core-client/form"),n=require("@rytass/bpm-core-shared/form");function r(t,n){let r=(0,e.readApproverFilledFieldKeys)(n);return{...t,fields:t.fields.filter(e=>!r.has(e.fieldKey))}}function i(t,n){return(0,e.omitFormDataKeys)(t,(0,e.readApproverFilledFieldKeys)(n))}function a(t,n){let r=(0,e.readNodeFillableFieldKeys)(n),i=o(t,n);return{...i,fields:i.fields.filter(e=>r.has(e.fieldKey))}}function o(t,n){let r=(0,e.readNodeFillableFieldKeys)(n),i=(0,e.readNodeRequiredFieldKeys)(n);return{...t,fields:t.fields.map(e=>r.has(e.fieldKey)?{...e,required:i.has(e.fieldKey),requiredWhen:void 0}:e)}}var s=e=>e.nodes.filter(e=>e.type===`userTask`);function c(t,n){let r=n===null?new Set:(0,e.readNodeFillableFieldKeys)(n);return s(t).reduce((t,n)=>({...Object.fromEntries([...(0,e.readNodeFillableFieldKeys)(n)].map(e=>[e,r.has(e)?`本關補填`:`${n.data.label||n.id}補填`])),...t}),{})}function l(t,n){return Object.fromEntries([...(0,e.readNodeFillableFieldKeys)(n)].filter(e=>Object.prototype.hasOwnProperty.call(t,e)).map(e=>[e,t[e]??null]))}function u({draft:t,node:r,schema:i,stored:a,values:o}){let s=(0,e.readNodeFillableFieldKeys)(r),c=i.fields.filter(e=>{let t=o[e.fieldKey];return(0,n.isTableFieldDefinition)(e)&&s.has(e.fieldKey)&&!Object.prototype.hasOwnProperty.call(a,e.fieldKey)&&Array.isArray(t)&&t.length>0});return{...Object.fromEntries(c.map(e=>[e.fieldKey,o[e.fieldKey]])),...t}}function d(e){return e.includes(`form data changed; refresh and retry`)}var f=/^formData\.([A-Za-z_][A-Za-z0-9_]*(?:\[\d+\]\.[A-Za-z_][A-Za-z0-9_]*)?) (.+)$/,p=`Form data is missing required fields: `;function m(e,t){let[r,i]=e.split(/\[\d+\]\./),a=t.find(e=>e.fieldKey===r);return i===void 0?a:a&&(0,n.isTableFieldDefinition)(a)?a.columns.find(e=>e.fieldKey===i):void 0}function h(e,t,n){let r=/^must include at least (\d+) row\(s\)$/.exec(t),i=/^must include at most (\d+) row\(s\)$/.exec(t),a=/^must be at least (\d+) characters$/.exec(t),o=/^must be at most (\d+) characters$/.exec(t);if(t===`is required`)return`此欄為必填。`;if(r)return`至少需要 ${r[1]} 列。`;if(i)return`最多 ${i[1]} 列。`;if(a)return`至少需要 ${a[1]} 個字。`;if(o)return`最多 ${o[1]} 個字。`;if(t===`does not match the required format`){let t=m(e,n);return(t&&(t.type===`text`||t.type===`textarea`)?t.patternErrorMessage?.trim():void 0)||`格式不正確。`}return t===`could not be checked against the required format in time`?`格式檢查逾時,請縮短內容後再試,或請表單設計者簡化格式。`:e.includes(`[`)?`此欄內容不正確。`:`此欄位內容不正確。`}function g(t,n,r){let i=n.fields.filter(t=>(0,e.readNodeFillableFieldKeys)(r).has(t.fieldKey));if(t.startsWith(p)){let e=`, ${t.slice(38)}, `,n=i.filter(t=>e.includes(`, ${t.label||t.fieldKey}, `));return n.length>0?Object.fromEntries(n.map(e=>[e.fieldKey,`${e.label||e.fieldKey}為必填欄位。`])):null}let a=t.split(`; `).map(e=>f.exec(e));return a.length===0||a.some(e=>e===null)?null:Object.fromEntries(a.flatMap(e=>e===null?[]:[[e[1],h(e[1],e[2],i)]]))}var _=`未知組織`;function v(e,t){return[...new Set(e.fields.filter(n.isOrgUnitFieldDefinition).map(e=>t[e.fieldKey]).filter(e=>typeof e==`string`&&e.trim().length>0))]}function y(r,i,a,o){if((0,n.isTableFieldDefinition)(r)){let e=(0,t.readFormTableRows)(i),n=r.columns.filter(e=>e.type===`number`||e.type===`money`).map(t=>({label:t.label||t.fieldKey,total:e.reduce((e,n)=>typeof n[t.fieldKey]==`number`&&Number.isFinite(n[t.fieldKey])?e+n[t.fieldKey]:e,0)}));return[`${e.length} 列`,...e.length>0?n.map(({label:e,total:t})=>`${e}合計 ${t.toLocaleString(`zh-TW`)}`):[]].join(`,`)}if((0,e.isFormDataValueEmpty)(i))return`未填寫`;if(typeof i==`boolean`)return i?`是`:`否`;if((0,n.isOrgUnitFieldDefinition)(r))return typeof i==`string`?o.get(i)??`未知組織`:_;let s=Array.isArray(i)?i:[i],c=(0,n.isFormStaticOptionFieldDefinition)(r)?new Map(r.options.map(e=>[e.value,e.label])):r.type===`member`?a:new Map;return s.map(e=>typeof e==`string`?c.get(e)??e:String(e)).join(`、`)}function b(t,n,r,i=new Map,a=new Map){let o=(0,e.readNodeFillableFieldKeys)(n);return t.fields.filter(e=>o.has(e.fieldKey)&&Object.prototype.hasOwnProperty.call(r,e.fieldKey)).map(e=>({fieldKey:e.fieldKey,label:e.label||e.fieldKey,text:y(e,r[e.fieldKey],i,a)}))}var x=`表單中有附件無法附加到這個案件(只能附加申請人為本案上傳的檔案),請移除後重新上傳再送出。`;function S(e){let r=(0,t.readFormDataSourceErrorMessage)(e);if(r)return r;let i=e instanceof Error?e.message:null;return i?.includes(n.ATTACHMENT_NOT_BINDABLE_ERROR_CODE)?x:i??`發生未知錯誤`}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return g}});
|
|
2
|
+
//# sourceMappingURL=instance-error-message-DTARGbGo.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-error-message-DTARGbGo.cjs","names":["readApproverFilledFieldKeys","omitFormDataKeys","readNodeFillableFieldKeys","readNodeRequiredFieldKeys","isTableFieldDefinition","isOrgUnitFieldDefinition","readFormTableRows","isFormDataValueEmpty","isFormStaticOptionFieldDefinition","readFormDataSourceErrorMessage","ATTACHMENT_NOT_BINDABLE_ERROR_CODE","_rytass_bpm_core_shared","_rytass_bpm_core_client_form","_rytass_bpm_core_shared_form","readApplicantFormSchema","approverFilledKeys","definition","schema","field","readApplicantSubmission","values","readFillValidationSchema","fillableKeys","node","displaySchema","readFillDisplaySchema","requiredKeys","userTaskNodes","readFillLabelMarkers","viewerKeys","viewerFillNode","fieldKey","markers","readFillPayload","readFillChanges","seededTables","seeded","stored","draft","isFillConflictMessage","message","FORM_DATA_PATH_PATTERN","MISSING_FIELDS_PREFIX","readFillPathField","columnKey","path","fields","candidate","column","readFillPathErrorText","atLeast","reason","atMost","shortest","longest","readFillServerErrors","fillableFields","listed","missing","parts","part","UNKNOWN_FILL_ORG_UNIT_TEXT","readFillOrgUnitIds","value","readFillValueText","rows","totals","row","sum","label","total","orgUnitNames","items","optionLabels","option","memberNames","item","readFillSummary","ATTACHMENT_NOT_BINDABLE_MESSAGE","readErrorMessage","dataSourceMessage","error"],"sources":["../../src/views/instances/approver-filled-form.ts","../../src/views/instances/instance-error-message.ts"],"sourcesContent":["import {\n isFormDataValueEmpty,\n omitFormDataKeys,\n readApproverFilledFieldKeys,\n readNodeFillableFieldKeys,\n readNodeRequiredFieldKeys,\n type UserTaskNode,\n type WorkflowDefinition,\n} from '@rytass/bpm-core-shared';\nimport {\n isFormStaticOptionFieldDefinition,\n isOrgUnitFieldDefinition,\n isTableFieldDefinition,\n type FormDefinitionSchema,\n type FormFieldDefinition,\n type FormFieldValue,\n type TableColumnDefinition,\n} from '@rytass/bpm-core-shared/form';\nimport { readFormTableRows } from '@rytass/bpm-core-client/form';\nimport type { WorkflowFormData } from '@rytass/bpm-core-client/workflow';\n\n/**\n * The form as the applicant sees it: without the fields some approver fills in.\n * The server drops those keys from a submission, so rendering one would swallow\n * what the applicant types, and a `minRows` or `required` on it would block a\n * launch nobody can complete. Returns an equal schema when nothing is\n * approver-filled; never mutates its input.\n */\nexport function readApplicantFormSchema(\n schema: FormDefinitionSchema,\n definition: WorkflowDefinition,\n): FormDefinitionSchema {\n const approverFilledKeys = readApproverFilledFieldKeys(definition);\n\n return {\n ...schema,\n fields: schema.fields.filter(\n (field) => !approverFilledKeys.has(field.fieldKey),\n ),\n };\n}\n\n/** The payload the applicant may send: `values` without approver-filled keys. */\nexport function readApplicantSubmission(\n values: WorkflowFormData,\n definition: WorkflowDefinition,\n): WorkflowFormData {\n // Dropping keys cannot change a remaining value's type, which is all the\n // shared helper's `unknown` return forgets.\n return omitFormDataKeys(\n values,\n readApproverFilledFieldKeys(definition),\n ) as WorkflowFormData;\n}\n\n/**\n * The form an approver's fill is validated against: only the fields `node`\n * lets them fill in, each required exactly when the node says `REQUIRED`. A\n * required table needs at least one row, the rule `validateFormRendererValues`\n * already applies, so the result agrees with the server's fill check. Never\n * mutates its input.\n */\nexport function readFillValidationSchema(\n schema: FormDefinitionSchema,\n node: UserTaskNode,\n): FormDefinitionSchema {\n const fillableKeys = readNodeFillableFieldKeys(node);\n const displaySchema = readFillDisplaySchema(schema, node);\n\n // Derived from the display schema so the check and the asterisk read the\n // same rule.\n return {\n ...displaySchema,\n fields: displaySchema.fields.filter((field) =>\n fillableKeys.has(field.fieldKey),\n ),\n };\n}\n\n/**\n * The schema the fill node's approver sees: every field as the form defines\n * it, except that the node's fillable fields are required exactly when the\n * node says `REQUIRED`, so the asterisk matches what approving will check.\n */\nexport function readFillDisplaySchema(\n schema: FormDefinitionSchema,\n node: UserTaskNode,\n): FormDefinitionSchema {\n const fillableKeys = readNodeFillableFieldKeys(node);\n const requiredKeys = readNodeRequiredFieldKeys(node);\n\n return {\n ...schema,\n fields: schema.fields.map((field) =>\n fillableKeys.has(field.fieldKey)\n ? {\n ...field,\n required: requiredKeys.has(field.fieldKey),\n // The node alone decides; the server ignores the form's rule.\n requiredWhen: undefined,\n }\n : field,\n ),\n };\n}\n\nconst userTaskNodes = (definition: WorkflowDefinition): readonly UserTaskNode[] =>\n definition.nodes.filter(\n (node): node is UserTaskNode => node.type === 'userTask',\n );\n\n/**\n * The marker shown after each approver-filled field's label: 「本關補填」 on\n * the fields `viewerFillNode` lets the viewer fill, 「<node>補填」 on every\n * other approver-filled field (the first node in the definition that fills\n * it names it).\n */\nexport function readFillLabelMarkers(\n definition: WorkflowDefinition,\n viewerFillNode: UserTaskNode | null,\n): Readonly<Record<string, string>> {\n const viewerKeys =\n viewerFillNode === null\n ? new Set<string>()\n : readNodeFillableFieldKeys(viewerFillNode);\n\n return userTaskNodes(definition).reduce<Readonly<Record<string, string>>>(\n (markers, node) => ({\n ...Object.fromEntries(\n [...readNodeFillableFieldKeys(node)].map((fieldKey) => [\n fieldKey,\n viewerKeys.has(fieldKey)\n ? '本關補填'\n : `${node.data.label || node.id}補填`,\n ]),\n ),\n ...markers,\n }),\n {},\n );\n}\n\n/**\n * What approving sends as `fill.formData`: the keys of `values` that `node`\n * lets its approver fill, and nothing else (the server refuses any other key).\n * `values` is what the approver changed, not the rendered form — a renderer\n * default the approver never touched (a table's empty rows, a boolean's\n * `false`) is not theirs to sign, and would otherwise show up as filled in.\n */\nexport function readFillPayload(\n values: WorkflowFormData,\n node: UserTaskNode,\n): Readonly<Record<string, unknown>> {\n return Object.fromEntries(\n [...readNodeFillableFieldKeys(node)]\n .filter((fieldKey) =>\n Object.prototype.hasOwnProperty.call(values, fieldKey),\n )\n // A cleared field reads `undefined`, which JSON drops, and the server\n // would keep the old value; `null` clears it.\n .map((fieldKey) => [fieldKey, values[fieldKey] ?? null]),\n );\n}\n\n/**\n * What the approver's fill amounts to: the fields they changed (`draft`), plus\n * each fill table the page seeds with `minRows` rows that the case does not\n * store yet. The page shows those rows and validates them, so they are sent\n * too — left out, the server would refuse the approval for missing rows the\n * approver can see on screen.\n */\nexport function readFillChanges({\n draft,\n node,\n schema,\n stored,\n values,\n}: {\n readonly draft: WorkflowFormData;\n readonly node: UserTaskNode;\n readonly schema: FormDefinitionSchema;\n readonly stored: WorkflowFormData;\n readonly values: WorkflowFormData;\n}): WorkflowFormData {\n const fillableKeys = readNodeFillableFieldKeys(node);\n const seededTables = schema.fields.filter((field) => {\n const seeded = values[field.fieldKey];\n\n return (\n isTableFieldDefinition(field) &&\n fillableKeys.has(field.fieldKey) &&\n !Object.prototype.hasOwnProperty.call(stored, field.fieldKey) &&\n Array.isArray(seeded) &&\n seeded.length > 0\n );\n });\n\n return {\n ...Object.fromEntries(\n seededTables.map((field) => [field.fieldKey, values[field.fieldKey]]),\n ),\n ...draft,\n };\n}\n\n/** The server message of a fill against form data someone else changed. */\nexport function isFillConflictMessage(message: string): boolean {\n return message.includes('form data changed; refresh and retry');\n}\n\nconst FORM_DATA_PATH_PATTERN =\n /^formData\\.([A-Za-z_][A-Za-z0-9_]*(?:\\[\\d+\\]\\.[A-Za-z_][A-Za-z0-9_]*)?) (.+)$/;\nconst MISSING_FIELDS_PREFIX = 'Form data is missing required fields: ';\n\n/**\n * The field or table column a server error path such as `note` or\n * `items[0].name` points at, so its own settings can word the error.\n */\nfunction readFillPathField(\n path: string,\n fields: readonly FormFieldDefinition[],\n): FormFieldDefinition | TableColumnDefinition | undefined {\n const [fieldKey, columnKey] = path.split(/\\[\\d+\\]\\./);\n const field = fields.find((candidate) => candidate.fieldKey === fieldKey);\n\n return columnKey === undefined\n ? field\n : field && isTableFieldDefinition(field)\n ? field.columns.find((column) => column.fieldKey === columnKey)\n : undefined;\n}\n\nfunction readFillPathErrorText(\n path: string,\n reason: string,\n fields: readonly FormFieldDefinition[],\n): string {\n const atLeast = /^must include at least (\\d+) row\\(s\\)$/.exec(reason);\n const atMost = /^must include at most (\\d+) row\\(s\\)$/.exec(reason);\n const shortest = /^must be at least (\\d+) characters$/.exec(reason);\n const longest = /^must be at most (\\d+) characters$/.exec(reason);\n\n if (reason === 'is required') {\n return '此欄為必填。';\n }\n\n if (atLeast) {\n return `至少需要 ${atLeast[1]} 列。`;\n }\n\n if (atMost) {\n return `最多 ${atMost[1]} 列。`;\n }\n\n if (shortest) {\n return `至少需要 ${shortest[1]} 個字。`;\n }\n\n if (longest) {\n return `最多 ${longest[1]} 個字。`;\n }\n\n if (reason === 'does not match the required format') {\n const field = readFillPathField(path, fields);\n const message =\n field && (field.type === 'text' || field.type === 'textarea')\n ? field.patternErrorMessage?.trim()\n : undefined;\n\n return message || '格式不正確。';\n }\n\n // The server ran out of time on the format check; the value may be fine.\n if (reason === 'could not be checked against the required format in time') {\n return '格式檢查逾時,請縮短內容後再試,或請表單設計者簡化格式。';\n }\n\n return path.includes('[') ? '此欄內容不正確。' : '此欄位內容不正確。';\n}\n\n/**\n * Turns the server's fill validation message (docs/08 §8.5, error table 2)\n * into field errors keyed the way `FormRenderer` addresses them, so a check\n * the page missed still lands on the field. `null` when any part does not\n * parse — the caller then shows the message as it is.\n */\nexport function readFillServerErrors(\n message: string,\n schema: FormDefinitionSchema,\n node: UserTaskNode,\n): Readonly<Record<string, string>> | null {\n const fillableFields = schema.fields.filter((field) =>\n readNodeFillableFieldKeys(node).has(field.fieldKey),\n );\n\n if (message.startsWith(MISSING_FIELDS_PREFIX)) {\n // Labels may hold commas, so match each fillable field's label (or key)\n // against the list rather than splitting it.\n const listed = `, ${message.slice(MISSING_FIELDS_PREFIX.length)}, `;\n const missing = fillableFields.filter((field) =>\n listed.includes(`, ${field.label || field.fieldKey}, `),\n );\n\n return missing.length > 0\n ? Object.fromEntries(\n missing.map((field) => [\n field.fieldKey,\n `${field.label || field.fieldKey}為必填欄位。`,\n ]),\n )\n : null;\n }\n\n const parts = message.split('; ').map((part) => FORM_DATA_PATH_PATTERN.exec(part));\n\n if (parts.length === 0 || parts.some((part) => part === null)) {\n return null;\n }\n\n return Object.fromEntries(\n parts.flatMap((part) =>\n part === null\n ? []\n : [[part[1], readFillPathErrorText(part[1], part[2], fillableFields)]],\n ),\n );\n}\n\nexport interface FillSummaryItem {\n readonly fieldKey: string;\n readonly label: string;\n readonly text: string;\n}\n\nexport const UNKNOWN_FILL_ORG_UNIT_TEXT = '未知組織';\n\n/**\n * The org unit ids among `values`, once each and in form order, so the caller\n * can look up their names before building the summary.\n */\nexport function readFillOrgUnitIds(\n schema: FormDefinitionSchema,\n values: WorkflowFormData,\n): readonly string[] {\n return [\n ...new Set(\n schema.fields\n .filter(isOrgUnitFieldDefinition)\n .map((field) => values[field.fieldKey])\n .filter(\n (value): value is string =>\n typeof value === 'string' && value.trim().length > 0,\n ),\n ),\n ];\n}\n\nfunction readFillValueText(\n field: FormFieldDefinition,\n value: FormFieldValue | undefined,\n memberNames: ReadonlyMap<string, string>,\n orgUnitNames: ReadonlyMap<string, string>,\n): string {\n if (isTableFieldDefinition(field)) {\n const rows = readFormTableRows(value);\n const totals = field.columns\n .filter((column) => column.type === 'number' || column.type === 'money')\n .map((column) => ({\n label: column.label || column.fieldKey,\n total: rows.reduce(\n (sum, row) =>\n typeof row[column.fieldKey] === 'number' &&\n Number.isFinite(row[column.fieldKey])\n ? sum + (row[column.fieldKey] as number)\n : sum,\n 0,\n ),\n }));\n\n return [\n `${rows.length} 列`,\n ...(rows.length > 0\n ? totals.map(\n ({ label, total }) => `${label}合計 ${total.toLocaleString('zh-TW')}`,\n )\n : []),\n ].join(',');\n }\n\n if (isFormDataValueEmpty(value)) {\n return '未填寫';\n }\n\n if (typeof value === 'boolean') {\n return value ? '是' : '否';\n }\n\n if (isOrgUnitFieldDefinition(field)) {\n // `orgUnitNames` (`useOrgUnitNames`) maps an id still being looked up to\n // a loading text; an id the lookup did not name is 「未知組織」. Never the\n // raw id.\n return typeof value === 'string'\n ? (orgUnitNames.get(value) ?? UNKNOWN_FILL_ORG_UNIT_TEXT)\n : UNKNOWN_FILL_ORG_UNIT_TEXT;\n }\n\n const items = Array.isArray(value) ? value : [value];\n const optionLabels = isFormStaticOptionFieldDefinition(field)\n ? new Map(field.options.map((option) => [option.value, option.label]))\n : field.type === 'member'\n ? memberNames\n : new Map<string, string>();\n\n return items\n .map((item) =>\n typeof item === 'string' ? (optionLabels.get(item) ?? item) : String(item),\n )\n .join('、');\n}\n\n/**\n * One line per field `node` lets its approver fill, in form order, for the\n * approve dialog: what will be sent along with the approval. A member field\n * names each member found in `memberNames` and shows the id otherwise; an org\n * unit field names its unit from `orgUnitNames` and shows 「未知組織」 otherwise.\n */\nexport function readFillSummary(\n schema: FormDefinitionSchema,\n node: UserTaskNode,\n values: WorkflowFormData,\n memberNames: ReadonlyMap<string, string> = new Map(),\n orgUnitNames: ReadonlyMap<string, string> = new Map(),\n): readonly FillSummaryItem[] {\n const fillableKeys = readNodeFillableFieldKeys(node);\n\n return schema.fields\n .filter(\n (field) =>\n fillableKeys.has(field.fieldKey) &&\n Object.prototype.hasOwnProperty.call(values, field.fieldKey),\n )\n .map((field) => ({\n fieldKey: field.fieldKey,\n label: field.label || field.fieldKey,\n text: readFillValueText(\n field,\n values[field.fieldKey],\n memberNames,\n orgUnitNames,\n ),\n }));\n}\n","import { readFormDataSourceErrorMessage } from '@rytass/bpm-core-client/form';\nimport { ATTACHMENT_NOT_BINDABLE_ERROR_CODE } from '@rytass/bpm-core-shared/form';\n\nconst ATTACHMENT_NOT_BINDABLE_MESSAGE =\n '表單中有附件無法附加到這個案件(只能附加申請人為本案上傳的檔案),請移除後重新上傳再送出。';\n\n/**\n * The message a case page shows for a failed request: a stable server code\n * translated into words, otherwise the server's own message.\n */\nexport function readErrorMessage(error: unknown): string {\n // DataSource failures arrive as stable codes so the backend never leaks\n // upstream transport detail; translate them instead of showing the raw code.\n const dataSourceMessage = readFormDataSourceErrorMessage(error);\n\n if (dataSourceMessage) {\n return dataSourceMessage;\n }\n\n const message = error instanceof Error ? error.message : null;\n\n // Names the problem, not the attachment ids the server lists.\n if (message?.includes(ATTACHMENT_NOT_BINDABLE_ERROR_CODE)) {\n return ATTACHMENT_NOT_BINDABLE_MESSAGE;\n }\n\n return message ?? '發生未知錯誤';\n}\n"],"mappings":"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"}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import { isFormDataValueEmpty as e, omitFormDataKeys as t, readApproverFilledFieldKeys as n, readNodeFillableFieldKeys as r, readNodeRequiredFieldKeys as i } from "@rytass/bpm-core-shared";
|
|
2
|
-
import {
|
|
3
|
-
import { isFormStaticOptionFieldDefinition as
|
|
2
|
+
import { readFormDataSourceErrorMessage as a, readFormTableRows as o } from "@rytass/bpm-core-client/form";
|
|
3
|
+
import { ATTACHMENT_NOT_BINDABLE_ERROR_CODE as s, isFormStaticOptionFieldDefinition as c, isOrgUnitFieldDefinition as l, isTableFieldDefinition as u } from "@rytass/bpm-core-shared/form";
|
|
4
4
|
// src/views/instances/approver-filled-form.ts
|
|
5
|
-
function
|
|
5
|
+
function d(e, t) {
|
|
6
6
|
let r = n(t);
|
|
7
7
|
return {
|
|
8
8
|
...e,
|
|
9
9
|
fields: e.fields.filter((e) => !r.has(e.fieldKey))
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
|
-
function
|
|
12
|
+
function f(e, r) {
|
|
13
13
|
return t(e, n(r));
|
|
14
14
|
}
|
|
15
|
-
function
|
|
16
|
-
let n = r(t), i =
|
|
15
|
+
function p(e, t) {
|
|
16
|
+
let n = r(t), i = m(e, t);
|
|
17
17
|
return {
|
|
18
18
|
...i,
|
|
19
19
|
fields: i.fields.filter((e) => n.has(e.fieldKey))
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
|
-
function
|
|
22
|
+
function m(e, t) {
|
|
23
23
|
let n = r(t), a = i(t);
|
|
24
24
|
return {
|
|
25
25
|
...e,
|
|
@@ -30,36 +30,36 @@ function f(e, t) {
|
|
|
30
30
|
} : e)
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
var
|
|
34
|
-
function
|
|
33
|
+
var h = (e) => e.nodes.filter((e) => e.type === "userTask");
|
|
34
|
+
function g(e, t) {
|
|
35
35
|
let n = t === null ? /* @__PURE__ */ new Set() : r(t);
|
|
36
|
-
return
|
|
36
|
+
return h(e).reduce((e, t) => ({
|
|
37
37
|
...Object.fromEntries([...r(t)].map((e) => [e, n.has(e) ? "本關補填" : `${t.data.label || t.id}補填`])),
|
|
38
38
|
...e
|
|
39
39
|
}), {});
|
|
40
40
|
}
|
|
41
|
-
function
|
|
41
|
+
function _(e, t) {
|
|
42
42
|
return Object.fromEntries([...r(t)].filter((t) => Object.prototype.hasOwnProperty.call(e, t)).map((t) => [t, e[t] ?? null]));
|
|
43
43
|
}
|
|
44
|
-
function
|
|
44
|
+
function v({ draft: e, node: t, schema: n, stored: i, values: a }) {
|
|
45
45
|
let o = r(t), s = n.fields.filter((e) => {
|
|
46
46
|
let t = a[e.fieldKey];
|
|
47
|
-
return
|
|
47
|
+
return u(e) && o.has(e.fieldKey) && !Object.prototype.hasOwnProperty.call(i, e.fieldKey) && Array.isArray(t) && t.length > 0;
|
|
48
48
|
});
|
|
49
49
|
return {
|
|
50
50
|
...Object.fromEntries(s.map((e) => [e.fieldKey, a[e.fieldKey]])),
|
|
51
51
|
...e
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
-
function
|
|
54
|
+
function y(e) {
|
|
55
55
|
return e.includes("form data changed; refresh and retry");
|
|
56
56
|
}
|
|
57
|
-
var
|
|
58
|
-
function
|
|
57
|
+
var b = /^formData\.([A-Za-z_][A-Za-z0-9_]*(?:\[\d+\]\.[A-Za-z_][A-Za-z0-9_]*)?) (.+)$/, x = "Form data is missing required fields: ";
|
|
58
|
+
function S(e, t) {
|
|
59
59
|
let [n, r] = e.split(/\[\d+\]\./), i = t.find((e) => e.fieldKey === n);
|
|
60
|
-
return r === void 0 ? i : i &&
|
|
60
|
+
return r === void 0 ? i : i && u(i) ? i.columns.find((e) => e.fieldKey === r) : void 0;
|
|
61
61
|
}
|
|
62
|
-
function
|
|
62
|
+
function C(e, t, n) {
|
|
63
63
|
let r = /^must include at least (\d+) row\(s\)$/.exec(t), i = /^must include at most (\d+) row\(s\)$/.exec(t), a = /^must be at least (\d+) characters$/.exec(t), o = /^must be at most (\d+) characters$/.exec(t);
|
|
64
64
|
if (t === "is required") return "此欄為必填。";
|
|
65
65
|
if (r) return `至少需要 ${r[1]} 列。`;
|
|
@@ -67,27 +67,27 @@ function x(e, t, n) {
|
|
|
67
67
|
if (a) return `至少需要 ${a[1]} 個字。`;
|
|
68
68
|
if (o) return `最多 ${o[1]} 個字。`;
|
|
69
69
|
if (t === "does not match the required format") {
|
|
70
|
-
let t =
|
|
70
|
+
let t = S(e, n);
|
|
71
71
|
return (t && (t.type === "text" || t.type === "textarea") ? t.patternErrorMessage?.trim() : void 0) || "格式不正確。";
|
|
72
72
|
}
|
|
73
73
|
return t === "could not be checked against the required format in time" ? "格式檢查逾時,請縮短內容後再試,或請表單設計者簡化格式。" : e.includes("[") ? "此欄內容不正確。" : "此欄位內容不正確。";
|
|
74
74
|
}
|
|
75
|
-
function
|
|
75
|
+
function w(e, t, n) {
|
|
76
76
|
let i = t.fields.filter((e) => r(n).has(e.fieldKey));
|
|
77
|
-
if (e.startsWith(
|
|
77
|
+
if (e.startsWith(x)) {
|
|
78
78
|
let t = `, ${e.slice(38)}, `, n = i.filter((e) => t.includes(`, ${e.label || e.fieldKey}, `));
|
|
79
79
|
return n.length > 0 ? Object.fromEntries(n.map((e) => [e.fieldKey, `${e.label || e.fieldKey}為必填欄位。`])) : null;
|
|
80
80
|
}
|
|
81
|
-
let a = e.split("; ").map((e) =>
|
|
82
|
-
return a.length === 0 || a.some((e) => e === null) ? null : Object.fromEntries(a.flatMap((e) => e === null ? [] : [[e[1],
|
|
81
|
+
let a = e.split("; ").map((e) => b.exec(e));
|
|
82
|
+
return a.length === 0 || a.some((e) => e === null) ? null : Object.fromEntries(a.flatMap((e) => e === null ? [] : [[e[1], C(e[1], e[2], i)]]));
|
|
83
83
|
}
|
|
84
|
-
var
|
|
85
|
-
function
|
|
86
|
-
return [...new Set(e.fields.filter(
|
|
84
|
+
var T = "未知組織";
|
|
85
|
+
function E(e, t) {
|
|
86
|
+
return [...new Set(e.fields.filter(l).map((e) => t[e.fieldKey]).filter((e) => typeof e == "string" && e.trim().length > 0))];
|
|
87
87
|
}
|
|
88
|
-
function
|
|
89
|
-
if (
|
|
90
|
-
let e =
|
|
88
|
+
function D(t, n, r, i) {
|
|
89
|
+
if (u(t)) {
|
|
90
|
+
let e = o(n), r = t.columns.filter((e) => e.type === "number" || e.type === "money").map((t) => ({
|
|
91
91
|
label: t.label || t.fieldKey,
|
|
92
92
|
total: e.reduce((e, n) => typeof n[t.fieldKey] == "number" && Number.isFinite(n[t.fieldKey]) ? e + n[t.fieldKey] : e, 0)
|
|
93
93
|
}));
|
|
@@ -95,18 +95,26 @@ function T(t, n, r, i) {
|
|
|
95
95
|
}
|
|
96
96
|
if (e(n)) return "未填寫";
|
|
97
97
|
if (typeof n == "boolean") return n ? "是" : "否";
|
|
98
|
-
if (
|
|
99
|
-
let
|
|
100
|
-
return
|
|
98
|
+
if (l(t)) return typeof n == "string" ? i.get(n) ?? "未知組織" : T;
|
|
99
|
+
let a = Array.isArray(n) ? n : [n], s = c(t) ? new Map(t.options.map((e) => [e.value, e.label])) : t.type === "member" ? r : /* @__PURE__ */ new Map();
|
|
100
|
+
return a.map((e) => typeof e == "string" ? s.get(e) ?? e : String(e)).join("、");
|
|
101
101
|
}
|
|
102
|
-
function
|
|
102
|
+
function O(e, t, n, i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map()) {
|
|
103
103
|
let o = r(t);
|
|
104
104
|
return e.fields.filter((e) => o.has(e.fieldKey) && Object.prototype.hasOwnProperty.call(n, e.fieldKey)).map((e) => ({
|
|
105
105
|
fieldKey: e.fieldKey,
|
|
106
106
|
label: e.label || e.fieldKey,
|
|
107
|
-
text:
|
|
107
|
+
text: D(e, n[e.fieldKey], i, a)
|
|
108
108
|
}));
|
|
109
109
|
}
|
|
110
|
-
|
|
110
|
+
// src/views/instances/instance-error-message.ts
|
|
111
|
+
var k = "表單中有附件無法附加到這個案件(只能附加申請人為本案上傳的檔案),請移除後重新上傳再送出。";
|
|
112
|
+
function A(e) {
|
|
113
|
+
let t = a(e);
|
|
114
|
+
if (t) return t;
|
|
115
|
+
let n = e instanceof Error ? e.message : null;
|
|
116
|
+
return n?.includes(s) ? k : n ?? "發生未知錯誤";
|
|
117
|
+
}
|
|
118
|
+
export { v as a, E as c, O as d, p as f, f as i, _ as l, y as n, m as o, d as r, g as s, A as t, w as u };
|
|
111
119
|
|
|
112
|
-
//# sourceMappingURL=
|
|
120
|
+
//# sourceMappingURL=instance-error-message-q6gy5evy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-error-message-q6gy5evy.js","names":["readApplicantFormSchema","approverFilledKeys","readApproverFilledFieldKeys","definition","schema","field","readApplicantSubmission","omitFormDataKeys","values","readFillValidationSchema","fillableKeys","readNodeFillableFieldKeys","node","displaySchema","readFillDisplaySchema","requiredKeys","readNodeRequiredFieldKeys","userTaskNodes","readFillLabelMarkers","viewerKeys","viewerFillNode","fieldKey","markers","readFillPayload","readFillChanges","seededTables","seeded","isTableFieldDefinition","stored","draft","isFillConflictMessage","message","FORM_DATA_PATH_PATTERN","MISSING_FIELDS_PREFIX","readFillPathField","columnKey","path","fields","candidate","column","readFillPathErrorText","atLeast","reason","atMost","shortest","longest","readFillServerErrors","fillableFields","listed","missing","parts","part","UNKNOWN_FILL_ORG_UNIT_TEXT","readFillOrgUnitIds","isOrgUnitFieldDefinition","value","readFillValueText","rows","readFormTableRows","totals","row","sum","label","total","isFormDataValueEmpty","orgUnitNames","items","optionLabels","isFormStaticOptionFieldDefinition","option","memberNames","item","readFillSummary","ATTACHMENT_NOT_BINDABLE_MESSAGE","readErrorMessage","dataSourceMessage","readFormDataSourceErrorMessage","error","ATTACHMENT_NOT_BINDABLE_ERROR_CODE"],"sources":["../../src/views/instances/approver-filled-form.ts","../../src/views/instances/instance-error-message.ts"],"sourcesContent":["import {\n isFormDataValueEmpty,\n omitFormDataKeys,\n readApproverFilledFieldKeys,\n readNodeFillableFieldKeys,\n readNodeRequiredFieldKeys,\n type UserTaskNode,\n type WorkflowDefinition,\n} from '@rytass/bpm-core-shared';\nimport {\n isFormStaticOptionFieldDefinition,\n isOrgUnitFieldDefinition,\n isTableFieldDefinition,\n type FormDefinitionSchema,\n type FormFieldDefinition,\n type FormFieldValue,\n type TableColumnDefinition,\n} from '@rytass/bpm-core-shared/form';\nimport { readFormTableRows } from '@rytass/bpm-core-client/form';\nimport type { WorkflowFormData } from '@rytass/bpm-core-client/workflow';\n\n/**\n * The form as the applicant sees it: without the fields some approver fills in.\n * The server drops those keys from a submission, so rendering one would swallow\n * what the applicant types, and a `minRows` or `required` on it would block a\n * launch nobody can complete. Returns an equal schema when nothing is\n * approver-filled; never mutates its input.\n */\nexport function readApplicantFormSchema(\n schema: FormDefinitionSchema,\n definition: WorkflowDefinition,\n): FormDefinitionSchema {\n const approverFilledKeys = readApproverFilledFieldKeys(definition);\n\n return {\n ...schema,\n fields: schema.fields.filter(\n (field) => !approverFilledKeys.has(field.fieldKey),\n ),\n };\n}\n\n/** The payload the applicant may send: `values` without approver-filled keys. */\nexport function readApplicantSubmission(\n values: WorkflowFormData,\n definition: WorkflowDefinition,\n): WorkflowFormData {\n // Dropping keys cannot change a remaining value's type, which is all the\n // shared helper's `unknown` return forgets.\n return omitFormDataKeys(\n values,\n readApproverFilledFieldKeys(definition),\n ) as WorkflowFormData;\n}\n\n/**\n * The form an approver's fill is validated against: only the fields `node`\n * lets them fill in, each required exactly when the node says `REQUIRED`. A\n * required table needs at least one row, the rule `validateFormRendererValues`\n * already applies, so the result agrees with the server's fill check. Never\n * mutates its input.\n */\nexport function readFillValidationSchema(\n schema: FormDefinitionSchema,\n node: UserTaskNode,\n): FormDefinitionSchema {\n const fillableKeys = readNodeFillableFieldKeys(node);\n const displaySchema = readFillDisplaySchema(schema, node);\n\n // Derived from the display schema so the check and the asterisk read the\n // same rule.\n return {\n ...displaySchema,\n fields: displaySchema.fields.filter((field) =>\n fillableKeys.has(field.fieldKey),\n ),\n };\n}\n\n/**\n * The schema the fill node's approver sees: every field as the form defines\n * it, except that the node's fillable fields are required exactly when the\n * node says `REQUIRED`, so the asterisk matches what approving will check.\n */\nexport function readFillDisplaySchema(\n schema: FormDefinitionSchema,\n node: UserTaskNode,\n): FormDefinitionSchema {\n const fillableKeys = readNodeFillableFieldKeys(node);\n const requiredKeys = readNodeRequiredFieldKeys(node);\n\n return {\n ...schema,\n fields: schema.fields.map((field) =>\n fillableKeys.has(field.fieldKey)\n ? {\n ...field,\n required: requiredKeys.has(field.fieldKey),\n // The node alone decides; the server ignores the form's rule.\n requiredWhen: undefined,\n }\n : field,\n ),\n };\n}\n\nconst userTaskNodes = (definition: WorkflowDefinition): readonly UserTaskNode[] =>\n definition.nodes.filter(\n (node): node is UserTaskNode => node.type === 'userTask',\n );\n\n/**\n * The marker shown after each approver-filled field's label: 「本關補填」 on\n * the fields `viewerFillNode` lets the viewer fill, 「<node>補填」 on every\n * other approver-filled field (the first node in the definition that fills\n * it names it).\n */\nexport function readFillLabelMarkers(\n definition: WorkflowDefinition,\n viewerFillNode: UserTaskNode | null,\n): Readonly<Record<string, string>> {\n const viewerKeys =\n viewerFillNode === null\n ? new Set<string>()\n : readNodeFillableFieldKeys(viewerFillNode);\n\n return userTaskNodes(definition).reduce<Readonly<Record<string, string>>>(\n (markers, node) => ({\n ...Object.fromEntries(\n [...readNodeFillableFieldKeys(node)].map((fieldKey) => [\n fieldKey,\n viewerKeys.has(fieldKey)\n ? '本關補填'\n : `${node.data.label || node.id}補填`,\n ]),\n ),\n ...markers,\n }),\n {},\n );\n}\n\n/**\n * What approving sends as `fill.formData`: the keys of `values` that `node`\n * lets its approver fill, and nothing else (the server refuses any other key).\n * `values` is what the approver changed, not the rendered form — a renderer\n * default the approver never touched (a table's empty rows, a boolean's\n * `false`) is not theirs to sign, and would otherwise show up as filled in.\n */\nexport function readFillPayload(\n values: WorkflowFormData,\n node: UserTaskNode,\n): Readonly<Record<string, unknown>> {\n return Object.fromEntries(\n [...readNodeFillableFieldKeys(node)]\n .filter((fieldKey) =>\n Object.prototype.hasOwnProperty.call(values, fieldKey),\n )\n // A cleared field reads `undefined`, which JSON drops, and the server\n // would keep the old value; `null` clears it.\n .map((fieldKey) => [fieldKey, values[fieldKey] ?? null]),\n );\n}\n\n/**\n * What the approver's fill amounts to: the fields they changed (`draft`), plus\n * each fill table the page seeds with `minRows` rows that the case does not\n * store yet. The page shows those rows and validates them, so they are sent\n * too — left out, the server would refuse the approval for missing rows the\n * approver can see on screen.\n */\nexport function readFillChanges({\n draft,\n node,\n schema,\n stored,\n values,\n}: {\n readonly draft: WorkflowFormData;\n readonly node: UserTaskNode;\n readonly schema: FormDefinitionSchema;\n readonly stored: WorkflowFormData;\n readonly values: WorkflowFormData;\n}): WorkflowFormData {\n const fillableKeys = readNodeFillableFieldKeys(node);\n const seededTables = schema.fields.filter((field) => {\n const seeded = values[field.fieldKey];\n\n return (\n isTableFieldDefinition(field) &&\n fillableKeys.has(field.fieldKey) &&\n !Object.prototype.hasOwnProperty.call(stored, field.fieldKey) &&\n Array.isArray(seeded) &&\n seeded.length > 0\n );\n });\n\n return {\n ...Object.fromEntries(\n seededTables.map((field) => [field.fieldKey, values[field.fieldKey]]),\n ),\n ...draft,\n };\n}\n\n/** The server message of a fill against form data someone else changed. */\nexport function isFillConflictMessage(message: string): boolean {\n return message.includes('form data changed; refresh and retry');\n}\n\nconst FORM_DATA_PATH_PATTERN =\n /^formData\\.([A-Za-z_][A-Za-z0-9_]*(?:\\[\\d+\\]\\.[A-Za-z_][A-Za-z0-9_]*)?) (.+)$/;\nconst MISSING_FIELDS_PREFIX = 'Form data is missing required fields: ';\n\n/**\n * The field or table column a server error path such as `note` or\n * `items[0].name` points at, so its own settings can word the error.\n */\nfunction readFillPathField(\n path: string,\n fields: readonly FormFieldDefinition[],\n): FormFieldDefinition | TableColumnDefinition | undefined {\n const [fieldKey, columnKey] = path.split(/\\[\\d+\\]\\./);\n const field = fields.find((candidate) => candidate.fieldKey === fieldKey);\n\n return columnKey === undefined\n ? field\n : field && isTableFieldDefinition(field)\n ? field.columns.find((column) => column.fieldKey === columnKey)\n : undefined;\n}\n\nfunction readFillPathErrorText(\n path: string,\n reason: string,\n fields: readonly FormFieldDefinition[],\n): string {\n const atLeast = /^must include at least (\\d+) row\\(s\\)$/.exec(reason);\n const atMost = /^must include at most (\\d+) row\\(s\\)$/.exec(reason);\n const shortest = /^must be at least (\\d+) characters$/.exec(reason);\n const longest = /^must be at most (\\d+) characters$/.exec(reason);\n\n if (reason === 'is required') {\n return '此欄為必填。';\n }\n\n if (atLeast) {\n return `至少需要 ${atLeast[1]} 列。`;\n }\n\n if (atMost) {\n return `最多 ${atMost[1]} 列。`;\n }\n\n if (shortest) {\n return `至少需要 ${shortest[1]} 個字。`;\n }\n\n if (longest) {\n return `最多 ${longest[1]} 個字。`;\n }\n\n if (reason === 'does not match the required format') {\n const field = readFillPathField(path, fields);\n const message =\n field && (field.type === 'text' || field.type === 'textarea')\n ? field.patternErrorMessage?.trim()\n : undefined;\n\n return message || '格式不正確。';\n }\n\n // The server ran out of time on the format check; the value may be fine.\n if (reason === 'could not be checked against the required format in time') {\n return '格式檢查逾時,請縮短內容後再試,或請表單設計者簡化格式。';\n }\n\n return path.includes('[') ? '此欄內容不正確。' : '此欄位內容不正確。';\n}\n\n/**\n * Turns the server's fill validation message (docs/08 §8.5, error table 2)\n * into field errors keyed the way `FormRenderer` addresses them, so a check\n * the page missed still lands on the field. `null` when any part does not\n * parse — the caller then shows the message as it is.\n */\nexport function readFillServerErrors(\n message: string,\n schema: FormDefinitionSchema,\n node: UserTaskNode,\n): Readonly<Record<string, string>> | null {\n const fillableFields = schema.fields.filter((field) =>\n readNodeFillableFieldKeys(node).has(field.fieldKey),\n );\n\n if (message.startsWith(MISSING_FIELDS_PREFIX)) {\n // Labels may hold commas, so match each fillable field's label (or key)\n // against the list rather than splitting it.\n const listed = `, ${message.slice(MISSING_FIELDS_PREFIX.length)}, `;\n const missing = fillableFields.filter((field) =>\n listed.includes(`, ${field.label || field.fieldKey}, `),\n );\n\n return missing.length > 0\n ? Object.fromEntries(\n missing.map((field) => [\n field.fieldKey,\n `${field.label || field.fieldKey}為必填欄位。`,\n ]),\n )\n : null;\n }\n\n const parts = message.split('; ').map((part) => FORM_DATA_PATH_PATTERN.exec(part));\n\n if (parts.length === 0 || parts.some((part) => part === null)) {\n return null;\n }\n\n return Object.fromEntries(\n parts.flatMap((part) =>\n part === null\n ? []\n : [[part[1], readFillPathErrorText(part[1], part[2], fillableFields)]],\n ),\n );\n}\n\nexport interface FillSummaryItem {\n readonly fieldKey: string;\n readonly label: string;\n readonly text: string;\n}\n\nexport const UNKNOWN_FILL_ORG_UNIT_TEXT = '未知組織';\n\n/**\n * The org unit ids among `values`, once each and in form order, so the caller\n * can look up their names before building the summary.\n */\nexport function readFillOrgUnitIds(\n schema: FormDefinitionSchema,\n values: WorkflowFormData,\n): readonly string[] {\n return [\n ...new Set(\n schema.fields\n .filter(isOrgUnitFieldDefinition)\n .map((field) => values[field.fieldKey])\n .filter(\n (value): value is string =>\n typeof value === 'string' && value.trim().length > 0,\n ),\n ),\n ];\n}\n\nfunction readFillValueText(\n field: FormFieldDefinition,\n value: FormFieldValue | undefined,\n memberNames: ReadonlyMap<string, string>,\n orgUnitNames: ReadonlyMap<string, string>,\n): string {\n if (isTableFieldDefinition(field)) {\n const rows = readFormTableRows(value);\n const totals = field.columns\n .filter((column) => column.type === 'number' || column.type === 'money')\n .map((column) => ({\n label: column.label || column.fieldKey,\n total: rows.reduce(\n (sum, row) =>\n typeof row[column.fieldKey] === 'number' &&\n Number.isFinite(row[column.fieldKey])\n ? sum + (row[column.fieldKey] as number)\n : sum,\n 0,\n ),\n }));\n\n return [\n `${rows.length} 列`,\n ...(rows.length > 0\n ? totals.map(\n ({ label, total }) => `${label}合計 ${total.toLocaleString('zh-TW')}`,\n )\n : []),\n ].join(',');\n }\n\n if (isFormDataValueEmpty(value)) {\n return '未填寫';\n }\n\n if (typeof value === 'boolean') {\n return value ? '是' : '否';\n }\n\n if (isOrgUnitFieldDefinition(field)) {\n // `orgUnitNames` (`useOrgUnitNames`) maps an id still being looked up to\n // a loading text; an id the lookup did not name is 「未知組織」. Never the\n // raw id.\n return typeof value === 'string'\n ? (orgUnitNames.get(value) ?? UNKNOWN_FILL_ORG_UNIT_TEXT)\n : UNKNOWN_FILL_ORG_UNIT_TEXT;\n }\n\n const items = Array.isArray(value) ? value : [value];\n const optionLabels = isFormStaticOptionFieldDefinition(field)\n ? new Map(field.options.map((option) => [option.value, option.label]))\n : field.type === 'member'\n ? memberNames\n : new Map<string, string>();\n\n return items\n .map((item) =>\n typeof item === 'string' ? (optionLabels.get(item) ?? item) : String(item),\n )\n .join('、');\n}\n\n/**\n * One line per field `node` lets its approver fill, in form order, for the\n * approve dialog: what will be sent along with the approval. A member field\n * names each member found in `memberNames` and shows the id otherwise; an org\n * unit field names its unit from `orgUnitNames` and shows 「未知組織」 otherwise.\n */\nexport function readFillSummary(\n schema: FormDefinitionSchema,\n node: UserTaskNode,\n values: WorkflowFormData,\n memberNames: ReadonlyMap<string, string> = new Map(),\n orgUnitNames: ReadonlyMap<string, string> = new Map(),\n): readonly FillSummaryItem[] {\n const fillableKeys = readNodeFillableFieldKeys(node);\n\n return schema.fields\n .filter(\n (field) =>\n fillableKeys.has(field.fieldKey) &&\n Object.prototype.hasOwnProperty.call(values, field.fieldKey),\n )\n .map((field) => ({\n fieldKey: field.fieldKey,\n label: field.label || field.fieldKey,\n text: readFillValueText(\n field,\n values[field.fieldKey],\n memberNames,\n orgUnitNames,\n ),\n }));\n}\n","import { readFormDataSourceErrorMessage } from '@rytass/bpm-core-client/form';\nimport { ATTACHMENT_NOT_BINDABLE_ERROR_CODE } from '@rytass/bpm-core-shared/form';\n\nconst ATTACHMENT_NOT_BINDABLE_MESSAGE =\n '表單中有附件無法附加到這個案件(只能附加申請人為本案上傳的檔案),請移除後重新上傳再送出。';\n\n/**\n * The message a case page shows for a failed request: a stable server code\n * translated into words, otherwise the server's own message.\n */\nexport function readErrorMessage(error: unknown): string {\n // DataSource failures arrive as stable codes so the backend never leaks\n // upstream transport detail; translate them instead of showing the raw code.\n const dataSourceMessage = readFormDataSourceErrorMessage(error);\n\n if (dataSourceMessage) {\n return dataSourceMessage;\n }\n\n const message = error instanceof Error ? error.message : null;\n\n // Names the problem, not the attachment ids the server lists.\n if (message?.includes(ATTACHMENT_NOT_BINDABLE_ERROR_CODE)) {\n return ATTACHMENT_NOT_BINDABLE_MESSAGE;\n }\n\n return message ?? '發生未知錯誤';\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/detail-
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/detail-6uw5dmTi.cjs");let t=require("react/jsx-runtime");var n={title:`案件詳情 | BPM Admin`};async function r({params:n}){let{id:r}=await n;return(0,t.jsx)(e.t,{instanceId:r})}exports.default=r,exports.metadata=n;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/compose-
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/compose-NH6dsFXD.cjs");let t=require("react/jsx-runtime"),n=require("next/server");var r={title:`建立模板(表單 + 流程) | BPM Admin`,description:`以精靈式流程一次完成 BPM 表單與簽核流程設計並發佈。`};async function i(){return await(0,n.connection)(),(0,t.jsx)(e.t,{aiAssistantAvailable:!!process.env.OPENAI_API_KEY,showAiAssistant:process.env.BPM_AI_ASSISTANT_ENABLED===`true`})}exports.default=i,exports.metadata=r;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/designer-
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/designer-Be9UI9Tg.cjs");let t=require("react/jsx-runtime");var n={title:`流程設計器 | BPM Admin`,description:`以視覺化設計器編輯 BPM 簽核流程節點、條件與發佈版本。`};async function r({params:n}){let{id:r}=await n;return(0,t.jsx)(e.t,{aiAssistantAvailable:!!process.env.OPENAI_API_KEY,showAiAssistant:process.env.BPM_AI_ASSISTANT_ENABLED===`true`,showDryRun:process.env.BPM_TEMPLATE_DRY_RUN_ENABLED!==`false`,templateId:r})}exports.default=r,exports.metadata=n;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/FormBuilderView-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/FormBuilderView-G6uRSywl.cjs");exports.FormBuilderView=e.t;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as FormBuilderView } from "../../../chunks/FormBuilderView-
|
|
1
|
+
export { t as FormBuilderView } from "../../../chunks/FormBuilderView-Djlm3y4S.js";
|
|
@@ -3,9 +3,16 @@ import { FormDataSourceValueSnapshots, FormDefinitionSchema, FormFieldDefinition
|
|
|
3
3
|
import { FormRendererValues } from '@rytass/bpm-core-client/form';
|
|
4
4
|
import { ResolvedFieldAccess } from '@rytass/bpm-core-shared';
|
|
5
5
|
import { FormDataSourceFieldState, FormRendererDataSourceContext } from './form-data-source-field.cjs';
|
|
6
|
+
import { FileUploadFieldState, FormRendererAttachment } from './file-upload-field.cjs';
|
|
6
7
|
export interface FormRendererProps {
|
|
7
8
|
readonly dataSourceContext?: FormRendererDataSourceContext;
|
|
8
9
|
readonly dataSourceInitialValues?: FormRendererValues;
|
|
10
|
+
/**
|
|
11
|
+
* Attachments the form's `file_upload` values may refer to (for example the
|
|
12
|
+
* instance's `listAttachments`). A field lists each id it holds by the name
|
|
13
|
+
* and size found here.
|
|
14
|
+
*/
|
|
15
|
+
readonly attachments?: readonly FormRendererAttachment[];
|
|
9
16
|
readonly emptyText?: string;
|
|
10
17
|
readonly errors?: Readonly<Record<string, string>>;
|
|
11
18
|
/**
|
|
@@ -25,6 +32,22 @@ export interface FormRendererProps {
|
|
|
25
32
|
readonly maxWidth?: CSSProperties['maxWidth'];
|
|
26
33
|
readonly onChange?: (values: FormRendererValues) => void;
|
|
27
34
|
readonly onDataSourceStateChange?: (fieldKey: string, state: Pick<FormDataSourceFieldState, 'hasValue' | 'invalidValues' | 'status'>) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Called when a `file_upload` field starts or settles an upload. A host
|
|
37
|
+
* that submits the form refuses to while any field reports a pending or
|
|
38
|
+
* failed upload (`readFileUploadSubmissionBlockMessage`): those files are
|
|
39
|
+
* listed but not in the value.
|
|
40
|
+
*/
|
|
41
|
+
readonly onFileUploadStateChange?: (fieldKey: string, state: FileUploadFieldState) => void;
|
|
42
|
+
/**
|
|
43
|
+
* Opens an attachment a `file_upload` field lists. Without it, only files
|
|
44
|
+
* picked in this form can be downloaded from the field.
|
|
45
|
+
*/
|
|
46
|
+
readonly onDownloadAttachment?: (attachmentId: string) => void;
|
|
47
|
+
/**
|
|
48
|
+
* Uploads a file picked in a `file_upload` field and returns the attachment
|
|
49
|
+
* id the value then holds. Without it a `file_upload` field cannot upload.
|
|
50
|
+
*/
|
|
28
51
|
readonly onUploadAttachment?: (field: FormFieldDefinition, file: File) => Promise<{
|
|
29
52
|
readonly id: string;
|
|
30
53
|
}>;
|
|
@@ -35,5 +58,5 @@ export interface FormRendererProps {
|
|
|
35
58
|
readonly uiSchema: FormUiSchema;
|
|
36
59
|
readonly value?: FormRendererValues;
|
|
37
60
|
}
|
|
38
|
-
export declare function FormRenderer({ dataSourceContext, dataSourceInitialValues, emptyText, errors, fieldAccess, fieldLabelMarkers, maxWidth, onChange, onDataSourceStateChange, onUploadAttachment, optionSnapshots, readonly, schema, singleColumn, uiSchema, value, }: FormRendererProps): ReactElement;
|
|
61
|
+
export declare function FormRenderer({ attachments, dataSourceContext, dataSourceInitialValues, emptyText, errors, fieldAccess, fieldLabelMarkers, maxWidth, onChange, onDataSourceStateChange, onDownloadAttachment, onFileUploadStateChange, onUploadAttachment, optionSnapshots, readonly, schema, singleColumn, uiSchema, value, }: FormRendererProps): ReactElement;
|
|
39
62
|
export { FormRenderer as FormRendererView };
|
|
@@ -3,9 +3,16 @@ import { FormDataSourceValueSnapshots, FormDefinitionSchema, FormFieldDefinition
|
|
|
3
3
|
import { FormRendererValues } from '@rytass/bpm-core-client/form';
|
|
4
4
|
import { ResolvedFieldAccess } from '@rytass/bpm-core-shared';
|
|
5
5
|
import { FormDataSourceFieldState, FormRendererDataSourceContext } from './form-data-source-field.js';
|
|
6
|
+
import { FileUploadFieldState, FormRendererAttachment } from './file-upload-field.js';
|
|
6
7
|
export interface FormRendererProps {
|
|
7
8
|
readonly dataSourceContext?: FormRendererDataSourceContext;
|
|
8
9
|
readonly dataSourceInitialValues?: FormRendererValues;
|
|
10
|
+
/**
|
|
11
|
+
* Attachments the form's `file_upload` values may refer to (for example the
|
|
12
|
+
* instance's `listAttachments`). A field lists each id it holds by the name
|
|
13
|
+
* and size found here.
|
|
14
|
+
*/
|
|
15
|
+
readonly attachments?: readonly FormRendererAttachment[];
|
|
9
16
|
readonly emptyText?: string;
|
|
10
17
|
readonly errors?: Readonly<Record<string, string>>;
|
|
11
18
|
/**
|
|
@@ -25,6 +32,22 @@ export interface FormRendererProps {
|
|
|
25
32
|
readonly maxWidth?: CSSProperties['maxWidth'];
|
|
26
33
|
readonly onChange?: (values: FormRendererValues) => void;
|
|
27
34
|
readonly onDataSourceStateChange?: (fieldKey: string, state: Pick<FormDataSourceFieldState, 'hasValue' | 'invalidValues' | 'status'>) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Called when a `file_upload` field starts or settles an upload. A host
|
|
37
|
+
* that submits the form refuses to while any field reports a pending or
|
|
38
|
+
* failed upload (`readFileUploadSubmissionBlockMessage`): those files are
|
|
39
|
+
* listed but not in the value.
|
|
40
|
+
*/
|
|
41
|
+
readonly onFileUploadStateChange?: (fieldKey: string, state: FileUploadFieldState) => void;
|
|
42
|
+
/**
|
|
43
|
+
* Opens an attachment a `file_upload` field lists. Without it, only files
|
|
44
|
+
* picked in this form can be downloaded from the field.
|
|
45
|
+
*/
|
|
46
|
+
readonly onDownloadAttachment?: (attachmentId: string) => void;
|
|
47
|
+
/**
|
|
48
|
+
* Uploads a file picked in a `file_upload` field and returns the attachment
|
|
49
|
+
* id the value then holds. Without it a `file_upload` field cannot upload.
|
|
50
|
+
*/
|
|
28
51
|
readonly onUploadAttachment?: (field: FormFieldDefinition, file: File) => Promise<{
|
|
29
52
|
readonly id: string;
|
|
30
53
|
}>;
|
|
@@ -35,5 +58,5 @@ export interface FormRendererProps {
|
|
|
35
58
|
readonly uiSchema: FormUiSchema;
|
|
36
59
|
readonly value?: FormRendererValues;
|
|
37
60
|
}
|
|
38
|
-
export declare function FormRenderer({ dataSourceContext, dataSourceInitialValues, emptyText, errors, fieldAccess, fieldLabelMarkers, maxWidth, onChange, onDataSourceStateChange, onUploadAttachment, optionSnapshots, readonly, schema, singleColumn, uiSchema, value, }: FormRendererProps): ReactElement;
|
|
61
|
+
export declare function FormRenderer({ attachments, dataSourceContext, dataSourceInitialValues, emptyText, errors, fieldAccess, fieldLabelMarkers, maxWidth, onChange, onDataSourceStateChange, onDownloadAttachment, onFileUploadStateChange, onUploadAttachment, optionSnapshots, readonly, schema, singleColumn, uiSchema, value, }: FormRendererProps): ReactElement;
|
|
39
62
|
export { FormRenderer as FormRendererView };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
import { FileUploadFieldDefinition, FormFieldDefinition, FormFieldValue } from '@rytass/bpm-core-shared/form';
|
|
3
|
+
/**
|
|
4
|
+
* What a `file_upload` field needs to know about an attachment it did not
|
|
5
|
+
* upload itself (a resubmitted case, a stored instance) to list it. The shape
|
|
6
|
+
* is a subset of `AttachmentRecord`, so a host passes its attachment list as is.
|
|
7
|
+
*/
|
|
8
|
+
export interface FormRendererAttachment {
|
|
9
|
+
readonly filename: string;
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly sizeBytes: number | string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Where a `file_upload` field stands, reported to the host through
|
|
15
|
+
* `FormRenderer`'s `onFileUploadStateChange`.
|
|
16
|
+
*/
|
|
17
|
+
export interface FileUploadFieldState {
|
|
18
|
+
/** Files that failed to upload. They are listed, but not in the value. */
|
|
19
|
+
readonly failedCount: number;
|
|
20
|
+
/** Files still uploading. They are listed, but not in the value yet. */
|
|
21
|
+
readonly pendingCount: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The copy to show when a submission is refused because a `file_upload` field
|
|
25
|
+
* has not settled. An upload still running is a "wait a moment"; a failed one
|
|
26
|
+
* needs the filler to retry or remove it. Returns `null` when nothing blocks.
|
|
27
|
+
*
|
|
28
|
+
* Without this check a submit made while a file is uploading sends the form
|
|
29
|
+
* without that attachment, although the field lists the file.
|
|
30
|
+
*/
|
|
31
|
+
export declare function readFileUploadSubmissionBlockMessage(states: readonly Pick<FileUploadFieldState, 'failedCount' | 'pendingCount'>[]): string | null;
|
|
32
|
+
export interface FileUploadFieldStates {
|
|
33
|
+
/** `readFileUploadSubmissionBlockMessage` over every field reported so far. */
|
|
34
|
+
readonly blockMessage: string | null;
|
|
35
|
+
/** Pass to `FormRenderer`'s `onFileUploadStateChange`. */
|
|
36
|
+
readonly onFileUploadStateChange: (fieldKey: string, state: FileUploadFieldState) => void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Collects what a form's `file_upload` fields report, for a host that has to
|
|
40
|
+
* refuse a submit while one of them is uploading or holds a failed upload.
|
|
41
|
+
*/
|
|
42
|
+
export declare function useFileUploadFieldStates(): FileUploadFieldStates;
|
|
43
|
+
export interface FileUploadFieldControlProps {
|
|
44
|
+
/** Metadata for listing attachments this control did not upload. */
|
|
45
|
+
readonly attachments?: readonly FormRendererAttachment[];
|
|
46
|
+
readonly field: FileUploadFieldDefinition;
|
|
47
|
+
/**
|
|
48
|
+
* Receives the attachment ids the field now holds. Like a controlled input,
|
|
49
|
+
* the host renders the value back: the list shows the value it is given.
|
|
50
|
+
*/
|
|
51
|
+
readonly onChange: (value: FormFieldValue | undefined) => void;
|
|
52
|
+
/** Opens an attachment the value holds. Without it, only files picked here download. */
|
|
53
|
+
readonly onDownloadAttachment?: (attachmentId: string) => void;
|
|
54
|
+
readonly onStateChange?: (state: FileUploadFieldState) => void;
|
|
55
|
+
readonly onUploadAttachment?: (field: FormFieldDefinition, file: File) => Promise<{
|
|
56
|
+
readonly id: string;
|
|
57
|
+
}>;
|
|
58
|
+
readonly readonly: boolean;
|
|
59
|
+
readonly value: FormFieldValue | undefined;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The `file_upload` control.
|
|
63
|
+
*
|
|
64
|
+
* Mezzanine's `Upload` is fully controlled: it renders `files` and resets its
|
|
65
|
+
* working list to that prop after every render, so the list is built here.
|
|
66
|
+
*
|
|
67
|
+
* What is attached is the host's value, and only that: every id it holds is
|
|
68
|
+
* listed — a file picked here by its own `File`, any other id by the name and
|
|
69
|
+
* size in `attachments` (or as an unnamed attachment without them) — so each
|
|
70
|
+
* one can be removed and counts towards `maxFiles`. Uploads still running and
|
|
71
|
+
* uploads that failed are listed too, in the order `Upload` keeps, but are not
|
|
72
|
+
* in the value; `onStateChange` reports them so the host can refuse a submit.
|
|
73
|
+
*
|
|
74
|
+
* The value emitted on a change is read off the list `Upload` hands back —
|
|
75
|
+
* the finished files in it, in order — never off this control's state. That
|
|
76
|
+
* list is `Upload`'s own working copy, which it updates the moment it emits,
|
|
77
|
+
* so it is current even when two uploads finish before the host re-renders.
|
|
78
|
+
* `Upload` calls the `onChange` it captured when a file was picked, so it is
|
|
79
|
+
* given a stable function that forwards to the latest handler.
|
|
80
|
+
*
|
|
81
|
+
* Without `onUploadAttachment` nothing can be uploaded, so the control is
|
|
82
|
+
* disabled and says so rather than listing a file no attachment stands behind.
|
|
83
|
+
*/
|
|
84
|
+
export declare function FileUploadFieldControl({ attachments, field, onChange, onDownloadAttachment, onStateChange, onUploadAttachment, readonly, value, }: FileUploadFieldControlProps): ReactElement;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
import { FileUploadFieldDefinition, FormFieldDefinition, FormFieldValue } from '@rytass/bpm-core-shared/form';
|
|
3
|
+
/**
|
|
4
|
+
* What a `file_upload` field needs to know about an attachment it did not
|
|
5
|
+
* upload itself (a resubmitted case, a stored instance) to list it. The shape
|
|
6
|
+
* is a subset of `AttachmentRecord`, so a host passes its attachment list as is.
|
|
7
|
+
*/
|
|
8
|
+
export interface FormRendererAttachment {
|
|
9
|
+
readonly filename: string;
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly sizeBytes: number | string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Where a `file_upload` field stands, reported to the host through
|
|
15
|
+
* `FormRenderer`'s `onFileUploadStateChange`.
|
|
16
|
+
*/
|
|
17
|
+
export interface FileUploadFieldState {
|
|
18
|
+
/** Files that failed to upload. They are listed, but not in the value. */
|
|
19
|
+
readonly failedCount: number;
|
|
20
|
+
/** Files still uploading. They are listed, but not in the value yet. */
|
|
21
|
+
readonly pendingCount: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The copy to show when a submission is refused because a `file_upload` field
|
|
25
|
+
* has not settled. An upload still running is a "wait a moment"; a failed one
|
|
26
|
+
* needs the filler to retry or remove it. Returns `null` when nothing blocks.
|
|
27
|
+
*
|
|
28
|
+
* Without this check a submit made while a file is uploading sends the form
|
|
29
|
+
* without that attachment, although the field lists the file.
|
|
30
|
+
*/
|
|
31
|
+
export declare function readFileUploadSubmissionBlockMessage(states: readonly Pick<FileUploadFieldState, 'failedCount' | 'pendingCount'>[]): string | null;
|
|
32
|
+
export interface FileUploadFieldStates {
|
|
33
|
+
/** `readFileUploadSubmissionBlockMessage` over every field reported so far. */
|
|
34
|
+
readonly blockMessage: string | null;
|
|
35
|
+
/** Pass to `FormRenderer`'s `onFileUploadStateChange`. */
|
|
36
|
+
readonly onFileUploadStateChange: (fieldKey: string, state: FileUploadFieldState) => void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Collects what a form's `file_upload` fields report, for a host that has to
|
|
40
|
+
* refuse a submit while one of them is uploading or holds a failed upload.
|
|
41
|
+
*/
|
|
42
|
+
export declare function useFileUploadFieldStates(): FileUploadFieldStates;
|
|
43
|
+
export interface FileUploadFieldControlProps {
|
|
44
|
+
/** Metadata for listing attachments this control did not upload. */
|
|
45
|
+
readonly attachments?: readonly FormRendererAttachment[];
|
|
46
|
+
readonly field: FileUploadFieldDefinition;
|
|
47
|
+
/**
|
|
48
|
+
* Receives the attachment ids the field now holds. Like a controlled input,
|
|
49
|
+
* the host renders the value back: the list shows the value it is given.
|
|
50
|
+
*/
|
|
51
|
+
readonly onChange: (value: FormFieldValue | undefined) => void;
|
|
52
|
+
/** Opens an attachment the value holds. Without it, only files picked here download. */
|
|
53
|
+
readonly onDownloadAttachment?: (attachmentId: string) => void;
|
|
54
|
+
readonly onStateChange?: (state: FileUploadFieldState) => void;
|
|
55
|
+
readonly onUploadAttachment?: (field: FormFieldDefinition, file: File) => Promise<{
|
|
56
|
+
readonly id: string;
|
|
57
|
+
}>;
|
|
58
|
+
readonly readonly: boolean;
|
|
59
|
+
readonly value: FormFieldValue | undefined;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The `file_upload` control.
|
|
63
|
+
*
|
|
64
|
+
* Mezzanine's `Upload` is fully controlled: it renders `files` and resets its
|
|
65
|
+
* working list to that prop after every render, so the list is built here.
|
|
66
|
+
*
|
|
67
|
+
* What is attached is the host's value, and only that: every id it holds is
|
|
68
|
+
* listed — a file picked here by its own `File`, any other id by the name and
|
|
69
|
+
* size in `attachments` (or as an unnamed attachment without them) — so each
|
|
70
|
+
* one can be removed and counts towards `maxFiles`. Uploads still running and
|
|
71
|
+
* uploads that failed are listed too, in the order `Upload` keeps, but are not
|
|
72
|
+
* in the value; `onStateChange` reports them so the host can refuse a submit.
|
|
73
|
+
*
|
|
74
|
+
* The value emitted on a change is read off the list `Upload` hands back —
|
|
75
|
+
* the finished files in it, in order — never off this control's state. That
|
|
76
|
+
* list is `Upload`'s own working copy, which it updates the moment it emits,
|
|
77
|
+
* so it is current even when two uploads finish before the host re-renders.
|
|
78
|
+
* `Upload` calls the `onChange` it captured when a file was picked, so it is
|
|
79
|
+
* given a stable function that forwards to the latest handler.
|
|
80
|
+
*
|
|
81
|
+
* Without `onUploadAttachment` nothing can be uploaded, so the control is
|
|
82
|
+
* disabled and says so rather than listing a file no attachment stands behind.
|
|
83
|
+
*/
|
|
84
|
+
export declare function FileUploadFieldControl({ attachments, field, onChange, onDownloadAttachment, onStateChange, onUploadAttachment, readonly, value, }: FileUploadFieldControlProps): ReactElement;
|