jsegd-bpm 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/jsegd-bpm.js +1 -1
- package/dist/jsegd-bpm.js.map +1 -1
- package/package.json +2 -2
- package/dist/assets/workflow-C51JnySw.css +0 -72
- package/dist/jsegd-fluig.d.ts +0 -892
- package/dist/jsegd-fluig.js +0 -2
- package/dist/jsegd-fluig.js.map +0 -1
package/dist/jsegd-bpm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsegd-bpm.js","sources":["../node_modules/jsegd/dist/jsegd.js","../app/app/worker-manager/interfaces/ISearchParams.ts","../app/app/worker-manager/worker-manager.ts","../app/app/attachment/attachment.constants.ts","../app/app/process-context/index.ts","../app/app/attachment/workflow-context.ts","../app/app/attachment/attachment.utils.ts","../app/app/attachment/attachment.version.ts","../app/app/attachment/attachmentPickerModal.ts","../app/app/attachment/attach.ts","../app/app/attachment/drag-drop-name-modal.ts","../app/app/attachment/attachment-metadata.ts","../app/app/attachment/attachmentsTable.ts","../app/app/attachment/attachButton.ts","../app/attachment/assets/styles.css","../app/app/events/beforeSendValidate.ts","../app/app/workflow-view/hooks-registry.ts","../app/app/workflow-view/overrides/send-request.ts","../app/app/workflow-view/workflow-view-patcher.ts","../app/app/form-repository/nameUtils.ts","../app/app/form-repository/BpmFormRepository.ts","../app/app/form-repository/MockFormRepository.ts","../app/app/form-repository/loadFields.ts","../app/app/workflow/define-config.ts","../app/app/workflow/history-parser.ts","../app/app/workflow/screen-context.ts","../app/app/workflow/screen-resolver.ts","../app/app/alpine/register-stores.ts"],"sourcesContent":["let e=class{__destroy_into_raw(){const e=this.__wbg_ptr;return this.__wbg_ptr=0,r.unregister(this),e}free(){const e=this.__destroy_into_raw();l.__wbg_validate_free(e,0)}static is_valid_cep(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_;return 0!==l.validate_is_valid_cep(t,r)}static is_valid_cnpj(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_;return 0!==l.validate_is_valid_cnpj(t,r)}static is_valid_cpf(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_;return 0!==l.validate_is_valid_cpf(t,r)}static is_valid_email(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_;return 0!==l.validate_is_valid_email(t,r)}static is_valid_evp(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_;return 0!==l.validate_is_valid_evp(t,r)}static is_valid_mobile(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_;return 0!==l.validate_is_valid_mobile(t,r)}};Symbol.dispose&&(e.prototype[Symbol.dispose]=e.prototype.free);let t=class{__destroy_into_raw(){const e=this.__wbg_ptr;return this.__wbg_ptr=0,n.unregister(this),e}free(){const e=this.__destroy_into_raw();l.__wbg_writtenout_free(e,0)}static format_currency(e,t){let r,n;try{const s=l.writtenout_format_currency(e,t);var i=s[0],a=s[1];if(s[3])throw i=0,a=0,takeFromExternrefTable0(s[2]);return r=i,n=a,getStringFromWasm0(i,a)}finally{l.__wbindgen_free(r,n,1)}}static format_date(e){let t,r;try{const a=l.writtenout_format_date(e);var n=a[0],i=a[1];if(a[3])throw n=0,i=0,takeFromExternrefTable0(a[2]);return t=n,r=i,getStringFromWasm0(n,i)}finally{l.__wbindgen_free(t,r,1)}}static format_deadline(e,t){let r,n;try{const s=l.writtenout_format_deadline(e,t);var i=s[0],a=s[1];if(s[3])throw i=0,a=0,takeFromExternrefTable0(s[2]);return r=i,n=a,getStringFromWasm0(i,a)}finally{l.__wbindgen_free(r,n,1)}}static format_number(e){let t,r;try{const a=l.writtenout_format_number(e);var n=a[0],i=a[1];if(a[3])throw n=0,i=0,takeFromExternrefTable0(a[2]);return t=n,r=i,getStringFromWasm0(n,i)}finally{l.__wbindgen_free(t,r,1)}}};Symbol.dispose&&(t.prototype[Symbol.dispose]=t.prototype.free);const r=\"undefined\"==typeof FinalizationRegistry?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry((e=>l.__wbg_validate_free(e>>>0,1))),n=\"undefined\"==typeof FinalizationRegistry?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry((e=>l.__wbg_writtenout_free(e>>>0,1)));function getStringFromWasm0(e,t){return function(e,t){o+=t,o>=s&&(a=new TextDecoder(\"utf-8\",{ignoreBOM:!0,fatal:!0}),a.decode(),o=t);return a.decode(getUint8ArrayMemory0().subarray(e,e+t))}(e>>>=0,t)}let i=null;function getUint8ArrayMemory0(){return null!==i&&0!==i.byteLength||(i=new Uint8Array(l.memory.buffer)),i}function passStringToWasm0(e,t,r){if(void 0===r){const r=c.encode(e),n=t(r.length,1)>>>0;return getUint8ArrayMemory0().subarray(n,n+r.length).set(r),_=r.length,n}let n=e.length,i=t(n,1)>>>0;const a=getUint8ArrayMemory0();let s=0;for(;s<n;s++){const t=e.charCodeAt(s);if(t>127)break;a[i+s]=t}if(s!==n){0!==s&&(e=e.slice(s)),i=r(i,n,n=s+3*e.length,1)>>>0;const t=getUint8ArrayMemory0().subarray(i+s,i+n);s+=c.encodeInto(e,t).written,i=r(i,n,s,1)>>>0}return _=s,i}function takeFromExternrefTable0(e){const t=l.__wbindgen_externrefs.get(e);return l.__externref_table_dealloc(e),t}let a=new TextDecoder(\"utf-8\",{ignoreBOM:!0,fatal:!0});a.decode();const s=2146435072;let o=0;const c=new TextEncoder;\"encodeInto\"in c||(c.encodeInto=function(e,t){const r=c.encode(e);return t.set(r),{read:e.length,written:r.length}});let l,_=0;class LocalCache{static instance;dbPromise=null;isInitialized=!1;cacheExpirationMs;storeName;constructor(){}static getInstance(){return LocalCache.instance||(LocalCache.instance=new LocalCache),LocalCache.instance}initialize(e){if(this.isInitialized)throw new Error(`LocalCache already initialized with storeName=\"${this.storeName}\". Create a new instance or reuse the existing one.`);this.cacheExpirationMs=e.cacheExpirationMs,this.storeName=e.storeName,this.isInitialized=!0}ensureInitialized(){if(!this.isInitialized)throw new Error(\"LocalCache not initialized. Call getInstance().initialize({ storeName, cacheExpirationMs }) first.\")}promisifyRequest(e){return new Promise(((t,r)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>r(e.error)}))}async openDatabase(){if(this.ensureInitialized(),this.dbPromise)return this.dbPromise;const e=`jsegd_cache_${this.storeName}`;return this.dbPromise=new Promise(((t,r)=>{const n=indexedDB.open(e,1);n.onupgradeneeded=()=>{const e=n.result;e.objectStoreNames.contains(this.storeName)||e.createObjectStore(this.storeName,{keyPath:\"key\"})},n.onsuccess=()=>t(n.result),n.onerror=()=>{r(n.error)}})),this.dbPromise}async get(e){this.ensureInitialized();try{const t=await this.openDatabase(),r=t.transaction(this.storeName,\"readonly\").objectStore(this.storeName),n=await this.promisifyRequest(r.get(e));return n?Date.now()-n.timestamp>this.cacheExpirationMs?(await this.remove(e).catch((()=>{})),null):n.data:null}catch(e){return null}}async set(e,t){this.ensureInitialized();try{const r=(await this.openDatabase()).transaction(this.storeName,\"readwrite\"),n=r.objectStore(this.storeName),i={key:e,timestamp:Date.now(),data:t};await this.promisifyRequest(n.put(i)),await new Promise(((e,t)=>{r.oncomplete=()=>e(),r.onerror=()=>t(r.error)}))}catch(e){throw e}}async remove(e){this.ensureInitialized();try{const t=(await this.openDatabase()).transaction(this.storeName,\"readwrite\"),r=t.objectStore(this.storeName);await this.promisifyRequest(r.delete(e)),await new Promise(((e,r)=>{t.oncomplete=()=>e(),t.onerror=()=>r(t.error)}))}catch(e){throw e}}async clear(){this.ensureInitialized();try{const e=(await this.openDatabase()).transaction(this.storeName,\"readwrite\"),t=e.objectStore(this.storeName);await this.promisifyRequest(t.clear()),await new Promise(((t,r)=>{e.oncomplete=()=>t(),e.onerror=()=>r(e.error)}))}catch(e){throw e}}async purgeExpired(){this.ensureInitialized();try{const e=(await this.openDatabase()).transaction(this.storeName,\"readwrite\"),t=e.objectStore(this.storeName),r=await this.promisifyRequest(t.getAll()),n=Date.now(),i=r.filter((e=>n-e.timestamp>this.cacheExpirationMs));for(const e of i)await this.promisifyRequest(t.delete(e.key));return await new Promise(((t,r)=>{e.oncomplete=()=>t(),e.onerror=()=>r(e.error)})),i.length}catch(e){return 0}}}class EventBus{static instance;events={};constructor(){}static getInstance(){return EventBus.instance||(EventBus.instance=new EventBus),EventBus.instance}on(e,t){return this.events[e]||(this.events[e]=[]),this.events[e].push(t),()=>this.off(e,t)}once(e,t){const wrapper=(...r)=>{this.off(e,wrapper),t(...r)};return this.on(e,wrapper)}off(e,t){this.events[e]&&(this.events[e]=this.events[e].filter((e=>e!==t)),0===this.events[e].length&&delete this.events[e])}emit(e,...t){if(!this.events[e])return;const r=[...this.events[e]];for(const e of r)try{e(...t)}catch{}}clear(e){void 0!==e?delete this.events[e]:this.events={}}}var u,d;!function(e){e[e.Second=0]=\"Second\",e[e.Minute=1]=\"Minute\",e[e.Hour=2]=\"Hour\",e[e.Day=3]=\"Day\",e[e.Week=4]=\"Week\",e[e.Month=5]=\"Month\",e[e.Bimonth=6]=\"Bimonth\",e[e.Quarter=7]=\"Quarter\",e[e.Semester=8]=\"Semester\",e[e.Year=9]=\"Year\"}(u||(u={})),function(e){e[e.BRL=0]=\"BRL\",e[e.USD=1]=\"USD\",e[e.EUR=2]=\"EUR\",e[e.JPY=3]=\"JPY\",e[e.GBP=4]=\"GBP\",e[e.CNY=5]=\"CNY\"}(d||(d={}));class WrittenOut{static formatDeadline(e,r){return t.format_deadline(e,r)}static formatNumber(e){return t.format_number(e)}static formatCurrency(e,r){return t.format_currency(e,r)}static formatDate(e){return t.format_date(BigInt(e.getTime()))}}const m={[d.BRL]:{locale:\"pt-BR\",currency:\"BRL\"},[d.USD]:{locale:\"en-US\",currency:\"USD\"},[d.EUR]:{locale:\"de-DE\",currency:\"EUR\"},[d.JPY]:{locale:\"ja-JP\",currency:\"JPY\"},[d.GBP]:{locale:\"en-GB\",currency:\"GBP\"},[d.CNY]:{locale:\"zh-CN\",currency:\"CNY\"}};class Util{static async parseNumber(e){return function(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_,n=l.parse_number(t,r);if(n[2])throw takeFromExternrefTable0(n[1]);return n[0]}(e)}static convertToMonetaryValue(e,t=d.BRL){const{locale:r,currency:n}=m[t];return e.toLocaleString(r,{minimumFractionDigits:2,maximumFractionDigits:2,style:\"currency\",currency:n})}static async removeAccents(e){return function(e){let t,r;try{const n=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),i=_,a=l.remove_accents(n,i);return t=a[0],r=a[1],getStringFromWasm0(a[0],a[1])}finally{l.__wbindgen_free(t,r,1)}}(e)}static async abbreviate(e){return function(e){let t,r;try{const n=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),i=_,a=l.abbreviate(n,i);return t=a[0],r=a[1],getStringFromWasm0(a[0],a[1])}finally{l.__wbindgen_free(t,r,1)}}(e)}}var f;!function(e){e[e.DOCUMENT=0]=\"DOCUMENT\",e[e.EMAIL=1]=\"EMAIL\",e[e.MOBILE=2]=\"MOBILE\",e[e.EVP=3]=\"EVP\"}(f||(f={}));class Validate{static async isValidEmail(t){return e.is_valid_email(t)}static async isValidMobile(t){return e.is_valid_mobile(t)}static async isValidCNPJ(t){return e.is_valid_cnpj(t)}static async isValidCPF(t){return e.is_valid_cpf(t)}static async isValidCEP(t){return e.is_valid_cep(t)}static async isValidEVP(t){return e.is_valid_evp(t)}static async isValidPix(t,r){switch(t){case f.DOCUMENT:if(11===r.length){if(!e.is_valid_cpf(r))throw new Error(\"O CPF informado é inválido\");return!0}if(14===r.length){if(!e.is_valid_cnpj(r))throw new Error(\"O CNPJ informado é inválido\");return!0}throw new Error(\"O documento informado deve conter 11 ou 14 dígitos\");case f.MOBILE:if(!e.is_valid_mobile(r))throw new Error(\"Chave PIX do tipo Número de Telefone possivelmente é inválida\");return!0;case f.EMAIL:if(!e.is_valid_email(r))throw new Error(\"Chave PIX do tipo E-mail possivelmente é inválida\");return!0;case f.EVP:if(!e.is_valid_evp(r))throw new Error(\"Chave PIX do tipo Chave aleatória possivelmente é inválida\");return!0;default:throw new Error(\"Informe o tipo da chave PIX\")}}}await async function(e){if(void 0!==l)return l;void 0!==e&&(Object.getPrototypeOf(e)===Object.prototype?({module_or_path:e}=e):console.warn(\"using deprecated parameters for the initialization function; pass a single object instead\")),void 0===e&&(e=new URL(\"jsegd_bg.wasm\",import.meta.url));const t={__proto__:null,\"./jsegd_bg.js\":{__proto__:null,__wbg_Error_960c155d3d49e4c2:function(e,t){return Error(getStringFromWasm0(e,t))},__wbg___wbindgen_throw_6b64449b9b9ed33c:function(e,t){throw new Error(getStringFromWasm0(e,t))},__wbindgen_cast_0000000000000001:function(e,t){return getStringFromWasm0(e,t)},__wbindgen_init_externref_table:function(){const e=l.__wbindgen_externrefs,t=e.grow(4);e.set(0,void 0),e.set(t+0,void 0),e.set(t+1,null),e.set(t+2,!0),e.set(t+3,!1)}}};(\"string\"==typeof e||\"function\"==typeof Request&&e instanceof Request||\"function\"==typeof URL&&e instanceof URL)&&(e=fetch(e));const{instance:r,module:n}=await async function(e,t){if(\"function\"==typeof Response&&e instanceof Response){if(\"function\"==typeof WebAssembly.instantiateStreaming)try{return await WebAssembly.instantiateStreaming(e,t)}catch(t){if(!e.ok||!function(e){switch(e){case\"basic\":case\"cors\":case\"default\":return!0}return!1}(e.type)||\"application/wasm\"===e.headers.get(\"Content-Type\"))throw t;console.warn(\"`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\\n\",t)}const r=await e.arrayBuffer();return await WebAssembly.instantiate(r,t)}{const r=await WebAssembly.instantiate(e,t);return r instanceof WebAssembly.Instance?{instance:r,module:e}:r}}(await e,t);return function(e){return l=e.exports,i=null,l.__wbindgen_start(),l}(r)}();export{d as Currency,u as DeadlineUnit,EventBus,LocalCache,f as TypePix,Util,Validate,WrittenOut};\n//# sourceMappingURL=jsegd.js.map\n","export enum ConstraintsType {\r\n MUST = 'MUST',\r\n MUST_NOT = 'MUST_NOT',\r\n SHOULD = 'SHOULD',\r\n}\r\n\r\nexport interface SearchParams {\r\n /** Código do dataset — obrigatório. */\r\n datasetId: string\r\n /** Campos a retornar; omitir para retornar todos os campos. */\r\n field?: string[]\r\n /** Registros a ignorar — usado para paginação (padrão: 0). */\r\n offset?: number\r\n /** Máximo de registros a retornar (padrão: 300; 0 = todos). */\r\n limit?: number\r\n /** Nome do campo para ordenação, opcionalmente sufixado com _ASC ou _DESC. */\r\n orderby?: string\r\n constraintsField?: string[]\r\n constraintsInitialValue?: string[]\r\n constraintsFinalValue?: string[]\r\n constraintsType?: ConstraintsType[]\r\n /** Quando verdadeiro, o curinga % é aceito no valor inicial/final correspondente. */\r\n constraintsLikeSearch?: boolean[]\r\n}\r\n","import type { ICache } from 'jsegd'\r\nimport { LocalCache } from 'jsegd'\r\nimport type { DatasetResponse } from './interfaces/IDataset'\r\nimport type { SearchParams, ConstraintsType } from './interfaces/ISearchParams'\r\nimport type { WorkerAbort, WorkerRequest, WorkerResponse } from './interfaces/IWorkerMessage'\r\nimport type { CancelablePromise, PendingRequest, Task, WorkerMeta } from './interfaces/IWorkerManager'\r\n\r\nexport type CacheOptions = { storeName: string; cacheExpirationMs: number }\r\n\r\nexport interface WorkerManagerOptions {\r\n poolSize?: number\r\n /** Injeta uma instância existente de ICache (compartilhada entre componentes). */\r\n cache?: ICache\r\n /** Cria um LocalCache interno com as opções fornecidas. */\r\n cacheOptions?: CacheOptions\r\n // Se nenhum dos dois for informado, o gerenciador opera sem cache.\r\n}\r\n\r\n/**\r\n * Gerencia um pool de Web Workers para executar consultas à API de Datasets do Fluig fora da thread principal.\r\n * Suporta deduplicacão de requisições, cache em IndexedDB e cancelamento HTTP real via AbortController.\r\n *\r\n * @example\r\n * ```typescript\r\n * import { WorkerManager, ConstraintsType } from 'jsegd-bpm'\r\n *\r\n * const manager = new WorkerManager({\r\n * poolSize: 4,\r\n * cacheOptions: { storeName: 'datasetCache', cacheExpirationMs: 24 * 60 * 60 * 1000 }\r\n * })\r\n *\r\n * const { promise, cancel } = manager.query('https://tenant.fluig.com', {\r\n * datasetId: 'dsColaboradores',\r\n * field: ['nome', 'email'],\r\n * constraintsField: ['ativo'],\r\n * constraintsInitialValue: ['true'],\r\n * constraintsType: [ConstraintsType.MUST],\r\n * })\r\n *\r\n * // Cancelar se necessário:\r\n * // cancel()\r\n *\r\n * const result = await promise\r\n * console.log(result.columns) // ['nome', 'email']\r\n * console.log(result.values) // [{ nome: 'João', email: 'joao@co.com' }, ...]\r\n * ```\r\n */\r\nexport class WorkerManager {\r\n private pool: Worker[] = []\r\n private workerMeta = new Map<Worker, WorkerMeta>()\r\n private taskQueue: Task[] = []\r\n private inFlight: Map<string, PendingRequest> = new Map()\r\n private cache: ICache | null = null\r\n private nextRequestId = 0\r\n\r\n constructor(options: WorkerManagerOptions = {}) {\r\n const poolSize = options.poolSize ?? 4\r\n\r\n if (options.cache) {\r\n this.cache = options.cache\r\n } else if (options.cacheOptions) {\r\n const lc = LocalCache.getInstance()\r\n lc.initialize(options.cacheOptions)\r\n this.cache = lc\r\n }\r\n\r\n for (let i = 0; i < poolSize; i++) {\r\n const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' })\r\n worker.onmessage = (e) => this.handleResponse(e.data as WorkerResponse, worker)\r\n this.workerMeta.set(worker, { busy: false })\r\n this.pool.push(worker)\r\n }\r\n }\r\n\r\n /**\r\n * Consulta a API de Datasets do Fluig. Retorna uma CancelablePromise.\r\n * Chame `cancel()` para abortar a requisição HTTP e liberar o worker imediatamente.\r\n */\r\n public query(baseUrl: string, params: SearchParams): CancelablePromise<DatasetResponse> {\r\n const url = this.buildUrl(baseUrl, params)\r\n const key = url\r\n\r\n const wrapperPromise = this.cache\r\n ? this.cache.get<DatasetResponse>(key).then((cached) => {\r\n if (cached) return cached\r\n return this.deduplicateOrEnqueue(key, url)\r\n })\r\n : this.deduplicateOrEnqueue(key, url)\r\n\r\n let canceller: () => void = () => {}\r\n const promise = new Promise<DatasetResponse>((res, rej) => {\r\n canceller = () => this.abortRequest(key, rej)\r\n wrapperPromise.then(res, rej)\r\n })\r\n\r\n return { promise, cancel: canceller }\r\n }\r\n\r\n /**\r\n * Encerra todos os workers do pool. Chame quando o gerenciador não for mais necessário\r\n * para evitar vazamentos de memória e workers zumbis.\r\n */\r\n public terminate(): void {\r\n for (const worker of this.pool) {\r\n worker.terminate()\r\n }\r\n this.pool = []\r\n this.workerMeta.clear()\r\n this.taskQueue = []\r\n this.inFlight.clear()\r\n }\r\n\r\n private deduplicateOrEnqueue(key: string, url: string): Promise<DatasetResponse> {\r\n if (this.inFlight.has(key)) {\r\n return this.inFlight.get(key)!.promise\r\n }\r\n return this.enqueueRequest(key, { type: 'request', requestId: ++this.nextRequestId, requestUrl: url })\r\n }\r\n\r\n private enqueueRequest(key: string, payload: WorkerRequest): Promise<any> {\r\n let resolveFn!: (v: any) => void\r\n let rejectFn!: (e: any) => void\r\n\r\n const promise = new Promise<any>((resolve, reject) => {\r\n resolveFn = resolve\r\n rejectFn = reject\r\n })\r\n\r\n const pending: PendingRequest = { promise, resolve: resolveFn, reject: rejectFn }\r\n this.inFlight.set(key, pending)\r\n this.taskQueue.push({ key, payload, pending })\r\n this.scheduleNext()\r\n return promise\r\n }\r\n\r\n private scheduleNext(): void {\r\n for (const worker of this.pool) {\r\n if (this.taskQueue.length === 0) break\r\n const meta = this.workerMeta.get(worker)!\r\n if (!meta.busy) {\r\n const task = this.taskQueue.shift()!\r\n meta.busy = true\r\n meta.currentKey = task.key\r\n meta.currentRequestId = task.payload.requestId\r\n worker.postMessage(task.payload)\r\n }\r\n }\r\n }\r\n\r\n private abortRequest(key: string, externalReject: (e: any) => void): void {\r\n externalReject(new Error('Request cancelled'))\r\n\r\n const queueIndex = this.taskQueue.findIndex((t) => t.key === key)\r\n if (queueIndex !== -1) {\r\n const [task] = this.taskQueue.splice(queueIndex, 1)\r\n this.inFlight.delete(key)\r\n task.pending.reject(new Error('Request cancelled'))\r\n return\r\n }\r\n\r\n // Already dispatched to a worker — send abort message\r\n for (const [worker, meta] of this.workerMeta) {\r\n if (meta.currentKey === key) {\r\n worker.postMessage({ type: 'abort', requestId: meta.currentRequestId! } satisfies WorkerAbort)\r\n break\r\n }\r\n }\r\n }\r\n\r\n private handleResponse(response: WorkerResponse, worker: Worker): void {\r\n const meta = this.workerMeta.get(worker)!\r\n const key = meta.currentKey!\r\n\r\n meta.busy = false\r\n delete meta.currentKey\r\n delete meta.currentRequestId\r\n\r\n const pending = this.inFlight.get(key)\r\n this.inFlight.delete(key)\r\n\r\n if (pending) {\r\n if (response.aborted) {\r\n pending.reject(new Error('Request cancelled'))\r\n } else if (response.success) {\r\n const data = response.data as DatasetResponse\r\n if (this.cache) {\r\n this.cache.set(key, data).catch(() => {})\r\n }\r\n pending.resolve(data)\r\n } else {\r\n pending.reject(new Error(response.error))\r\n }\r\n }\r\n\r\n this.scheduleNext()\r\n }\r\n\r\n private buildUrl(baseUrl: string, params: SearchParams): string {\r\n const url = new URL(`${baseUrl}/dataset/api/v2/dataset-handle/search`)\r\n url.searchParams.set('datasetId', params.datasetId)\r\n params.field?.forEach((f) => url.searchParams.append('field', f))\r\n if (params.offset !== undefined) url.searchParams.set('offset', String(params.offset))\r\n if (params.limit !== undefined) url.searchParams.set('limit', String(params.limit))\r\n if (params.orderby) url.searchParams.set('orderby', params.orderby)\r\n params.constraintsField?.forEach((f) => url.searchParams.append('constraintsField', f))\r\n params.constraintsInitialValue?.forEach((v) => url.searchParams.append('constraintsInitialValue', v))\r\n params.constraintsFinalValue?.forEach((v) => url.searchParams.append('constraintsFinalValue', v))\r\n params.constraintsType?.forEach((t) => url.searchParams.append('constraintsType', t))\r\n params.constraintsLikeSearch?.forEach((b) => url.searchParams.append('constraintsLikeSearch', String(b)))\r\n return url.toString()\r\n }\r\n}\r\n","/** Marcador de anexo genérico (sem descrição prévia definida no componente) */\r\nexport const GENERIC_ATTACHMENT_MARKER = '_Z_'\r\n\r\n/** Versão padrão exibida para documentos ainda não publicados no ECM */\r\nexport const UNPUBLISHED_VERSION_DISPLAY = 1000\r\n\r\n/** Descrição do arquivo de metadados interno gerenciado pela biblioteca */\r\nexport const METADATA_ATTACHMENT_NAME = '_jsegd_metadata'\r\n","/**\r\n * Fronteira única de acesso ao objeto `parent` do Fluig dentro do módulo `bpm/`.\r\n *\r\n * Isola todos os consumidores da dependência direta sobre o frame pai,\r\n * permitindo mock completo em testes unitários.\r\n * Cada função de fábrica valida apenas o objeto `parent.*` de que depende.\r\n *\r\n * **Regra de fronteira:** este é o único arquivo em `bpm/` autorizado a referenciar\r\n * `parent.WKFViewAttachment`, `parent.ECM`, `parent.Mustache`, `parent.$` e\r\n * `parent.document` (exceção: `workflow-view-patcher.ts` acessa `parent.ECM_WKFView`\r\n * por responsabilidade própria de patching).\r\n */\r\n\r\n/** Operações sobre anexos via `WKFViewAttachment` */\r\nexport interface IAttachmentOps {\r\n /**\r\n * Retorna todos os anexos do processo atual.\r\n */\r\n getAllAttachments(): Attachment[]\r\n\r\n /**\r\n * Abre o visualizador de documento do processo.\r\n */\r\n openAttachmentView(colleagueId: string, documentId: number, version: number): void\r\n\r\n /**\r\n * Inicia o download de anexos pelos índices na tabela.\r\n */\r\n downloadAttach(indexes: number[]): void\r\n\r\n /**\r\n * Exibe o diálogo de confirmação de remoção do processo.\r\n */\r\n confirmRemoveAttach(indexes: number[]): void\r\n\r\n /**\r\n * Abre o painel de edição de conteúdo/metadados para o anexo.\r\n */\r\n editAttach(row: { [key: string]: string }, index: number): void\r\n\r\n /**\r\n * Remove um anexo publicado diretamente, sem diálogo de confirmação e sem toast.\r\n * Uso exclusivo para remoção de arquivos internos da biblioteca (ex: `_jsegd_metadata`).\r\n */\r\n deleteAttachmentSilent(attachment: Attachment): void\r\n}\r\n\r\n/** Callbacks fornecidos por `Attach` para substituição dos handlers do jQuery File Upload */\r\nexport interface FileUploadCallbacks {\r\n /**\r\n * Chamado após todas as validações internas passarem em `fileuploadadd`.\r\n * Retornar `false` cancela o upload.\r\n */\r\n onFileAdd(event: unknown, data: unknown): boolean | void\r\n /**\r\n * Chamado quando o arquivo é publicado com sucesso via `startPublishingDocument`.\r\n * `item.description` contém o nome/descrição final do arquivo no ECM.\r\n */\r\n onFileDone(event: unknown, data: unknown, item: { description?: string; name?: string }): void\r\n /** Chamado quando o jQuery File Upload falha a nível de rede */\r\n onFileFail(event: unknown, data: unknown): void\r\n}\r\n\r\n/** Operações de substituição dos handlers de upload do Fluig */\r\nexport interface IUploadHandlerOps {\r\n /**\r\n * Substitui `WKFViewAttachment.successRemoveAttachment` pela função fornecida.\r\n * Necessário para que `jsegd:upload:reset` dispare no `window` do iframe.\r\n */\r\n overrideSuccessRemoveAttachment(handler: (data: unknown[]) => void): void\r\n\r\n /**\r\n * Vincula handlers TypeScript ao `#ecm_navigation_fileupload` (jQuery File Upload).\r\n * Substitui os handlers nativos do Fluig; realiza toda a validação ECM internamente\r\n * e delega os pontos de extensão aos callbacks fornecidos.\r\n */\r\n bindFileUploadHandlers(callbacks: FileUploadCallbacks): void\r\n}\r\n\r\n/** Dados de processo via `ECM` */\r\nexport interface IProcessInfo {\r\n /**\r\n * Retorna o vetor de letras de permissão do usuário no processo.\r\n */\r\n getUserPermissions(): string[]\r\n\r\n /**\r\n * Retorna o `processInstanceId` do processo em execução (0 quando não persistido).\r\n */\r\n getProcessInstanceId(): number\r\n\r\n /**\r\n * Retorna o identificador do responsável pela tarefa atual.\r\n */\r\n getTaskUserId(): string\r\n\r\n /**\r\n * Retorna o número de sequência da movimentação atual do processo.\r\n */\r\n getWorkflowSequence(): number\r\n\r\n /**\r\n * Retorna todas as linhas da tabela de anexos do ECM.\r\n */\r\n getTableData(): { [key: string]: string }[]\r\n\r\n /**\r\n * Retorna a linha de índice `index` da tabela de anexos do ECM.\r\n */\r\n getTableRow(index: number): { [key: string]: string }\r\n}\r\n\r\n/** Utilitários do frame pai (document, Mustache, jQuery) */\r\nexport interface IParentEnv {\r\n /**\r\n * Documento DOM do frame pai (janela do processo).\r\n * Usado para manipulação direta do DOM do processo.\r\n */\r\n parentDocument: Document\r\n\r\n /**\r\n * Renderiza um template Mustache com o contexto fornecido.\r\n *\r\n * @throws {Error} quando `Mustache` não está disponível no contexto do processo\r\n */\r\n renderTemplate(template: string, data: object): string\r\n\r\n /**\r\n * Remove listeners de arrastar-e-soltar legados do processo\r\n * para evitar upload acidental ao arrastar arquivos na página.\r\n */\r\n removeDragListeners(): void\r\n}\r\n\r\n/**\r\n * Retorna o adapter de operações sobre anexos via `WKFViewAttachment`.\r\n *\r\n * @throws {Error} quando `WKFViewAttachment` não está disponível\r\n */\r\nexport function getAttachmentOps(): IAttachmentOps {\r\n if (!parent.WKFViewAttachment) {\r\n throw new Error('WKFViewAttachment não disponível no contexto do processo')\r\n }\r\n\r\n const { WKFViewAttachment } = parent\r\n\r\n return {\r\n getAllAttachments(): Attachment[] {\r\n return WKFViewAttachment.getAllAttachments()\r\n },\r\n\r\n openAttachmentView(colleagueId: string, documentId: number, version: number): void {\r\n WKFViewAttachment.openAttachmentView(colleagueId, documentId, version)\r\n },\r\n\r\n downloadAttach(indexes: number[]): void {\r\n WKFViewAttachment.downloadAttach(indexes)\r\n },\r\n\r\n confirmRemoveAttach(indexes: number[]): void {\r\n WKFViewAttachment.confirmRemoveAttach(indexes)\r\n },\r\n\r\n editAttach(row: { [key: string]: string }, index: number): void {\r\n // attachEdit não está nos tipos públicos de WKFViewAttachment\r\n ;(WKFViewAttachment as any).attachEdit(row, index)\r\n },\r\n\r\n deleteAttachmentSilent(attachment: Attachment): void {\r\n ;(WKFViewAttachment as any).deleteAttachments([attachment])\r\n },\r\n }\r\n}\r\n\r\n/**\r\n * Retorna o adapter de dados de processo via `ECM`.\r\n *\r\n * @throws {Error} quando `ECM` não está disponível\r\n */\r\nexport function getProcessInfo(): IProcessInfo {\r\n if (!parent.ECM) {\r\n throw new Error('ECM não disponível no contexto do processo')\r\n }\r\n\r\n const { ECM } = parent\r\n\r\n return {\r\n getUserPermissions(): string[] {\r\n return (ECM.workflowView as any).userPermissions ?? []\r\n },\r\n\r\n getProcessInstanceId(): number {\r\n return ECM.workflowView.processDefinition.processInstanceId\r\n },\r\n\r\n getTaskUserId(): string {\r\n return ECM.workflowView.processDefinition.taskUserId\r\n },\r\n\r\n getWorkflowSequence(): number {\r\n return ECM.workflowView.sequence\r\n },\r\n\r\n getTableData(): { [key: string]: string }[] {\r\n return ECM.attachmentTable.getData()\r\n },\r\n\r\n getTableRow(index: number): { [key: string]: string } {\r\n return ECM.attachmentTable.getRow(index)\r\n },\r\n }\r\n}\r\n\r\n/**\r\n * Retorna o adapter de utilitários do frame pai.\r\n * `Mustache` e `$` são validados internamente no método que os utiliza.\r\n */\r\nexport function getParentEnv(): IParentEnv {\r\n return {\r\n parentDocument: parent.document,\r\n\r\n renderTemplate(template: string, data: object): string {\r\n const mustache = (parent as any).Mustache\r\n if (!mustache) {\r\n throw new Error('Mustache não disponível no contexto do processo')\r\n }\r\n return mustache.render(template, data)\r\n },\r\n\r\n removeDragListeners(): void {\r\n const $ = (parent as any).$\r\n if (typeof $ === 'function') {\r\n $('#ecm_wkfview').off('drop dragover dragenter')\r\n $('#ecm-workflowView-attachment').off('drop dragover dragenter')\r\n }\r\n },\r\n }\r\n}\r\n\r\n/**\r\n * Retorna o adapter de substituição dos handlers de upload do Fluig.\r\n * Toda referência a `parent.$` e `parent.ECM` permanece neste módulo.\r\n */\r\nexport function getUploadHandlerOps(): IUploadHandlerOps {\r\n return {\r\n overrideSuccessRemoveAttachment(handler: (data: unknown[]) => void): void {\r\n ;(parent as any).WKFViewAttachment.successRemoveAttachment = handler.bind((parent as any).WKFViewAttachment)\r\n },\r\n\r\n bindFileUploadHandlers(callbacks: FileUploadCallbacks): void {\r\n const $ = (parent as any).$\r\n if (typeof $ !== 'function') return\r\n const getECM = () => (parent as any).ECM\r\n\r\n $('#ecm_navigation_fileupload')\r\n .off('fileuploadadd')\r\n .on('fileuploadadd', (e: any, data: any) => {\r\n const ECM = getECM()\r\n // Bloqueia se outro modal de upload estiver aberto\r\n if (ECM?.WKFViewAttachment?.validateUpload?.()) return false\r\n // Verifica permissão de publicação\r\n if (!ECM?.workflowView?.userPermissions?.includes('P')) {\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:error'))\r\n FLUIGC.toast({\r\n message: 'Usuário não possui permissão para publicar anexos',\r\n type: 'warning',\r\n })\r\n return false\r\n }\r\n // Remove duplicatas no mesmo lote\r\n const duplicated: number[] = []\r\n ;(data.files as File[]).filter((item, index, arr) => {\r\n if (arr.indexOf(item) !== index) duplicated.push(index)\r\n })\r\n duplicated\r\n .sort((a, b) => b - a)\r\n .forEach((idx) => (data.files as File[]).splice(idx, 1))\r\n // Registra cada arquivo no FileMonitor e verifica duplicata/tamanho\r\n let item: any = null\r\n ;(data.files as File[]).forEach((file) => {\r\n item = ECM.attachFileMonitor?.add({\r\n name: file.name,\r\n fullPath: ECM.WKFViewAttachment?.defFullPath ?? 'BPM',\r\n droppedZipZone: false,\r\n hasApprovers: ECM.WKFViewAttachment?.defHasApprovers ?? false,\r\n })\r\n const isDuplicate = (ECM.newAttachmentsDocs as any[])?.some(\r\n (d) => d.name === item?.name\r\n )\r\n if (isDuplicate) {\r\n ECM.attachFileMonitor?.error(item, 'Arquivo duplicado. Você tentou enviar um arquivo já anexado com este nome. ')\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:error'))\r\n return false\r\n }\r\n const maxMb = ECM.maxUploadSize ?? 0\r\n if (maxMb > 0 && file.size >= maxMb * 1024 * 1024) {\r\n ECM.attachFileMonitor?.error(item, `Tamanho total do arquivo ultrapassou o limite de ${ECM.core?.formatSize?.(maxMb) ?? maxMb + ' MB'}`)\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:error'))\r\n return false\r\n }\r\n if (data) {\r\n const datasUpload = ECM.WKFViewAttachment?.datasUpload ?? (window as any).datasUpload\r\n if (datasUpload) datasUpload[item.id] = data\r\n }\r\n data.context = item?.context\r\n })\r\n return callbacks.onFileAdd(e, data)\r\n })\r\n .off('fileuploaddone')\r\n .on('fileuploaddone', (e: any, data: any) => {\r\n const ECM = getECM()\r\n ;(data.result?.files as any[])?.forEach((file) => {\r\n let item: any = {}\r\n if (data.context) {\r\n item.id = data.context.data?.('item-id')\r\n item.fullPath = data.context.data?.('item-full-path')\r\n item.droppedZipZone = data.context.data?.('item-dropped-zip-zone')\r\n }\r\n if (file.error) {\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:error'))\r\n ECM?.attachFileMonitor?.error(item, file.error)\r\n } else if (item) {\r\n item.name = file.name\r\n item.internalId = Date.now()\r\n const el = $?.('#ecm-navigation-inputFile-clone')\r\n if (el?.attr?.('data-on-camera') === 'true') {\r\n const cameraName = el.attr('data-file-name-camera')\r\n if (cameraName) item.description = cameraName\r\n el.removeAttr('data-on-camera')\r\n el.removeAttr('data-file-name-camera')\r\n }\r\n item.uploadId = file.uploadId\r\n ECM?.WKFViewAttachment?.startPublishingDocument?.(null, item)\r\n callbacks.onFileDone(e, data, { description: item.description, name: item.name })\r\n }\r\n })\r\n })\r\n .off('fileuploadfail')\r\n .on('fileuploadfail', (e: any, data: any) => {\r\n if (data?.context) {\r\n const ECM = getECM()\r\n const item: any = { id: data.context.data?.('item-id') }\r\n ECM?.attachFileMonitor?.cancel?.(item)\r\n }\r\n callbacks.onFileFail(e, data)\r\n })\r\n },\r\n }\r\n}\r\n","import { getAttachmentOps, getParentEnv, getProcessInfo, getUploadHandlerOps, type IAttachmentOps, type IParentEnv, type IProcessInfo, type IUploadHandlerOps } from '../process-context'\r\n\r\n/** Permissões de operação sobre anexos */\r\nexport type AttachmentPermission = 'R' | 'P' | 'E' | 'D' | 'M' | 'O'\r\n\r\n/** Linha da tabela de anexos do processo */\r\nexport type AttachmentRow = { [key: string]: string }\r\n\r\n/**\r\n * Composição de todas as operações necessárias do ambiente de processo.\r\n * União das quatro interfaces segregadas de `process-context`.\r\n */\r\nexport type WorkflowContext = IAttachmentOps & IProcessInfo & IParentEnv & IUploadHandlerOps\r\n\r\n/**\r\n * Retorna o adapter de contexto do processo em execução.\r\n * Delega para as fábricas segregadas de `process-context`, cada uma validando\r\n * apenas o objeto `parent.*` de que depende.\r\n * Para substituir em testes, basta reimplementar as fábricas individuais.\r\n *\r\n * @throws {Error} quando `WKFViewAttachment` não está disponível\r\n * @throws {Error} quando `ECM` não está disponível\r\n */\r\nexport function getWorkflowContext(): WorkflowContext {\r\n return {\r\n ...getAttachmentOps(),\r\n ...getProcessInfo(),\r\n ...getParentEnv(),\r\n ...getUploadHandlerOps(),\r\n }\r\n}\r\n","import { GENERIC_ATTACHMENT_MARKER } from './attachment.constants'\r\nimport { getWorkflowContext } from './workflow-context'\r\n\r\n/**\r\n * Retorna `true` para anexos internos da biblioteca (prefixo `_jsegd_`).\r\n * Esses documentos nunca devem ser exibidos ao usuário.\r\n */\r\nexport function isMetadataAttachment(attachment: Attachment): boolean {\r\n return attachment.description.startsWith('_jsegd_')\r\n}\r\n\r\n/**\r\n * Retorna todos os anexos cujo prefixo de descrição corresponde ao valor informado.\r\n * Quando `description` é o marcador genérico, retorna todos os anexos que o contêm.\r\n */\r\nexport function getAttachmentsByDescription(description: string): Attachment[] {\r\n const context = getWorkflowContext()\r\n if (description === GENERIC_ATTACHMENT_MARKER) {\r\n return context.getAllAttachments().filter((attachment) => attachment.description.toLowerCase().includes(description.toLowerCase()))\r\n }\r\n return context\r\n .getAllAttachments()\r\n .filter((attachment) => attachment.description.replace(/_V\\d+$/, '').toLowerCase() === description.toLowerCase())\r\n}\r\n\r\n/**\r\n * Filtra a lista retornando apenas anexos já publicados (não são novos uploads pendentes).\r\n */\r\nexport function filterPublishedAttachments(attachments: Attachment[]): Attachment[] {\r\n return attachments.filter((attachment) => attachment.newAttach !== true)\r\n}\r\n\r\n/**\r\n * Retorna o índice na tabela de anexos do processo para a linha que satisfaz o predicado.\r\n * Centraliza o padrão `getTableData().findIndex()` usado em múltiplos locais.\r\n */\r\nexport function findAttachmentTableIndex(predicate: (row: { [key: string]: string }) => boolean): number {\r\n return getWorkflowContext().getTableData().findIndex(predicate)\r\n}\r\n\r\n/**\r\n * Retorna as descrições sem sufixo de versão dos anexos genéricos existentes,\r\n * sem duplicatas. Usado pelo autocomplete do modal de descrição.\r\n */\r\nexport function getGenericAttachmentDescriptions(): string[] {\r\n const attachments = getAttachmentsByDescription(GENERIC_ATTACHMENT_MARKER)\r\n const prefixes = attachments.map((a) => a.description.replace(/_Z__V\\d+$/, '').replace(/_Z_$/, ''))\r\n return [...new Set(prefixes)]\r\n}\r\n\r\n/**\r\n * Verifica se o usuário atual possui a permissão especificada no processo em curso.\r\n */\r\nexport function hasPermission(type: 'R' | 'P' | 'E' | 'D' | 'M' | 'O'): boolean {\r\n return getWorkflowContext().getUserPermissions().indexOf(type) >= 0\r\n}\r\n\r\n/**\r\n * Retorna `true` se o processo ainda não foi persistido (processInstanceId === 0).\r\n * Downloads e visualizações de documentos não publicados são bloqueados nesse estado.\r\n */\r\nexport function isNewProcess(): boolean {\r\n return getWorkflowContext().getProcessInstanceId() === 0\r\n}\r\n\r\n/**\r\n * Retorna `true` se o anexo pertence ao usuário atual.\r\n */\r\nexport function isOwnAttachment(attachment: Attachment): boolean {\r\n return attachment.colleagueId === getWorkflowContext().getTaskUserId()\r\n}\r\n\r\n/**\r\n * Verifica se o usuário pode editar o anexo fornecido.\r\n * - 'M': editar anexo próprio\r\n * - 'O': editar anexo de outros\r\n */\r\nexport function canEditAttachment(attachment: Attachment): boolean {\r\n if (isOwnAttachment(attachment)) {\r\n return hasPermission('M')\r\n }\r\n return hasPermission('O')\r\n}\r\n\r\n/**\r\n * Sanitiza campos de texto de um anexo antes de renderização em template HTML.\r\n * Protege contra XSS em campos que podem vir de entrada de usuário (description).\r\n */\r\nexport function sanitizeAttachmentForDisplay(attachment: Attachment): Attachment {\r\n return {\r\n ...attachment,\r\n description: attachment.description.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"'),\r\n }\r\n}\r\n\r\n/**\r\n * Sanitiza um nome de arquivo/descrição para uso seguro em upload programático.\r\n * Remove caracteres inválidos em nomes de arquivo, normaliza espaços, limita a 100 caracteres\r\n * e remove acentuação para garantir compatibilidade com sistemas de arquivo.\r\n */\r\nexport function sanitizeAttachmentName(input: string): string {\r\n let sanitized = input.replace(/[<>:\"/\\\\|?*\\x00-\\x1F]/g, '')\r\n sanitized = sanitized.replace(/\\s+/g, ' ').trim()\r\n if (sanitized.length > 100) {\r\n sanitized = sanitized.substring(0, 100)\r\n }\r\n sanitized = sanitized.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '')\r\n return sanitized\r\n}\r\n","/**\r\n * Calcula a próxima versão com base no maior número `_V{n}` encontrado nas descrições.\r\n */\r\nexport function getNextVersion(attachments: Attachment[]): number {\r\n let maxVersion = 0\r\n attachments.forEach((attachment) => {\r\n const match = attachment.description.match(/_V(\\d+)$/)\r\n if (match) {\r\n const version = parseInt(match[1], 10)\r\n maxVersion = Math.max(maxVersion, version)\r\n }\r\n })\r\n return maxVersion + 1\r\n}\r\n\r\n/**\r\n * Aplica a próxima versão à descrição, substituindo `_V{n}` existente ou adicionando `_V{n+1}`.\r\n */\r\nexport function applyNextVersion(description: string, attachments: Attachment[]): string {\r\n const nextVersion = getNextVersion(attachments)\r\n return description.replace(/_V\\d+$/, '') + `_V${nextVersion}`\r\n}\r\n","export type CallbackView = (params: { colleagueId: string; documentId: number; version: number }) => void\r\n\r\nexport type CallbackRemove = (params: { description: string }) => void\r\n\r\n/**\r\n * Modal de seleção de anexos exibido quando há mais de um com a mesma descrição.\r\n * Renderiza uma tabela FLUIGC com os anexos disponíveis e executa o callback ao selecionar um item.\r\n */\r\nexport class AttachmentPickerModal {\r\n private datatable: Datatable\r\n private modal: Modal\r\n\r\n constructor(attachments: Attachment[], callback: CallbackView | CallbackRemove) {\r\n const existing = parent.document.getElementById('modalPesquisa')\r\n if (existing) existing.remove()\r\n this.modal = this.createModal()\r\n this.datatable = this.createTable(attachments)\r\n this.bindEvents(callback)\r\n }\r\n\r\n private createTable(attachments: Attachment[]) {\r\n return parent.FLUIGC.datatable('#targetModal', {\r\n dataRequest: attachments,\r\n renderContent: ['attachedActivity', 'attachedUser', 'description'],\r\n header: [{ title: 'Atividade' }, { title: 'Solicitante' }, { title: 'Descrição' }],\r\n multiSelect: false,\r\n search: {\r\n enabled: false,\r\n onlyEnterkey: false,\r\n searchAreaStyle: 'col-12',\r\n onSearch: () => {},\r\n },\r\n scroll: { enabled: false },\r\n navButtons: { enabled: false },\r\n tableStyle: 'table-striped table-hover table-condensed',\r\n emptyMessage: 'Nenhum dado encontrado',\r\n classSelected: '',\r\n actions: {\r\n enabled: true,\r\n template: '',\r\n actionAreaStyle: '',\r\n },\r\n draggable: {\r\n enabled: false,\r\n onDrag: () => {},\r\n },\r\n })\r\n }\r\n\r\n private createModal() {\r\n const templateModelo = `\r\n <div class=\"row\">\r\n <div class=\"col-xs-12 col-sm-12 col-md-12 fs-xs-padding\" id=\"targetModal\">\r\n </div>\r\n </div>\r\n `\r\n return parent.FLUIGC.modal(\r\n {\r\n title: 'Pesquisar',\r\n content: templateModelo,\r\n id: 'modalPesquisa',\r\n size: 'full',\r\n actions: [],\r\n showHeader: true,\r\n showFooter: true,\r\n headerActions: [],\r\n headerContent: '',\r\n formModal: false,\r\n },\r\n () => {}\r\n )\r\n }\r\n\r\n private bindEvents(callback: CallbackView | CallbackRemove) {\r\n this.datatable.on('fluig.datatable.onselectrow', (data: DataCallback) => {\r\n const attachment = this.datatable.getRow(data.selectedIndex[0], false) as Attachment\r\n callback(attachment)\r\n // destroy() não está nos tipos públicos de Datatable do FLUIG SDK\r\n if (typeof (this.datatable as any).destroy === 'function') {\r\n ;(this.datatable as any).destroy()\r\n }\r\n this.modal.remove()\r\n })\r\n }\r\n}\r\n","import './attachment.events'\r\nimport {\r\n canEditAttachment,\r\n filterPublishedAttachments,\r\n findAttachmentTableIndex,\r\n getAttachmentsByDescription,\r\n hasPermission,\r\n isNewProcess,\r\n isOwnAttachment,\r\n sanitizeAttachmentName,\r\n} from './attachment.utils'\r\nimport { applyNextVersion } from './attachment.version'\r\nimport { AttachmentPickerModal } from './attachmentPickerModal'\r\nimport { GENERIC_ATTACHMENT_MARKER } from './attachment.constants'\r\nimport { getWorkflowContext } from './workflow-context'\r\nimport type { AttachmentSource } from './attachment-metadata'\r\n\r\n/**\r\n * @protected\r\n */\r\nexport class Attach {\r\n private static instance: Attach\r\n\r\n /** Origem do último upload iniciado (atualizado por `add()` e `uploadBlob()`) */\r\n static currentUploadSource: AttachmentSource = 'button'\r\n /** Filtro de tipos do último upload iniciado */\r\n static currentUploadAccept: string | null = null\r\n\r\n private constructor() {\r\n this.interceptUploadEvents()\r\n window.addEventListener('jsegd:attachment:download', ({ detail }) => {\r\n Attach.download(detail.documentId)\r\n })\r\n }\r\n\r\n public static getInstance(): Attach {\r\n if (!Attach.instance) {\r\n Attach.instance = new Attach()\r\n }\r\n return Attach.instance\r\n }\r\n\r\n private interceptUploadEvents(): void {\r\n const context = getWorkflowContext()\r\n\r\n // Remove drag-and-drop nativo do Fluig\r\n context.removeDragListeners()\r\n\r\n // Sobrescreve handler de remoção para disparar evento no window do iframe\r\n context.overrideSuccessRemoveAttachment((data: unknown[]) => {\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:reset'))\r\n const message = Array.isArray(data) && data.length > 1\r\n ? 'Os anexos foram removidos'\r\n : 'O anexo foi removido'\r\n FLUIGC.toast({ message, type: 'success' })\r\n })\r\n\r\n // Vincula handlers TypeScript ao jQuery File Upload\r\n context.bindFileUploadHandlers({\r\n onFileAdd: (_e: unknown, _data: unknown) => {\r\n // Validação completa é realizada em process-context.bindFileUploadHandlers\r\n },\r\n onFileDone: (_e: unknown, _data: unknown, item: { description?: string; name?: string }) => {\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:success', {\r\n detail: {\r\n description: item.description ?? item.name,\r\n source: Attach.currentUploadSource,\r\n accept: Attach.currentUploadAccept,\r\n },\r\n }))\r\n },\r\n onFileFail: (_e: unknown, _data: unknown) => {\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:error'))\r\n },\r\n })\r\n }\r\n\r\n /**\r\n * Abre o seletor de arquivos para adicionar um novo anexo ao processo.\r\n * Aplica versionamento automático ao nome quando já existe um anexo com a mesma descrição.\r\n *\r\n * @param attachmentDescription Descrição (label) do anexo — usada como nome do arquivo no ECM\r\n * @param accept Tipos de arquivo aceitos pelo seletor (ex: \".pdf,.docx\"). `null` aceita qualquer tipo.\r\n */\r\n add(attachmentDescription: string, accept: string | null | undefined) {\r\n Attach.currentUploadSource = attachmentDescription === GENERIC_ATTACHMENT_MARKER ? 'toolbar' : 'button'\r\n Attach.currentUploadAccept = accept ?? null\r\n const element = parent.document.getElementById('ecm-navigation-inputFile-clone') as HTMLInputElement\r\n const attachments = getAttachmentsByDescription(attachmentDescription)\r\n if (accept) {\r\n element.setAttribute('accept', accept)\r\n }\r\n attachmentDescription = applyNextVersion(attachmentDescription, attachments)\r\n element.setAttribute('data-on-camera', 'true')\r\n element.setAttribute('data-file-name-camera', attachmentDescription)\r\n element.click()\r\n }\r\n\r\n /**\r\n * Abre o visualizador de documentos para o anexo informado.\r\n * Quando há mais de um anexo com a mesma descrição, exibe um modal de seleção.\r\n * Bloqueia ação em processos não iniciados e valida permissões de leitura.\r\n *\r\n * @param attachmentDescription Descrição do anexo a ser visualizado\r\n */\r\n view(attachmentDescription: string) {\r\n if (isNewProcess()) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Não é possível visualizar anexos em um processo não iniciado',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n const attachments = getAttachmentsByDescription(attachmentDescription)\r\n if (attachments.length === 0) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Não há documentos em anexo',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n const publishedAttachments = filterPublishedAttachments(attachments)\r\n if (publishedAttachments.length === 0) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Não é possível visualizar documentos anexados nesta etapa do processo',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n if (!hasPermission('R') && !publishedAttachments.some(isOwnAttachment)) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Usuário não possui permissão para visualizar anexos',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n const callback = ({ colleagueId, documentId, version }: { colleagueId: string; documentId: number; version: number }) => {\r\n getWorkflowContext().openAttachmentView(colleagueId, documentId, version)\r\n }\r\n new AttachmentPickerModal(publishedAttachments, callback)\r\n }\r\n\r\n /**\r\n * Remove um anexo do processo após confirmação via modal.\r\n * Quando há mais de um anexo com a mesma descrição, exibe um modal de seleção.\r\n * Valida permissões de exclusão antes de prosseguir.\r\n *\r\n * @param attachmentDescription Descrição do anexo a ser removido\r\n */\r\n remove(attachmentDescription: string) {\r\n if (!hasPermission('E') && !hasPermission('D')) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Usuário não possui permissão para remover anexos',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n const attachments = getAttachmentsByDescription(attachmentDescription)\r\n if (attachments.length === 0) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Não há documentos em anexo',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n const context = getWorkflowContext()\r\n const callback = ({ description }: { description: string }) => {\r\n const index = findAttachmentTableIndex((row) => row['description'] === description)\r\n context.confirmRemoveAttach([index])\r\n }\r\n new AttachmentPickerModal(attachments, callback)\r\n }\r\n\r\n /**\r\n * Inicia o download de um anexo pelo seu identificador de documento.\r\n * Bloqueia a ação em processos não iniciados.\r\n *\r\n * @param documentId Identificador do documento a ser baixado\r\n */\r\n public static download(documentId: number): void {\r\n if (isNewProcess()) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Não é possível fazer download de anexos em um processo não iniciado',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n const index = findAttachmentTableIndex((row) => row['documentId'] === String(documentId))\r\n if (index >= 0) {\r\n getWorkflowContext().downloadAttach([index])\r\n }\r\n }\r\n\r\n /**\r\n * Abre o painel de edição de conteúdo para o anexo informado.\r\n * Filtra apenas anexos publicados que o usuário tem permissão de editar.\r\n * Quando há mais de um anexo editável, exibe modal de seleção.\r\n * Bloqueia a ação em processos não iniciados.\r\n *\r\n * @param attachmentDescription Descrição do anexo a ser editado\r\n */\r\n edit(attachmentDescription: string) {\r\n if (isNewProcess()) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Não é possível editar anexos em um processo não iniciado',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n const allAttachments = getAttachmentsByDescription(attachmentDescription)\r\n const editableAttachments = filterPublishedAttachments(allAttachments).filter(canEditAttachment)\r\n if (editableAttachments.length === 0) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Nenhum anexo disponível para edição',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n const context = getWorkflowContext()\r\n const callback = ({ description }: { description: string }) => {\r\n const index = findAttachmentTableIndex((row) => row['description'] === description)\r\n if (index >= 0) {\r\n context.editAttach(context.getTableRow(index), index)\r\n }\r\n }\r\n new AttachmentPickerModal(editableAttachments, callback)\r\n }\r\n\r\n /**\r\n * Retorna todos os anexos do processo atual.\r\n * @returns Lista de todos os objetos `Attachment` presentes no processo\r\n */\r\n public static getAllAttachments(): Attachment[] {\r\n return getWorkflowContext().getAllAttachments()\r\n }\r\n\r\n /**\r\n * Inicia o download de um Blob diretamente no navegador do usuário,\r\n * sem interação com o ECM ou com o processo em execução.\r\n *\r\n * @param blob Conteúdo a ser baixado\r\n * @param filename Nome do arquivo que será sugerido ao navegador\r\n * @param type Tipo MIME do arquivo. Quando omitido, usa `blob.type`.\r\n */\r\n public static downloadBlob(blob: Blob, filename: string, type?: string): void {\r\n const file = type ? new Blob([blob], { type }) : blob\r\n const url = URL.createObjectURL(file)\r\n const a = document.createElement('a')\r\n a.href = url\r\n a.download = filename\r\n a.click()\r\n URL.revokeObjectURL(url)\r\n }\r\n\r\n /**\r\n * Faz upload programático de um Blob como anexo do processo,\r\n * sem abrir o seletor de arquivos nativo. Sanitiza o nome antes do envio.\r\n *\r\n * @param blob Arquivo no formato `Blob` — deve ser não-vazio\r\n * @param description Nome/descrição do arquivo que será exibido no ECM\r\n * @param type Tipo MIME do arquivo. Quando omitido, usa `blob.type`.\r\n * @throws {Error} Via toast quando o Blob é inválido, o MIME está ausente ou o contexto não está disponível\r\n */\r\n public static uploadBlob(blob: Blob, description: string, type?: string): void {\r\n Attach.currentUploadSource = 'drag-drop'\r\n Attach.currentUploadAccept = null\r\n if (!(blob instanceof Blob) || blob.size === 0) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Blob inválido ou vazio.',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n const mimeType = type || blob.type\r\n if (!mimeType) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Tipo MIME não especificado.',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n if (!parent || !parent.document) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Contexto parent.document não disponível.',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n const inputFile = parent.document.getElementById('ecm-navigation-inputFile-clone') as HTMLInputElement | null\r\n if (!inputFile) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Elemento de input de upload não encontrado.',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n const safeDescription = sanitizeAttachmentName(description)\r\n const file = new File([blob], safeDescription, { type: mimeType })\r\n const dt = new DataTransfer()\r\n dt.items.add(file)\r\n inputFile.files = dt.files\r\n inputFile.dispatchEvent(new Event('change'))\r\n }\r\n}\r\n","import { sanitizeAttachmentName } from './attachment.utils'\r\n\r\n/** Entrada de um arquivo para upload em lote via drag-and-drop */\r\nexport type DragDropEntry = { file: File; name: string }\r\n\r\n/**\r\n * Modal de associação de nomes para upload em lote via drag-and-drop.\r\n * Exibe todos os arquivos arrastados de uma vez, com campo de nome editável por linha\r\n * e checkbox global \"Usar nomes originais dos arquivos\".\r\n * @hideconstructor\r\n */\r\nexport class DragDropNameModal {\r\n private readonly modal: any\r\n private readonly files: File[]\r\n private readonly onConfirm: (entries: DragDropEntry[]) => void\r\n\r\n constructor(files: FileList, onConfirm: (entries: DragDropEntry[]) => void) {\r\n this.files = Array.from(files)\r\n this.onConfirm = onConfirm\r\n\r\n const rows = this.files\r\n .map(\r\n (f, i) => `\r\n <div style=\"display:flex;align-items:center;gap:8px;margin-bottom:6px\">\r\n <span style=\"flex:0 0 auto;font-size:12px;color:#555;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap\" title=\"${sanitizeAttributeValue(f.name)}\">${sanitizeText(f.name)}</span>\r\n <input\r\n type=\"text\"\r\n class=\"form-control input-sm drag-drop-name-input\"\r\n data-index=\"${i}\"\r\n value=\"${sanitizeAttributeValue(sanitizeAttachmentName(f.name))}\"\r\n style=\"flex:1\"\r\n />\r\n </div>`\r\n )\r\n .join('')\r\n\r\n const content = `\r\n <div id=\"drag-drop-name-modal-body\">\r\n <div style=\"margin-bottom:10px\">\r\n <label style=\"cursor:pointer;font-weight:normal\">\r\n <input type=\"checkbox\" id=\"drag-drop-use-originals\" style=\"margin-right:6px\">\r\n Usar nomes originais dos arquivos\r\n </label>\r\n </div>\r\n ${rows}\r\n </div>`\r\n\r\n const cfg = {\r\n title: 'Associar nomes aos arquivos',\r\n content: content,\r\n id: 'drag-drop-name-modal',\r\n size: 'medium',\r\n showHeader: true,\r\n showFooter: true,\r\n headerActions: [],\r\n headerContent: '',\r\n formModal: false,\r\n actions: [\r\n { label: 'Cancelar', classType: 'btn-default', autoClose: true },\r\n { label: 'Confirmar', classType: 'btn-primary', bind: 'data-drag-drop-confirm' },\r\n ],\r\n }\r\n\r\n this.modal = FLUIGC.modal(cfg, () => {})\r\n this.bindEvents()\r\n }\r\n\r\n private bindEvents(): void {\r\n // Checkbox \"usar nomes originais\"\r\n document.addEventListener('change', this.handleUseOriginals)\r\n\r\n // Botão confirmar\r\n document\r\n .querySelector('[data-drag-drop-confirm]')\r\n ?.addEventListener('click', () => this.confirm())\r\n }\r\n\r\n private handleUseOriginals = (e: Event): void => {\r\n const target = e.target as HTMLInputElement\r\n if (target.id !== 'drag-drop-use-originals') return\r\n const inputs = document.querySelectorAll<HTMLInputElement>('.drag-drop-name-input')\r\n inputs.forEach((input, i) => {\r\n input.disabled = target.checked\r\n if (target.checked) {\r\n input.value = sanitizeAttachmentName(this.files[i]?.name ?? '')\r\n }\r\n })\r\n }\r\n\r\n private confirm(): void {\r\n const inputs = document.querySelectorAll<HTMLInputElement>('.drag-drop-name-input')\r\n const entries: DragDropEntry[] = this.files.map((file, i) => ({\r\n file,\r\n name: sanitizeAttachmentName((inputs[i]?.value || file.name).trim()),\r\n }))\r\n\r\n document.removeEventListener('change', this.handleUseOriginals)\r\n this.modal?.remove?.()\r\n this.onConfirm(entries)\r\n }\r\n}\r\n\r\n/** Escapa texto para inserção como conteúdo de elemento HTML */\r\nfunction sanitizeText(text: string): string {\r\n return text\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n}\r\n\r\n/** Escapa texto para uso em atributos HTML entre aspas duplas */\r\nfunction sanitizeAttributeValue(text: string): string {\r\n return sanitizeText(text).replace(/\"/g, '"')\r\n}\r\n","import { Attach } from './attach'\r\nimport { METADATA_ATTACHMENT_NAME } from './attachment.constants'\r\nimport { getWorkflowContext } from './workflow-context'\r\n\r\n/** Origem do upload de um anexo */\r\nexport type AttachmentSource = 'button' | 'toolbar' | 'drag-drop'\r\n\r\n/**\r\n * Metadados associados a um único documento anexado ao processo.\r\n * Persiste informações que o ECM não armazena nativamente.\r\n */\r\nexport interface AttachmentRecord {\r\n /** ID do documento no ECM */\r\n documentId: number\r\n /** Mecanismo pelo qual o arquivo foi adicionado */\r\n source: AttachmentSource\r\n /**\r\n * Descrição base do `AttachButton` que originou o upload.\r\n * Presente apenas quando `source === 'button'`.\r\n */\r\n buttonDescription?: string\r\n /** Filtro de tipos de arquivo ativo no momento do upload (`null` = qualquer tipo) */\r\n accept: string | null\r\n /** Número de sequência da movimentação do processo em que foi anexado */\r\n workflowSequence: number\r\n /** Data e hora do upload em ISO 8601 */\r\n uploadedAt: string\r\n /**\r\n * Metadados arbitrários adicionados pelo consumidor da biblioteca.\r\n * Nunca interpretado internamente — apenas serializado/desserializado.\r\n */\r\n custom?: Record<string, unknown>\r\n}\r\n\r\n/** Configuração persistida de um `AttachButton` registrado */\r\nexport interface ButtonRecord {\r\n /** Filtro de tipos de arquivo definido no atributo `accept` do botão */\r\n accept: string | null\r\n}\r\n\r\n/** Schema do arquivo `_jsegd_metadata.json` armazenado como anexo interno do processo */\r\nexport interface AttachmentMetadata {\r\n /** Versão do schema — permite migrações sem quebra ao evoluir a estrutura */\r\n version: number\r\n /**\r\n * Registry de botões registrados.\r\n * Chave: `description` do botão em lowercase sem sufixo de versão.\r\n */\r\n buttons: Record<string, ButtonRecord>\r\n /**\r\n * Metadados por documento anexado.\r\n * Chave: `String(documentId)`.\r\n */\r\n attachments: Record<string, AttachmentRecord>\r\n /** Data e hora da última gravação em ISO 8601 */\r\n updatedAt: string\r\n}\r\n\r\n/**\r\n * Cache de sessão em memória.\r\n * `undefined` = não carregado; `null` = carregado, sem arquivo; objeto = dados válidos.\r\n */\r\nlet sessionCache: AttachmentMetadata | null | undefined = undefined\r\n\r\n/**\r\n * Gerencia o arquivo de metadados oculto `_jsegd_metadata` do processo.\r\n * @internal — não exportado pelo barrel público; uso exclusivo da biblioteca.\r\n */\r\nexport class AttachmentMetadataFile {\r\n private static readonly CURRENT_VERSION = 1\r\n\r\n /**\r\n * Verifica de forma síncrona se o arquivo de metadados já existe no processo.\r\n * Retorna `false` em nova solicitação (documentId ainda não atribuído).\r\n */\r\n static exists(): boolean {\r\n return !!AttachmentMetadataFile.findAttachment()\r\n }\r\n\r\n /**\r\n * Retorna o anexo de metadados se existir e já possuir `documentId`.\r\n * Retorna `undefined` quando não há anexo com a descrição interna\r\n * ou quando `documentId === 0` (nova solicitação).\r\n */\r\n private static findAttachment(): Attachment | undefined {\r\n const att = Attach.getAllAttachments().find(\r\n (a) => a.description === METADATA_ATTACHMENT_NAME\r\n )\r\n return att?.documentId ? att : undefined\r\n }\r\n\r\n /**\r\n * Carrega e desserializa o arquivo de metadados do processo.\r\n * Resultado memoizado durante a sessão.\r\n * Retorna `null` quando o arquivo não existe ou o processo é nova solicitação.\r\n *\r\n * @param force Ignora o cache de sessão e recarrega do ECM\r\n * @throws {Error} quando o fetch falha com status HTTP ≥ 400\r\n */\r\n static async load(force = false): Promise<AttachmentMetadata | null> {\r\n if (!force && sessionCache !== undefined) return sessionCache\r\n\r\n const attachment = AttachmentMetadataFile.findAttachment()\r\n if (!attachment) {\r\n sessionCache = null\r\n return null\r\n }\r\n\r\n // Content Management API v2 — não requer companyId nem version\r\n const url = `/content-management/api/v2/documents/${attachment.documentId}/stream`\r\n const response = await fetch(url, { credentials: 'include' })\r\n if (!response.ok) {\r\n throw new Error(`Falha ao carregar metadados: HTTP ${response.status}`)\r\n }\r\n\r\n const raw: unknown = await response.json()\r\n sessionCache = AttachmentMetadataFile.parseAndMigrate(raw)\r\n return sessionCache\r\n }\r\n\r\n /**\r\n * Persiste os metadados no processo atual.\r\n *\r\n * - Sempre atualiza o `sessionCache` em memória.\r\n * - Não persiste no ECM quando `processInstanceId === 0`\r\n * (nova solicitação — documentIds ainda não atribuídos).\r\n * - Remove o anexo anterior de forma silenciosa antes de subir o novo:\r\n * o Fluig não versiona pelo nome — cria um duplicado se o anterior existir.\r\n *\r\n * @param metadata Dados a persistir\r\n * @param attach Instância de `Attach` usada para o upload do blob\r\n */\r\n static save(metadata: AttachmentMetadata): void {\r\n const updated: AttachmentMetadata = {\r\n ...metadata,\r\n updatedAt: new Date().toISOString(),\r\n }\r\n\r\n // Atualiza o memo imediatamente\r\n sessionCache = updated\r\n\r\n // Guard: nova solicitação ainda não tem processInstanceId\r\n const ctx = getWorkflowContext()\r\n if (!ctx.getProcessInstanceId()) return\r\n\r\n // Remove o anexo anterior silenciosamente (sem diálogo, sem toast).\r\n // Attach.remove() não pode ser usado — abre modal de confirmação.\r\n const existing = AttachmentMetadataFile.findAttachment()\r\n if (existing) {\r\n ctx.deleteAttachmentSilent(existing)\r\n }\r\n\r\n const json = JSON.stringify(updated, null, 2)\r\n const blob = new Blob([json], { type: 'application/json' })\r\n Attach.uploadBlob(blob, METADATA_ATTACHMENT_NAME, 'application/json')\r\n }\r\n\r\n /**\r\n * Desserializa e migra o schema se necessário.\r\n * Garante que dados corrompidos ou parciais resultam em estrutura válida.\r\n */\r\n private static parseAndMigrate(raw: unknown): AttachmentMetadata {\r\n if (typeof raw !== 'object' || raw === null) {\r\n return AttachmentMetadataFile.empty()\r\n }\r\n\r\n const data = raw as Partial<AttachmentMetadata>\r\n\r\n // Versão 1 é a inicial — sem migração necessária por enquanto\r\n // Estrutura para versões futuras:\r\n // if ((data.version ?? 0) < 2) data = migrateV1toV2(data)\r\n\r\n return {\r\n version: AttachmentMetadataFile.CURRENT_VERSION,\r\n buttons: data.buttons ?? {},\r\n attachments: data.attachments ?? {},\r\n updatedAt: data.updatedAt ?? new Date().toISOString(),\r\n }\r\n }\r\n\r\n /** Retorna um objeto de metadados vazio com a versão atual do schema */\r\n static empty(): AttachmentMetadata {\r\n return {\r\n version: AttachmentMetadataFile.CURRENT_VERSION,\r\n buttons: {},\r\n attachments: {},\r\n updatedAt: new Date().toISOString(),\r\n }\r\n }\r\n}\r\n","import { Attach } from './attach'\r\nimport {\r\n canEditAttachment,\r\n hasPermission,\r\n isMetadataAttachment,\r\n isNewProcess,\r\n isOwnAttachment,\r\n sanitizeAttachmentForDisplay,\r\n sanitizeAttachmentName,\r\n} from './attachment.utils'\r\nimport { GENERIC_ATTACHMENT_MARKER, UNPUBLISHED_VERSION_DISPLAY } from './attachment.constants'\r\nimport { getWorkflowContext } from './workflow-context'\r\nimport { DragDropNameModal } from './drag-drop-name-modal'\r\nimport { AttachmentMetadataFile } from './attachment-metadata'\r\nimport type { AttachmentRecord, AttachmentSource } from './attachment-metadata'\r\n\r\n/** Seletor do container raiz criado pela classe no DOM do frame pai */\r\nconst CONTAINER_ID = 'attachmentsCustom'\r\n/** Seletor do toolbar criado acima do container no modo `self-managed` */\r\nconst TOOLBAR_ID = 'attachmentsToolbar'\r\n\r\n/**\r\n * Modo de operação da tabela de anexos.\r\n * - `buttons-only` — somente download por linha; uploads exclusivamente via `AttachButton` externos\r\n * - `self-managed` — gerencia seu próprio ciclo de upload; exibe ações completas por linha;\r\n * aceita `AttachButton` externos cujos atributos são herdados pela linha do anexo\r\n */\r\nexport type AttachmentsTableMode = 'buttons-only' | 'self-managed'\r\n\r\n/** Opções de configuração de `AttachmentsTable` */\r\nexport interface AttachmentsTableOptions {\r\n /** Modo de operação. Obrigatório — sem valor padrão. */\r\n mode: AttachmentsTableMode\r\n /**\r\n * Tipos de arquivo aceitos nos uploads avulsos do modo `self-managed`.\r\n * Ex: `\".pdf,.docx\"`. `null` aceita qualquer tipo.\r\n */\r\n accept?: string | null\r\n}\r\n\r\n/**\r\n * Registro de um `AttachButton` na `AttachmentsTable`.\r\n * Armazenado para associar anexos existentes ao botão que os originou.\r\n */\r\nexport interface AttachButtonRegistration {\r\n /** Descrição base usada pelo botão (sem sufixo `_V\\d+`). */\r\n description: string\r\n /** Filtro de tipos de arquivo definido no botão. */\r\n accept: string | null\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Templates Mustache\r\n// ---------------------------------------------------------------------------\r\n\r\nconst THEAD = `\r\n <thead>\r\n <tr>\r\n <th data-sort=\"title\" data-order=\"asc\" style=\"cursor:pointer\">\r\n Nome <i class=\"flaticon flaticon-ordenation icon-xs\" aria-hidden=\"true\" style=\"margin-left:8px\"></i>\r\n </th>\r\n <th>Documento</th>\r\n <th>Versão</th>\r\n <th data-sort=\"user\" data-order=\"asc\" style=\"cursor:pointer\">\r\n Usuário <i class=\"flaticon flaticon-ordenation icon-xs\" aria-hidden=\"true\" style=\"margin-left:8px\"></i>\r\n </th>\r\n <th data-sort=\"date\" data-order=\"asc\" style=\"cursor:pointer\">\r\n Data <i class=\"flaticon flaticon-ordenation icon-xs\" aria-hidden=\"true\" style=\"margin-left:8px\"></i>\r\n </th>\r\n <th data-sort=\"activity\" data-order=\"asc\" style=\"cursor:pointer\">\r\n Atividade <i class=\"flaticon flaticon-ordenation icon-xs\" aria-hidden=\"true\" style=\"margin-left:8px\"></i>\r\n </th>\r\n <th></th>\r\n </tr>\r\n </thead>`\r\n\r\nconst TEMPLATE_BUTTONS_ONLY = `\r\n<table class=\"table table-condensed\" id=\"attachmentsTableCustom\">\r\n <caption>Lista de documentos anexados</caption>\r\n ${THEAD}\r\n <tbody>\r\n {{#attachments}}\r\n <tr>\r\n <td>\r\n {{#iconUrl}}<img src=\"/webdesk/{{iconPath}}\" class=\"iconAttachDoc\" />{{/iconUrl}}\r\n {{^iconUrl}}<i class=\"fluigicon fluigicon-md {{iconClass}}\"></i>{{/iconUrl}}\r\n <a href=\"#\"\r\n data-attachment-open\r\n data-colleague-id=\"{{colleagueId}}\"\r\n data-document-id=\"{{documentId}}\"\r\n data-version=\"{{version}}\"\r\n class=\"fs-sm-margin-left\">{{description}}</a>\r\n </td>\r\n <td>{{documentId}}</td>\r\n <td><span>{{#version}}{{version}}{{/version}}{{^version}}{{unpublishedVersion}}{{/version}}</span></td>\r\n <td>{{attachedUser}}</td>\r\n <td><span>{{#attachedDate}}{{attachedDate}}{{/attachedDate}}{{^attachedDate}}Ainda não publicado{{/attachedDate}}</span></td>\r\n <td>{{attachedActivity}}</td>\r\n <td>\r\n {{#enableDownload}}\r\n <i class=\"flaticon flaticon-download icon-sm\"\r\n aria-hidden=\"true\"\r\n data-attachment-download\r\n data-document-id=\"{{documentId}}\"\r\n style=\"cursor:pointer\"></i>\r\n {{/enableDownload}}\r\n </td>\r\n </tr>\r\n {{/attachments}}\r\n </tbody>\r\n</table>`\r\n\r\nconst TEMPLATE_SELF_MANAGED = `\r\n<table class=\"table table-condensed\" id=\"attachmentsTableCustom\">\r\n <caption>Lista de documentos anexados</caption>\r\n ${THEAD}\r\n <tbody>\r\n {{#attachments}}\r\n <tr>\r\n <td>\r\n {{#iconUrl}}<img src=\"/webdesk/{{iconPath}}\" class=\"iconAttachDoc\" />{{/iconUrl}}\r\n {{^iconUrl}}<i class=\"fluigicon fluigicon-md {{iconClass}}\"></i>{{/iconUrl}}\r\n <a href=\"#\"\r\n data-attachment-open\r\n data-colleague-id=\"{{colleagueId}}\"\r\n data-document-id=\"{{documentId}}\"\r\n data-version=\"{{version}}\"\r\n class=\"fs-sm-margin-left\">{{description}}</a>\r\n </td>\r\n <td>{{documentId}}</td>\r\n <td><span>{{#version}}{{version}}{{/version}}{{^version}}{{unpublishedVersion}}{{/version}}</span></td>\r\n <td>{{attachedUser}}</td>\r\n <td><span>{{#attachedDate}}{{attachedDate}}{{/attachedDate}}{{^attachedDate}}Ainda não publicado{{/attachedDate}}</span></td>\r\n <td>{{attachedActivity}}</td>\r\n <td class=\"attachments-actions\" style=\"white-space:nowrap\">\r\n {{#enableView}}\r\n <i class=\"flaticon flaticon-view icon-sm\" aria-hidden=\"true\"\r\n data-attachment-open\r\n data-colleague-id=\"{{colleagueId}}\"\r\n data-document-id=\"{{documentId}}\"\r\n data-version=\"{{version}}\"\r\n title=\"Visualizar\"\r\n style=\"cursor:pointer;margin-right:4px\"></i>\r\n {{/enableView}}\r\n {{#enableReversion}}\r\n <i class=\"flaticon flaticon-upload icon-sm\" aria-hidden=\"true\"\r\n data-attachment-reversion\r\n data-document-id=\"{{documentId}}\"\r\n data-button-description=\"{{buttonDescription}}\"\r\n data-button-accept=\"{{buttonAccept}}\"\r\n title=\"Nova versão\"\r\n style=\"cursor:pointer;margin-right:4px\"></i>\r\n {{/enableReversion}}\r\n {{#enableEdit}}\r\n <i class=\"flaticon flaticon-pencil icon-sm\" aria-hidden=\"true\"\r\n data-attachment-edit\r\n data-document-id=\"{{documentId}}\"\r\n title=\"Editar conteúdo\"\r\n style=\"cursor:pointer;margin-right:4px\"></i>\r\n {{/enableEdit}}\r\n {{#enableDownload}}\r\n <i class=\"flaticon flaticon-download icon-sm\" aria-hidden=\"true\"\r\n data-attachment-download\r\n data-document-id=\"{{documentId}}\"\r\n title=\"Download\"\r\n style=\"cursor:pointer;margin-right:4px\"></i>\r\n {{/enableDownload}}\r\n {{#enableDelete}}\r\n <i class=\"flaticon flaticon-trash icon-sm\" aria-hidden=\"true\"\r\n data-attachment-delete\r\n data-document-id=\"{{documentId}}\"\r\n title=\"Excluir\"\r\n style=\"cursor:pointer\"></i>\r\n {{/enableDelete}}\r\n </td>\r\n </tr>\r\n {{/attachments}}\r\n </tbody>\r\n</table>`\r\n\r\nconst TOOLBAR_HTML = `\r\n<div id=\"${TOOLBAR_ID}\" style=\"margin-bottom:8px\">\r\n <div class=\"btn-group\">\r\n <button type=\"button\" class=\"btn btn-sm btn-default\" data-attach-quick title=\"Anexar arquivo usando o nome original\">\r\n <i class=\"flaticon flaticon-add\" aria-hidden=\"true\"></i> Novo Anexo\r\n </button>\r\n <button type=\"button\" class=\"btn btn-sm btn-default dropdown-toggle\" data-toggle=\"dropdown\" aria-expanded=\"false\">\r\n <span class=\"caret\"></span>\r\n </button>\r\n <ul class=\"dropdown-menu\" role=\"menu\">\r\n <li><a href=\"#\" data-attach-quick>Usar nome do arquivo</a></li>\r\n <li><a href=\"#\" data-attach-named>Informar nome antes de anexar</a></li>\r\n </ul>\r\n </div>\r\n</div>`\r\n\r\n// ---------------------------------------------------------------------------\r\n// Classe principal\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Cria e gerencia uma tabela de anexos customizada no frame pai,\r\n * mantendo a tabela nativa do Fluig oculta.\r\n * @hideconstructor\r\n */\r\nexport class AttachmentsTable {\r\n private static instance: AttachmentsTable\r\n private static options: AttachmentsTableOptions\r\n private static attachInstance: Attach | null = null\r\n private static buttonRegistry: Map<string, AttachButtonRegistration> = new Map()\r\n\r\n private constructor() {\r\n AttachmentsTable.start()\r\n }\r\n\r\n /**\r\n * Retorna a instância singleton da tabela de anexos.\r\n * Deve ser chamado uma única vez durante a inicialização do form.\r\n *\r\n * @param options Configuração obrigatória de modo e accept\r\n */\r\n public static getInstance(options: AttachmentsTableOptions): AttachmentsTable {\r\n if (!AttachmentsTable.instance) {\r\n AttachmentsTable.options = options\r\n if (options.mode === 'self-managed') {\r\n AttachmentsTable.attachInstance = Attach.getInstance()\r\n }\r\n AttachmentsTable.instance = new AttachmentsTable()\r\n void AttachmentsTable.hydrateFromMetadata()\r\n }\r\n return AttachmentsTable.instance\r\n }\r\n\r\n /**\r\n * Registra um `AttachButton` para que seus metadados sejam associados\r\n * às linhas de anexo originadas por aquele botão.\r\n * Só tem efeito no modo `self-managed`.\r\n * @internal Chamado por `AttachButton` durante sua inicialização.\r\n */\r\n public static registerButton(registration: AttachButtonRegistration): void {\r\n if (AttachmentsTable.options?.mode !== 'self-managed') return\r\n AttachmentsTable.buttonRegistry.set(registration.description.toLowerCase(), registration)\r\n void AttachmentsTable.persistMetadata()\r\n }\r\n\r\n private static resolveButtonRegistration(attachment: Attachment): AttachButtonRegistration | undefined {\r\n const base = attachment.description.replace(/_V\\d+$/, '').toLowerCase()\r\n return AttachmentsTable.buttonRegistry.get(base)\r\n }\r\n\r\n private static start(): void {\r\n const context = getWorkflowContext()\r\n\r\n context.removeDragListeners()\r\n\r\n const nativeContainer = context.parentDocument.getElementById('ecm-workflowView-attachment') as HTMLElement | null\r\n if (nativeContainer) nativeContainer.style.display = 'none'\r\n\r\n const attachmentsRoot = context.parentDocument.getElementById('attachments')\r\n if (attachmentsRoot) {\r\n if (AttachmentsTable.options?.mode === 'self-managed') {\r\n const toolbarWrapper = context.parentDocument.createElement('div')\r\n toolbarWrapper.innerHTML = TOOLBAR_HTML\r\n attachmentsRoot.appendChild(toolbarWrapper.firstElementChild!)\r\n }\r\n const container = context.parentDocument.createElement('div')\r\n container.id = CONTAINER_ID\r\n attachmentsRoot.appendChild(container)\r\n }\r\n\r\n AttachmentsTable.render()\r\n\r\n // Event delegation — container\r\n context.parentDocument.getElementById(CONTAINER_ID)?.addEventListener('click', (event: Event) => {\r\n const target = event.target as HTMLElement\r\n\r\n const openLink = target.closest('[data-attachment-open]') as HTMLElement | null\r\n if (openLink) {\r\n event.preventDefault()\r\n const colleagueId = openLink.getAttribute('data-colleague-id') ?? ''\r\n const documentId = Number(openLink.getAttribute('data-document-id'))\r\n const version = Number(openLink.getAttribute('data-version'))\r\n context.openAttachmentView(colleagueId, documentId, version)\r\n return\r\n }\r\n\r\n const downloadIcon = target.closest('[data-attachment-download]') as HTMLElement | null\r\n if (downloadIcon) {\r\n event.preventDefault()\r\n const documentId = Number(downloadIcon.getAttribute('data-document-id'))\r\n window.dispatchEvent(new CustomEvent('jsegd:attachment:download', { detail: { documentId } }))\r\n return\r\n }\r\n\r\n const th = target.closest('th[data-sort]') as HTMLElement | null\r\n if (th) {\r\n const column = th.getAttribute('data-sort') as SortColumn\r\n const ascending = th.getAttribute('data-order') === 'asc'\r\n AttachmentsTable.sortBy(column, ascending)\r\n th.setAttribute('data-order', ascending ? 'desc' : 'asc')\r\n return\r\n }\r\n\r\n if (AttachmentsTable.options?.mode !== 'self-managed') return\r\n\r\n const editIcon = target.closest('[data-attachment-edit]') as HTMLElement | null\r\n if (editIcon) {\r\n event.preventDefault()\r\n const documentId = Number(editIcon.getAttribute('data-document-id'))\r\n const attachment = Attach.getAllAttachments().find((a) => a.documentId === documentId)\r\n if (attachment) AttachmentsTable.attachInstance?.edit(attachment.description)\r\n return\r\n }\r\n\r\n const reversionIcon = target.closest('[data-attachment-reversion]') as HTMLElement | null\r\n if (reversionIcon) {\r\n event.preventDefault()\r\n const btnDescription = reversionIcon.getAttribute('data-button-description') ?? ''\r\n const btnAccept = reversionIcon.getAttribute('data-button-accept') || null\r\n AttachmentsTable.attachInstance?.add(btnDescription, btnAccept)\r\n return\r\n }\r\n\r\n const deleteIcon = target.closest('[data-attachment-delete]') as HTMLElement | null\r\n if (deleteIcon) {\r\n event.preventDefault()\r\n const documentId = Number(deleteIcon.getAttribute('data-document-id'))\r\n const attachment = Attach.getAllAttachments().find((a) => a.documentId === documentId)\r\n if (attachment) AttachmentsTable.attachInstance?.remove(attachment.description)\r\n return\r\n }\r\n })\r\n\r\n // Event delegation — toolbar (self-managed)\r\n if (AttachmentsTable.options?.mode === 'self-managed') {\r\n context.parentDocument.getElementById(TOOLBAR_ID)?.addEventListener('click', (event: Event) => {\r\n const target = event.target as HTMLElement\r\n\r\n const quickBtn = target.closest('[data-attach-quick]') as HTMLElement | null\r\n if (quickBtn) {\r\n event.preventDefault()\r\n if (!hasPermission('P')) {\r\n FLUIGC.toast({ title: 'Aviso', message: 'Usuário não possui permissão para publicar anexos', type: 'warning' })\r\n return\r\n }\r\n AttachmentsTable.attachInstance?.add(GENERIC_ATTACHMENT_MARKER, AttachmentsTable.options.accept ?? null)\r\n return\r\n }\r\n\r\n const namedBtn = target.closest('[data-attach-named]') as HTMLElement | null\r\n if (namedBtn) {\r\n event.preventDefault()\r\n if (!hasPermission('P')) {\r\n FLUIGC.toast({ title: 'Aviso', message: 'Usuário não possui permissão para publicar anexos', type: 'warning' })\r\n return\r\n }\r\n AttachmentsTable.openNameInputModal(AttachmentsTable.options.accept ?? null)\r\n }\r\n })\r\n\r\n // Drag-and-drop\r\n const container = context.parentDocument.getElementById(CONTAINER_ID)!\r\n container.addEventListener('dragover', (e: DragEvent) => {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n container.classList.add('drag-over')\r\n })\r\n container.addEventListener('dragleave', () => container.classList.remove('drag-over'))\r\n container.addEventListener('drop', (e: DragEvent) => {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n container.classList.remove('drag-over')\r\n const files = e.dataTransfer?.files\r\n if (!files || files.length === 0) return\r\n if (!hasPermission('P')) {\r\n FLUIGC.toast({ title: 'Aviso', message: 'Usuário não possui permissão para publicar anexos', type: 'warning' })\r\n return\r\n }\r\n new DragDropNameModal(files, (entries) => {\r\n entries.forEach(({ file, name }) => {\r\n Attach.uploadBlob(file, name, file.type)\r\n })\r\n })\r\n })\r\n }\r\n\r\n window.addEventListener('jsegd:upload:reset', () => AttachmentsTable.render())\r\n\r\n window.addEventListener('jsegd:upload:success', async (e: Event) => {\r\n const detail = (e as CustomEvent<{\r\n description?: string\r\n source?: AttachmentSource\r\n accept?: string | null\r\n }>).detail\r\n\r\n AttachmentsTable.render()\r\n\r\n if (!detail?.source || AttachmentsTable.options?.mode !== 'self-managed') return\r\n if (!AttachmentsTable.attachInstance) return\r\n\r\n const allAttachments = Attach.getAllAttachments().filter((a) => !isMetadataAttachment(a))\r\n const newAttachment = allAttachments.find(\r\n (a) => a.description?.replace(/_V\\d+$/, '') === detail.description?.replace(/_V\\d+$/, '')\r\n )\r\n\r\n if (!newAttachment || !newAttachment.documentId) return\r\n\r\n const metadata = (await AttachmentMetadataFile.load()) ?? AttachmentMetadataFile.empty()\r\n const record: AttachmentRecord = {\r\n documentId: newAttachment.documentId,\r\n source: detail.source,\r\n buttonDescription: detail.source === 'button' ? detail.description : undefined,\r\n accept: detail.accept ?? null,\r\n workflowSequence: getWorkflowContext().getWorkflowSequence(),\r\n uploadedAt: new Date().toISOString(),\r\n }\r\n\r\n AttachmentMetadataFile.save(\r\n {\r\n ...metadata,\r\n attachments: {\r\n ...metadata.attachments,\r\n [String(newAttachment.documentId)]: record,\r\n },\r\n }\r\n )\r\n })\r\n }\r\n\r\n private static render(): void {\r\n const context = getWorkflowContext()\r\n const container = context.parentDocument.getElementById(CONTAINER_ID)\r\n if (!container) return\r\n\r\n const isSelfManaged = AttachmentsTable.options?.mode === 'self-managed'\r\n const template = isSelfManaged ? TEMPLATE_SELF_MANAGED : TEMPLATE_BUTTONS_ONLY\r\n\r\n const attachments = Attach.getAllAttachments()\r\n .filter((a) => !isMetadataAttachment(a))\r\n .map((attachment) => {\r\n const sanitized = sanitizeAttachmentForDisplay(attachment)\r\n if (!isSelfManaged) {\r\n return { ...sanitized, enableDownload: !isNewProcess() }\r\n }\r\n const btn = AttachmentsTable.resolveButtonRegistration(attachment)\r\n return {\r\n ...sanitized,\r\n enableView: !isNewProcess() && (hasPermission('R') || isOwnAttachment(attachment)),\r\n enableEdit: !attachment.newAttach && canEditAttachment(attachment),\r\n enableReversion: !!btn && hasPermission('P'),\r\n enableDownload: !isNewProcess(),\r\n enableDelete: hasPermission('E') || hasPermission('D'),\r\n buttonDescription: btn?.description ?? '',\r\n buttonAccept: btn?.accept ?? '',\r\n }\r\n })\r\n\r\n container.innerHTML = context.renderTemplate(template, {\r\n attachments,\r\n unpublishedVersion: UNPUBLISHED_VERSION_DISPLAY,\r\n })\r\n }\r\n\r\n private static async hydrateFromMetadata(): Promise<void> {\r\n const metadata = await AttachmentMetadataFile.load()\r\n if (!metadata) return\r\n\r\n for (const [description, record] of Object.entries(metadata.buttons)) {\r\n if (!AttachmentsTable.buttonRegistry.has(description)) {\r\n AttachmentsTable.buttonRegistry.set(description, {\r\n description,\r\n accept: record.accept,\r\n })\r\n }\r\n }\r\n }\r\n\r\n private static async persistMetadata(): Promise<void> {\r\n if (!AttachmentsTable.attachInstance) return\r\n\r\n const current = (await AttachmentMetadataFile.load()) ?? AttachmentMetadataFile.empty()\r\n const buttons: Record<string, { accept: string | null }> = {}\r\n for (const [key, reg] of AttachmentsTable.buttonRegistry.entries()) {\r\n buttons[key] = { accept: reg.accept }\r\n }\r\n\r\n AttachmentMetadataFile.save({ ...current, buttons })\r\n }\r\n\r\n private static openNameInputModal(accept: string | null): void {\r\n FLUIGC.modal(\r\n {\r\n title: 'Nome do anexo',\r\n content: `<div style=\"padding:8px 0\"><label for=\"attach-name-input\" style=\"display:block;margin-bottom:6px\">Informe o nome do arquivo:</label><input type=\"text\" id=\"attach-name-input\" class=\"form-control\" placeholder=\"Ex: Contrato assinado\" maxlength=\"200\"></div>`,\r\n id: 'attach-name-modal',\r\n size: 'small',\r\n showHeader: true,\r\n showFooter: true,\r\n headerActions: [],\r\n headerContent: '',\r\n formModal: false,\r\n actions: [\r\n { label: 'Cancelar', classType: 'btn-default', autoClose: true },\r\n { label: 'Anexar', classType: 'btn-primary', bind: 'data-attach-name-confirm' },\r\n ],\r\n },\r\n () => {}\r\n )\r\n\r\n document.querySelector('[data-attach-name-confirm]')?.addEventListener('click', () => {\r\n const input = document.getElementById('attach-name-input') as HTMLInputElement | null\r\n const rawName = input?.value?.trim() ?? ''\r\n if (!rawName) return\r\n const safeName = sanitizeAttachmentName(rawName)\r\n AttachmentsTable.attachInstance?.add(safeName, accept)\r\n })\r\n }\r\n\r\n private static getRows(): HTMLTableRowElement[] {\r\n return Array.from(\r\n getWorkflowContext().parentDocument.querySelectorAll(`#${CONTAINER_ID} table tbody tr`)\r\n ) as HTMLTableRowElement[]\r\n }\r\n\r\n private static setOrder(rows: HTMLTableRowElement[]): void {\r\n const tbody = getWorkflowContext().parentDocument.querySelector(\r\n `#${CONTAINER_ID} table tbody`\r\n ) as HTMLTableSectionElement | null\r\n if (!tbody) return\r\n rows.forEach((row) => tbody.appendChild(row))\r\n }\r\n\r\n private static sortBy(column: SortColumn, ascending: boolean): void {\r\n const rows = AttachmentsTable.getRows()\r\n rows.sort((a, b) => {\r\n const valueA = AttachmentsTable.getCellValue(a, column)\r\n const valueB = AttachmentsTable.getCellValue(b, column)\r\n if (valueA && valueB) {\r\n return ascending ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA)\r\n }\r\n return 0\r\n })\r\n AttachmentsTable.setOrder(rows)\r\n }\r\n\r\n private static getCellValue(row: HTMLTableRowElement, column: SortColumn): string | undefined {\r\n switch (column) {\r\n case 'title':\r\n return row.querySelector('[data-attachment-open]')?.closest('td')?.textContent?.trim()\r\n case 'user':\r\n return row.querySelector('td:nth-child(4)')?.textContent?.trim()\r\n case 'date':\r\n return row.querySelector('td:nth-child(5)')?.textContent?.trim()\r\n case 'activity':\r\n return row.querySelector('td:nth-child(6)')?.textContent?.trim()\r\n }\r\n }\r\n}\r\n\r\ntype SortColumn = 'title' | 'user' | 'date' | 'activity'\r\n\r\n","import html from './assets/index.html'\r\nimport styles from './assets/styles.css'\r\nimport { Attach } from './attach'\r\nimport { GENERIC_ATTACHMENT_MARKER } from './attachment.constants'\r\nimport './attachment.events'\r\nimport { getGenericAttachmentDescriptions } from './attachment.utils'\r\nimport { AttachmentsTable } from './attachmentsTable'\r\n\r\n/**\r\n * Implementa um botão para gerenciar anexos\r\n * @hideconstructor\r\n * @example\r\n * ```html\r\n * <attachment-button description=\"CONTRATO\"></attachment-button>\r\n * ```\r\n */\r\nexport class AttachButton extends HTMLElement {\r\n /**\r\n * Descrição do tipo de anexo gerenciado pelo botão.\r\n * Quando vazio, um modal é exibido para o usuário informar a descrição no momento do upload.\r\n * @defaultValue `''`\r\n */\r\n description: string\r\n\r\n /**\r\n * Filtro de tipos de arquivo aceitos pelo seletor nativo (ex: `\".pdf,.docx\"`).\r\n * `null` aceita qualquer tipo de arquivo.\r\n */\r\n accept: string | null\r\n\r\n noaddbutton: string | null = null\r\n noviewbutton: string | null = null\r\n noeditbutton: string | null = null\r\n nodeletebutton: string | null = null\r\n\r\n private handleSuccess: EventListener = () => {\r\n const button = this.shadowRoot?.querySelector('.dropdown-button') as HTMLButtonElement\r\n if (button) {\r\n button.style.color = 'rgb(255, 255, 255)'\r\n button.style.backgroundColor = 'rgb(26, 184, 63)'\r\n }\r\n }\r\n\r\n private handleError: EventListener = () => {\r\n const button = this.shadowRoot?.querySelector('.dropdown-button') as HTMLButtonElement\r\n if (button) {\r\n button.style.color = 'rgb(255, 255, 255)'\r\n button.style.backgroundColor = 'rgb(204, 61, 61)'\r\n }\r\n }\r\n\r\n private handleDefault: EventListener = () => {\r\n const button = this.shadowRoot?.querySelector('.dropdown-button') as HTMLButtonElement\r\n if (button) {\r\n button.style.color = 'rgb(85, 85, 85)'\r\n button.style.backgroundColor = 'rgb(255, 255, 255)'\r\n }\r\n }\r\n\r\n constructor() {\r\n super()\r\n const shadow = this.attachShadow({ mode: 'open' })\r\n const style = document.createElement('style')\r\n style.innerHTML = styles\r\n const template = document.createElement('template')\r\n template.innerHTML = html\r\n shadow.appendChild(style)\r\n\r\n shadow.appendChild(template.content.cloneNode(true))\r\n this.description = ''\r\n this.accept = null\r\n }\r\n\r\n static get observedAttributes() {\r\n return ['description', 'accept', 'noaddbutton', 'noviewbutton', 'noeditbutton', 'nodeletebutton']\r\n }\r\n\r\n attributeChangedCallback(name: string, _oldValue: string, newValue: string) {\r\n if (!this.isConnected) return\r\n switch (name) {\r\n case 'description':\r\n this.description = newValue || ''\r\n break\r\n case 'accept':\r\n this.accept = newValue\r\n break\r\n case 'noaddbutton':\r\n this.noaddbutton = newValue\r\n break\r\n case 'noviewbutton':\r\n this.noviewbutton = newValue\r\n break\r\n case 'noeditbutton':\r\n this.noeditbutton = newValue ?? 'true'\r\n break\r\n case 'nodeletebutton':\r\n this.nodeletebutton = newValue\r\n break\r\n }\r\n this.displayButtons()\r\n }\r\n\r\n disconnectedCallback() {\r\n parent.removeEventListener('jsegd:upload:success', this.handleSuccess)\r\n parent.removeEventListener('jsegd:upload:error', this.handleError)\r\n parent.removeEventListener('jsegd:upload:reset', this.handleDefault)\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n connectedCallback() {\r\n /**\r\n * Botões\r\n */\r\n this.noaddbutton = this.getAttribute('noAddButton')\r\n this.noviewbutton = this.getAttribute('noViewButton')\r\n this.noeditbutton = this.getAttribute('noEditButton') ?? 'true'\r\n this.nodeletebutton = this.getAttribute('noDeleteButton')\r\n this.displayButtons()\r\n /**\r\n *\r\n */\r\n this.accept = this.getAttribute('accept')\r\n this.description = this.getAttribute('description') || ''\r\n const attachment = Attach.getInstance()\r\n this.addButton(attachment)\r\n this.viewButton(attachment)\r\n this.editButton(attachment)\r\n this.removeButton(attachment)\r\n parent.addEventListener('jsegd:upload:success', this.handleSuccess)\r\n parent.addEventListener('jsegd:upload:error', this.handleError)\r\n parent.addEventListener('jsegd:upload:reset', this.handleDefault)\r\n AttachmentsTable.registerButton({ description: this.description, accept: this.accept ?? null })\r\n }\r\n\r\n private displayButtons() {\r\n if (this.noaddbutton !== 'true') {\r\n this.shadowRoot?.querySelector('#attach')?.parentElement?.classList.remove('fs-display-none')\r\n }\r\n if (this.noviewbutton !== 'true') {\r\n this.shadowRoot?.querySelector('#view')?.parentElement?.classList.remove('fs-display-none')\r\n }\r\n if (this.noeditbutton !== 'true') {\r\n this.shadowRoot?.querySelector('#edit')?.parentElement?.classList.remove('fs-display-none')\r\n }\r\n if (this.nodeletebutton !== 'true') {\r\n this.shadowRoot?.querySelector('#remove')?.parentElement?.classList.remove('fs-display-none')\r\n }\r\n }\r\n\r\n private addButton(attachment: Attach) {\r\n this.shadowRoot?.querySelector('#attach')?.addEventListener('click', (e) => {\r\n e.preventDefault()\r\n if (!this.description) {\r\n this.showModal()\r\n } else {\r\n attachment.add(this.description, this.accept)\r\n }\r\n })\r\n }\r\n private viewButton(attachment: Attach) {\r\n this.shadowRoot?.querySelector('#view')?.addEventListener('click', (e) => {\r\n e.preventDefault()\r\n attachment.view(!this.description ? GENERIC_ATTACHMENT_MARKER : this.description)\r\n })\r\n }\r\n private editButton(attachment: Attach) {\r\n this.shadowRoot?.querySelector('#edit')?.addEventListener('click', (e) => {\r\n e.preventDefault()\r\n attachment.edit(!this.description ? GENERIC_ATTACHMENT_MARKER : this.description)\r\n })\r\n }\r\n\r\n private removeButton(attachment: Attach) {\r\n this.shadowRoot?.querySelector('#remove')?.addEventListener('click', (e) => {\r\n e.preventDefault()\r\n attachment.remove(!this.description ? GENERIC_ATTACHMENT_MARKER : this.description)\r\n })\r\n }\r\n\r\n private showModal() {\r\n const template = `\r\n <div class=\"row\" style=\"height: 200px;\">\r\n <div class=\"col-xs-12 col-sm-12 col-md-12 col-lg-12\">\r\n <div class=\"form-group\">\r\n <label for=\"attach_description\">Descrição do anexo</label>\r\n <input type=\"text\" name=\"attach_description\" id=\"attach_description\"\r\n class=\"form-control\" />\r\n </div>\r\n </div>\r\n </div>\r\n `\r\n\r\n const attachModal = parent.FLUIGC.modal(\r\n {\r\n title: 'Informe a descrição do anexo',\r\n content: template,\r\n id: 'attachModal',\r\n showHeader: true,\r\n showFooter: true,\r\n actions: [\r\n {\r\n label: 'Salvar',\r\n bind: 'data-save-modal',\r\n },\r\n {\r\n label: 'Cancelar',\r\n bind: 'data-cancel-modal',\r\n },\r\n ],\r\n headerActions: [],\r\n headerContent: '',\r\n size: 'large',\r\n formModal: false,\r\n },\r\n (err, _data) => {\r\n if (!err) {\r\n parent.FLUIGC.autocomplete(\r\n '#attach_description',\r\n {\r\n source: (q: string, cb: (results: { description: string }[]) => void) => {\r\n const matches = getGenericAttachmentDescriptions()\r\n .filter((d) => d.toLowerCase().includes(q.toLowerCase()))\r\n .map((description) => ({ description }))\r\n cb(matches)\r\n },\r\n highlight: true,\r\n displayKey: 'description',\r\n tagClass: 'tag-gray',\r\n type: 'autocomplete',\r\n },\r\n () => {}\r\n )\r\n\r\n parent.document.querySelector('[data-save-modal]')?.addEventListener('click', () => {\r\n const { value } = parent.document.querySelector('#attach_description') as HTMLInputElement\r\n if (!value) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Informe a descrição do anexo',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n const description = `${value.toUpperCase()}_Z_`\r\n attachModal.remove()\r\n const attachment = Attach.getInstance()\r\n attachment.add(description, this.accept)\r\n })\r\n\r\n parent.document.querySelector('[data-cancel-modal]')?.addEventListener('click', () => {\r\n attachModal.remove()\r\n })\r\n }\r\n }\r\n )\r\n }\r\n}\r\n\r\nif (!customElements.get('attachment-button')) {\r\n customElements.define('attachment-button', AttachButton)\r\n}\r\n",":host {\n display: inline-block;\n position: relative;\n font-family: Arial, sans-serif;\n}\n\n.dropdown {\n position: relative;\n display: inline-block;\n}\n\n.dropdown-button {\n background-color: #fff;\n color: #555;\n padding: 6px 10px;\n font-size: 14px;\n border: 1px solid #ccc;\n cursor: pointer;\n border-radius: 0 5px 5px 0;\n display: flex;\n align-items: center;\n gap: 5px;\n height: 32px;\n}\n\n.dropdown-button:hover {\n color: #555;\n border-color: #adadad;\n background-color: #e6e6e6;\n}\n\n.dropdown-menu {\n display: none;\n position: absolute;\n top: 100%;\n right: 0;\n background-color: #fff;\n box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);\n min-width: 150px;\n list-style: none;\n padding: 0;\n margin: 0;\n border-radius: 0 0 2px 2px;\n}\n\n.dropdown-menu a {\n display: flex;\n gap: 10px;\n padding: 5px;\n box-sizing: border-box;\n width: 100%;\n text-decoration: none;\n color: #333;\n font-size: 14px;\n justify-content: end;\n align-items: center;\n line-height: 1.5rem;\n}\n\n.dropdown-menu a:hover {\n background-color: #f1f1f1;\n color: #1d1b1b;\n}\n\n.dropdown:hover .dropdown-menu {\n display: block;\n z-index: 9999;\n}\n\n.fs-display-none {\n display: none !important;\n}\r\n","export type FieldError = {\r\n field?: HTMLElement | null\r\n errorMessage: string\r\n}\r\n\r\nexport class BeforeSendValidate {\r\n private static clearAllErrors(): void {\r\n const allGroups = document.querySelectorAll('[data-group]')\r\n allGroups.forEach((group) => {\r\n group.classList.remove('has-error')\r\n const helperElement = group.querySelector('[data-helper]')\r\n if (helperElement) {\r\n helperElement.classList.add('fs-display-none')\r\n }\r\n })\r\n }\r\n\r\n static throwValidationError(fields: FieldError[]): never {\r\n if (!fields || fields.length === 0) {\r\n throw new Error('<div class=\"alert alert-danger\" role=\"alert\">Erro de validação</div>')\r\n }\r\n this.clearAllErrors()\r\n\r\n fields.forEach(({ field, errorMessage }) => {\r\n if (field) {\r\n const group = field.closest('[data-group]')\r\n if (group) {\r\n group.classList.add('has-error')\r\n const helperElement = group.querySelector('[data-helper]')\r\n if (helperElement) {\r\n helperElement.classList.remove('fs-display-none')\r\n helperElement.textContent = errorMessage\r\n }\r\n\r\n const clearErrorHandler = () => {\r\n group.classList.remove('has-error')\r\n if (helperElement) {\r\n helperElement.classList.add('fs-display-none')\r\n helperElement.textContent = ''\r\n }\r\n }\r\n\r\n group.addEventListener('click', clearErrorHandler, { once: true })\r\n group.addEventListener('focusin', clearErrorHandler, { once: true })\r\n }\r\n }\r\n })\r\n const validMessages = fields\r\n .filter(({ errorMessage }) => errorMessage && errorMessage.trim())\r\n .map(({ errorMessage }) => errorMessage.replace(/</g, '<').replace(/>/g, '>'))\r\n\r\n if (validMessages.length === 0) {\r\n throw new Error('<div class=\"alert alert-danger\" role=\"alert\">Erro de validação</div>')\r\n }\r\n const combinedMessages = validMessages.join('<br>')\r\n throw new Error(`<div class=\"alert alert-danger\" role=\"alert\">${combinedMessages}</div>`)\r\n }\r\n}\r\n","import type { ProcessCompletionMessage } from './interfaces/IWorkflowViewHooks'\r\n\r\n\r\nexport type HooksMap = {\r\n beforeValidate: Array<() => void | Promise<void>>\r\n afterValidate: Array<() => void | Promise<void>>\r\n onMoveSuccess: Array<() => void | Promise<void>>\r\n onMoveError: Array<() => void | Promise<void>>\r\n onCompletionLinkAdd: Array<(message: ProcessCompletionMessage) => void | Promise<void>>\r\n}\r\n\r\n/**\r\n * Registro mutável de hooks compartilhado entre `WorkflowViewPatcher` e `sendRequestEvent`.\r\n *\r\n * @internal\r\n */\r\nexport const hooksMap: HooksMap = {\r\n beforeValidate: [],\r\n afterValidate: [],\r\n onMoveSuccess: [],\r\n onMoveError: [],\r\n onCompletionLinkAdd: [],\r\n}\r\n","import { hooksMap } from '../hooks-registry'\r\nimport { getProcessInfo } from '../../process-context'\r\n\r\n/**\r\n * Override de `sendRequestEvent()` do widget de processo.\r\n * Executa os hooks `beforeValidate` e `afterValidate` em sequência antes de enviar a solicitação.\r\n * Reabilita os botões de ação em caso de erro ou quando a validação falha.\r\n */\r\nexport async function sendRequestEvent(this: ECM_WKFView) {\r\n const enableButtons = () => {\r\n this.enableSendButton()\r\n this.enableActionButtons()\r\n }\r\n\r\n // Executa todos os beforeValidate em sequência\r\n // Primeira exceção cancela o envio e reabilita os botões\r\n for (const fn of hooksMap.beforeValidate) {\r\n try {\r\n const result = fn()\r\n if (result instanceof Promise) {\r\n await result\r\n }\r\n } catch (e) {\r\n enableButtons()\r\n return\r\n }\r\n }\r\n\r\n const nextActivityElement = document.getElementById('nextActivity') as HTMLSelectElement | HTMLInputElement | null\r\n const nextActivity = nextActivityElement?.value || this.selectActivity()\r\n\r\n const isValid = await this.callFormFunction('beforeSendValidate', [getProcessInfo().getWorkflowSequence(), nextActivity])\r\n if (!isValid) {\r\n enableButtons()\r\n return\r\n }\r\n\r\n // Executa todos os afterValidate em sequência\r\n // Primeira exceção cancela o envio e reabilita os botões\r\n for (const fn of hooksMap.afterValidate) {\r\n try {\r\n const result = fn()\r\n if (result instanceof Promise) {\r\n await result\r\n }\r\n } catch (e) {\r\n enableButtons()\r\n return\r\n }\r\n }\r\n this.disableActionButtons()\r\n this.sendRequest(false, false)\r\n}\r\n","import { sendRequestEvent } from './overrides/send-request'\r\nimport type { ProcessCompletionMessage } from './interfaces/IWorkflowViewHooks'\r\nimport { hooksMap, type HooksMap } from './hooks-registry'\r\n\r\n/**\r\n * Mapa de substituições que serão aplicadas ao widget nativo de processo.\r\n */\r\nconst overrides = {\r\n sendRequestEvent: sendRequestEvent,\r\n}\r\n\r\n/**\r\n * Tipo do mapa de substituições.\r\n */\r\ntype OverrideMap = typeof overrides\r\n\r\n/**\r\n * Classe utilitária para substituir métodos no widget nativo de processo.\r\n *\r\n * Preserva os métodos originais para permitir reversão via `restore()`.\r\n *\r\n * @example\r\n * ```typescript\r\n * // Aguardar inicialização do widget de processo\r\n * await WorkflowViewPatcher.init()\r\n *\r\n * // Aplicar todos os patches registrados\r\n * WorkflowViewPatcher.patchAll()\r\n *\r\n * // Registrar hooks\r\n * WorkflowViewPatcher.addBeforeValidate(async () => {\r\n * console.log('Antes da validação')\r\n * })\r\n *\r\n * WorkflowViewPatcher.addAfterValidate(async () => {\r\n * console.log('Após a validação')\r\n * })\r\n * ```\r\n */\r\nexport class WorkflowViewPatcher {\r\n private static isInitialized = false\r\n private static isInitializing = false\r\n private static originalMethods: Partial<Record<keyof OverrideMap, Function>> = {}\r\n\r\n /**\r\n * Inicializa o patcher aguardando o carregamento do widget de processo no frame pai.\r\n *\r\n * Chamadas repetidas retornam imediatamente se já inicializado.\r\n *\r\n * @param timeout - Tempo máximo de espera em ms (padrão: 5000ms)\r\n * @returns Promise<void>\r\n *\r\n * @throws {Error} Se outra chamada a `init()` já estiver em progresso\r\n * @throws {Error} Se o widget `ECM_WKFView` não estiver disponível após o timeout\r\n *\r\n * @example\r\n * ```typescript\r\n * await WorkflowViewPatcher.init()\r\n * WorkflowViewPatcher.patchAll()\r\n * ```\r\n */\r\n static async init(timeout = 5000): Promise<void> {\r\n if (this.isInitialized) return\r\n if (this.isInitializing) {\r\n throw new Error('[WorkflowViewPatcher] init() já está em progresso')\r\n }\r\n\r\n this.isInitializing = true\r\n const startTime = Date.now()\r\n\r\n while (!parent.ECM_WKFView) {\r\n if (Date.now() - startTime > timeout) {\r\n this.isInitializing = false\r\n throw new Error('[WorkflowViewPatcher] Timeout: ECM_WKFView não disponível no contexto pai')\r\n }\r\n await new Promise((resolve) => setTimeout(resolve, 100))\r\n }\r\n\r\n this.isInitializing = false\r\n this.isInitialized = true\r\n }\r\n\r\n /**\r\n * Aplica o patch de um override específico no widget de processo.\r\n *\r\n * Salva o método original antes de sobrescrever, permitindo reversão via `restore()`.\r\n *\r\n * @param attr - Nome do método a ser substituído\r\n * @throws {Error} Se `init()` não tiver sido chamado antes\r\n * @throws {Error} Se o override não estiver registrado no mapa de substituições\r\n */\r\n static patch(attr: keyof OverrideMap) {\r\n if (!this.isInitialized) {\r\n throw new Error('[WorkflowViewPatcher] Chame init() antes de aplicar patches')\r\n }\r\n if (!parent.ECM_WKFView) return\r\n\r\n const fn = overrides[attr]\r\n if (!fn) {\r\n throw new Error(`[WorkflowViewPatcher] Override '${attr}' não registrado no mapa de substituições`)\r\n }\r\n if (!this.originalMethods[attr]) {\r\n this.originalMethods[attr] = parent.ECM_WKFView[attr]\r\n }\r\n parent.ECM_WKFView[attr] = fn.bind(parent.ECM_WKFView)\r\n }\r\n\r\n /**\r\n * Aplica patches para múltiplos métodos do widget de processo.\r\n *\r\n * @param attrs - Array com nomes dos métodos a serem substituídos\r\n * @throws {Error} Se `init()` não tiver sido chamado antes\r\n */\r\n static patchMany(attrs: (keyof OverrideMap)[]) {\r\n if (!this.isInitialized) {\r\n throw new Error('[WorkflowViewPatcher] Chame init() antes de aplicar patches')\r\n }\r\n attrs.forEach((attr) => this.patch(attr))\r\n }\r\n\r\n /**\r\n * Aplica todos os patches registrados no mapa de substituições.\r\n * @throws {Error} Se `init()` não tiver sido chamado antes\r\n */\r\n static patchAll() {\r\n if (!this.isInitialized) {\r\n throw new Error('[WorkflowViewPatcher] Chame init() antes de aplicar patches')\r\n }\r\n if (parent.ECM_WKFView) {\r\n Object.keys(overrides).forEach((attr) => {\r\n this.patch(attr as keyof OverrideMap)\r\n })\r\n }\r\n }\r\n\r\n /**\r\n * Restaura todos os métodos do widget para as implementações originais.\r\n *\r\n * Deve ser chamado ao desmontar o componente em SPAs, para evitar que os patches\r\n * persistam além do ciclo de vida do formulário. Também zera os flags de estado\r\n * interno, permitindo reinicialização via `init()`.\r\n *\r\n * @example\r\n * ```typescript\r\n * // Ao desmontar o formulário\r\n * WorkflowViewPatcher.restore()\r\n * ```\r\n */\r\n static restore() {\r\n if (!parent.ECM_WKFView) return\r\n\r\n Object.entries(this.originalMethods).forEach(([attr, originalFn]) => {\r\n const k = attr as keyof OverrideMap\r\n if (originalFn !== undefined) {\r\n ;(parent.ECM_WKFView as any)[k] = originalFn\r\n } else {\r\n delete (parent.ECM_WKFView as any)[k]\r\n }\r\n })\r\n\r\n this.originalMethods = {}\r\n this.isInitialized = false\r\n this.isInitializing = false\r\n hooksMap.beforeValidate.length = 0\r\n hooksMap.afterValidate.length = 0\r\n hooksMap.onMoveSuccess.length = 0\r\n hooksMap.onMoveError.length = 0\r\n hooksMap.onCompletionLinkAdd.length = 0\r\n }\r\n\r\n /**\r\n * Acessa a lista interna de hooks para um tipo específico.\r\n * Usado por `sendRequestEvent` para executar os hooks em sequência.\r\n *\r\n * @internal\r\n */\r\n static getHooks<K extends keyof HooksMap>(key: K): HooksMap[K] {\r\n return hooksMap[key]\r\n }\r\n\r\n /**\r\n * Registra uma função executada ANTES da validação principal do widget.\r\n *\r\n * Múltiplas chamadas acumulam handlers — nenhuma sobrescreve a anterior.\r\n * Se o handler lançar exceção (sync ou async), o envio é cancelado e os botões são reabilitados.\r\n *\r\n * @param fn - Função a ser executada (pode ser async).\r\n *\r\n * @example\r\n * ```typescript\r\n * WorkflowViewPatcher.addBeforeValidate(async () => {\r\n * const value = getValue('campo_obrigatorio')\r\n * if (!value) {\r\n * throw new Error('Campo obrigatório não preenchido')\r\n * }\r\n * })\r\n * ```\r\n */\r\n static addBeforeValidate(fn: () => void | Promise<void>) {\r\n hooksMap.beforeValidate.push(fn)\r\n }\r\n\r\n /**\r\n * Registra uma função executada APÓS `beforeSendValidate` retornar `true`,\r\n * mas ANTES do envio efetivo da solicitação.\r\n *\r\n * Múltiplas chamadas acumulam handlers — nenhuma sobrescreve a anterior.\r\n * Se o handler lançar exceção (sync ou async), o envio é cancelado e os botões são reabilitados.\r\n *\r\n * @param fn - Função a ser executada (pode ser async).\r\n *\r\n * @example\r\n * ```typescript\r\n * WorkflowViewPatcher.addAfterValidate(async () => {\r\n * console.log('Validação concluída, preparando envio...')\r\n * await salvarDadosLocais()\r\n * })\r\n * ```\r\n */\r\n static addAfterValidate(fn: () => void | Promise<void>) {\r\n hooksMap.afterValidate.push(fn)\r\n }\r\n\r\n /**\r\n * Registra uma função executada quando a movimentação do processo é concluída com sucesso.\r\n *\r\n * Múltiplas chamadas acumulam handlers — nenhuma sobrescreve a anterior.\r\n *\r\n * @param fn - Função callback executada em caso de sucesso (pode ser async).\r\n *\r\n * @example\r\n * ```typescript\r\n * WorkflowViewPatcher.addOnMoveSuccess(() => {\r\n * console.log('Processo movimentado com sucesso')\r\n * })\r\n * ```\r\n */\r\n static addOnMoveSuccess(fn: () => void | Promise<void>) {\r\n hooksMap.onMoveSuccess.push(fn)\r\n }\r\n\r\n /**\r\n * Registra uma função executada quando ocorre erro na movimentação do processo.\r\n *\r\n * Múltiplas chamadas acumulam handlers — nenhuma sobrescreve a anterior.\r\n *\r\n * @param fn - Função callback executada em caso de erro (pode ser async).\r\n *\r\n * @example\r\n * ```typescript\r\n * WorkflowViewPatcher.addOnMoveError(() => {\r\n * console.error('Erro ao movimentar processo')\r\n * })\r\n * ```\r\n */\r\n static addOnMoveError(fn: () => void | Promise<void>) {\r\n hooksMap.onMoveError.push(fn)\r\n }\r\n\r\n /**\r\n * Registra uma função para manipular os links da página de conclusão da movimentação.\r\n *\r\n * Múltiplas chamadas acumulam handlers — nenhuma sobrescreve a anterior.\r\n *\r\n * @param fn - Função que recebe o objeto de conclusão e pode adicionar ou modificar links (pode ser async).\r\n *\r\n * @example\r\n * ```typescript\r\n * WorkflowViewPatcher.addOnCompletionLinkAdd((message: ProcessCompletionMessage) => {\r\n * message.links.push({ description: 'Voltar ao início', href: '/inicio' })\r\n * })\r\n * ```\r\n */\r\n static addOnCompletionLinkAdd(fn: (message: ProcessCompletionMessage) => void | Promise<void>) {\r\n hooksMap.onCompletionLinkAdd.push(fn)\r\n }\r\n}\r\n","/**\r\n * Converte snake_case para camelCase.\r\n * @example snakeToCamel('primeiro_pagamento') → 'primeiroPagamento'\r\n * @example snakeToCamel('contrato_indice') → 'contratoIndice'\r\n */\r\nexport function snakeToCamel(str: string): string {\r\n return str.replace(/_([a-z])/g, (_, letter: string) => letter.toUpperCase())\r\n}\r\n\r\n/**\r\n * Converte camelCase para snake_case.\r\n * @example camelToSnake('primeiroPagamento') → 'primeiro_pagamento'\r\n * @example camelToSnake('contratoIndice') → 'contrato_indice'\r\n */\r\nexport function camelToSnake(str: string): string {\r\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)\r\n}\r\n","import type { IFormRepository } from './IFormRepository'\r\nimport { snakeToCamel, camelToSnake } from './nameUtils'\r\n\r\ndeclare function wdkAddChild(tableName: string, skipLoadZoom?: boolean): number\r\n\r\n/**\r\n * Adapter de produção que isola o acesso ao DOM do formulário BPM e às\r\n * funções globais `wdkAddChild`/`fnWdkRemoveChild` (definidas em `wdkdetail.js`).\r\n *\r\n * Segue o mesmo padrão de fronteira estabelecido por `process-context/` —\r\n * este é o único arquivo autorizado a referenciar as globais do formulário BPM.\r\n */\r\nexport class BpmFormRepository implements IFormRepository {\r\n load<T>(section: string): Partial<T> {\r\n const prefix = `${section}_`\r\n const result: Record<string, unknown> = {}\r\n const fields = document.querySelectorAll<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(\r\n `input[name^=\"${prefix}\"], select[name^=\"${prefix}\"], textarea[name^=\"${prefix}\"]`\r\n )\r\n fields.forEach((el) => {\r\n const domName = el.name\r\n if (!domName || domName.includes('___')) return\r\n const camelKey = snakeToCamel(domName.slice(prefix.length))\r\n if (el instanceof HTMLInputElement && el.type === 'checkbox') {\r\n result[camelKey] = el.checked\r\n } else {\r\n result[camelKey] = el.value\r\n }\r\n })\r\n return result as Partial<T>\r\n }\r\n\r\n loadTable<T>(tableName: string): T[] {\r\n const rows = document.querySelectorAll<HTMLTableRowElement>(\r\n `table[tablename=\"${tableName}\"] tbody tr:not([style*=\"display: none\"]):not([style*=\"display:none\"])`\r\n )\r\n const result: T[] = []\r\n rows.forEach((row) => {\r\n const rowData: Record<string, unknown> = {}\r\n const fields = row.querySelectorAll<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(\r\n 'input, select, textarea'\r\n )\r\n fields.forEach((el) => {\r\n if (!el.name) return\r\n const baseName = el.name.includes('___') ? el.name.substring(0, el.name.lastIndexOf('___')) : el.name\r\n if (el instanceof HTMLInputElement && el.type === 'checkbox') {\r\n rowData[baseName] = el.checked\r\n } else {\r\n rowData[baseName] = el.value\r\n }\r\n })\r\n result.push(rowData as T)\r\n })\r\n return result\r\n }\r\n\r\n save<T>(section: string, data: Partial<T>): void {\r\n const prefix = `${section}_`\r\n Object.entries(data as Record<string, unknown>).forEach(([camelKey, value]) => {\r\n const domName = `${prefix}${camelToSnake(camelKey)}`\r\n const el = document.querySelector<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(\r\n `[name=\"${domName}\"]`\r\n )\r\n if (!el) return\r\n if (el instanceof HTMLInputElement && el.type === 'checkbox') {\r\n el.checked = Boolean(value)\r\n } else {\r\n el.value = String(value ?? '')\r\n }\r\n })\r\n }\r\n\r\n saveTable<T>(tableName: string, rows: T[]): void {\r\n // Remove linhas existentes — equivalente a clearTables() de wdkdetail.js\r\n document.querySelectorAll<HTMLTableRowElement>(\r\n `table[tablename=\"${tableName}\"] tbody tr`\r\n ).forEach((row) => {\r\n if ((row as HTMLElement).style.display !== 'none') {\r\n row.remove()\r\n }\r\n })\r\n\r\n rows.forEach((rowData) => {\r\n const rowId = wdkAddChild(tableName, false)\r\n Object.entries(rowData as Record<string, unknown>).forEach(([key, value]) => {\r\n const el = document.querySelector<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(\r\n `[name=\"${key}___${rowId}\"]`\r\n )\r\n if (!el) return\r\n if (el instanceof HTMLInputElement && el.type === 'checkbox') {\r\n el.checked = Boolean(value)\r\n } else {\r\n el.value = String(value ?? '')\r\n }\r\n })\r\n })\r\n }\r\n}\r\n","import type { IFormRepository } from './IFormRepository'\r\nimport { snakeToCamel, camelToSnake } from './nameUtils'\r\n\r\n/**\r\n * Implementação em memória de `IFormRepository` para uso em testes unitários.\r\n * Não depende de DOM, jQuery ou da plataforma — permite testar Presenters em isolamento.\r\n *\r\n * Aplica a mesma lógica de prefixo e conversão de `BpmFormRepository`: armazena\r\n * internamente com o nome DOM completo (`{section}_{snake_case}`) e converte para\r\n * camelCase ao retornar — garantindo que os testes reflitam o comportamento real.\r\n *\r\n * @example\r\n * const repo = new MockFormRepository()\r\n * repo.save('vigencia', { prazo: '12', tipoDePrazo: 'Meses' })\r\n * const data = repo.load<Vigencia>('vigencia')\r\n * // data.prazo === '12'\r\n * // data.tipoDePrazo === 'Meses'\r\n *\r\n * @example\r\n * const repo = new MockFormRepository()\r\n * repo.save('imovel', { cep: '01310100', logradouro: 'Av. Paulista' })\r\n * repo.save('contrato', { indice: 'IGPM', primeiroPagamento: '2026-02-01' })\r\n * // imovel_cep e contrato_indice são domínios distintos — sem colisão\r\n */\r\nexport class MockFormRepository implements IFormRepository {\r\n /** Armazena valores com chave no formato DOM completo: `{section}_{snake_case}`. */\r\n private readonly store = new Map<string, unknown>()\r\n private readonly tables = new Map<string, unknown[]>()\r\n\r\n load<T>(section: string): Partial<T> {\r\n const prefix = `${section}_`\r\n const result: Record<string, unknown> = {}\r\n for (const [domName, value] of this.store.entries()) {\r\n if (domName.startsWith(prefix)) {\r\n const camelKey = snakeToCamel(domName.slice(prefix.length))\r\n result[camelKey] = value\r\n }\r\n }\r\n return result as Partial<T>\r\n }\r\n\r\n loadTable<T>(tableName: string): T[] {\r\n return (this.tables.get(tableName) ?? []) as T[]\r\n }\r\n\r\n save<T>(section: string, data: Partial<T>): void {\r\n const prefix = `${section}_`\r\n Object.entries(data as Record<string, unknown>).forEach(([camelKey, value]) => {\r\n this.store.set(`${prefix}${camelToSnake(camelKey)}`, value)\r\n })\r\n }\r\n\r\n saveTable<T>(tableName: string, rows: T[]): void {\r\n this.tables.set(tableName, [...rows])\r\n }\r\n\r\n /**\r\n * Limpa todo o estado interno — campos e tabelas.\r\n * Ideal para uso em `beforeEach` nos testes.\r\n */\r\n reset(): void {\r\n this.store.clear()\r\n this.tables.clear()\r\n }\r\n}\r\n","/**\r\n * Lê campos do formulário por mapeamento explícito `{ propriedadeModelo: nomeDOM }`.\r\n *\r\n * Utilitário para **processos legados** cujos campos não seguem a convenção\r\n * `{domínio}_{atributo}` — use quando o nome DOM não pode ser alterado sem\r\n * migração de dados no banco EGD.\r\n *\r\n * Novos processos devem usar `IFormRepository.load(section)` diretamente.\r\n *\r\n * @param fieldMap Mapeamento de propriedade do modelo → nome do campo no DOM\r\n * @returns Objeto parcial com os valores lidos, chaveado pelos atributos do modelo\r\n *\r\n * @example\r\n * ```typescript\r\n * // Processo legado: campos com sufixo em vez de prefixo\r\n * import { loadFields } from 'jsegd-bpm'\r\n *\r\n * interface Solicitante {\r\n * nome: string\r\n * email: string\r\n * }\r\n *\r\n * const dados = loadFields<Solicitante>({\r\n * nome: 'nome_solicitante',\r\n * email: 'email_solicitante',\r\n * })\r\n * // dados.nome === valor de input[name=\"nome_solicitante\"]\r\n * ```\r\n */\r\nexport function loadFields<T>(fieldMap: { [K in keyof T]?: string }): Partial<T> {\r\n const result: Partial<T> = {}\r\n for (const modelKey of Object.keys(fieldMap) as (keyof T)[]) {\r\n const domName = fieldMap[modelKey]\r\n if (!domName) continue\r\n const el = document.querySelector<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(\r\n `[name=\"${domName}\"]`\r\n )\r\n if (!el) continue\r\n result[modelKey] = (\r\n el instanceof HTMLInputElement && el.type === 'checkbox' ? el.checked : el.value\r\n ) as T[typeof modelKey]\r\n }\r\n return result\r\n}\r\n","import type { WorkflowModuleDefinition, WorkflowActivityDefinition, WorkflowConfig } from './types'\r\n\r\n/**\r\n * Define a configuração de workflow de um projeto BPM a partir de uma\r\n * declaração única de módulos e atividades. O tipo `ModuleId` é inferido\r\n * automaticamente do array de módulos — nenhum type alias manual é necessário.\r\n *\r\n * @param config Objeto com `modules` (definições de módulo) e `activities` (políticas por atividade)\r\n * @returns Configuração tipada pronta para uso em `resolveWorkflowScreen` e `extractCompletedStages`\r\n *\r\n * @example\r\n * const workflowConfig = defineWorkflowConfig({\r\n * modules: [\r\n * { moduleId: 'solicitante', label: 'Dados Iniciais', icon: 'file', order: 1,\r\n * showInNavigation: true, renderContent: true, contentIncludePath: 'solicitante.html' },\r\n * { moduleId: 'juridico', label: 'Jurídico', icon: 'gavel', order: 2,\r\n * showInNavigation: true, renderContent: true, contentIncludePath: 'juridico.html' },\r\n * ],\r\n * activities: [\r\n * { sequence: 9, description: 'Solicitação inicial', kind: 'human', stage: 'solicitacao',\r\n * modules: { visible: ['solicitante'], editable: ['solicitante'], active: 'solicitante' } },\r\n * { sequence: 88, description: 'Roteamento', kind: 'routing' },\r\n * ]\r\n * } as const)\r\n * // Tipo de ModuleId inferido automaticamente: 'solicitante' | 'juridico'\r\n */\r\nexport function defineWorkflowConfig<\r\n const M extends readonly (WorkflowModuleDefinition & { moduleId: string })[]\r\n>(config: {\r\n modules: M\r\n activities: readonly WorkflowActivityDefinition<M[number]['moduleId']>[]\r\n}): WorkflowConfig<M, M[number]['moduleId']> {\r\n return config\r\n}\r\n","import type { WorkflowActivityDefinition } from './types'\r\n\r\n/**\r\n * Entrada do histórico do processo BPM retornada por\r\n * `parent.ECM.workflowView.processDefinition.urlHistory`.\r\n * As chaves do objeto pai são arbitrárias — usar apenas `movementDate` e\r\n * `movementHour` para determinar a ordem cronológica real.\r\n */\r\nexport interface BpmHistoryEntry {\r\n /** `null` = ação de usuário; `'SYSTEM'` = tarefa de sistema; `'OBSERVATION'`/`'ATTACHMENT'` = ignorar */\r\n historyType: 'SYSTEM' | 'OBSERVATION' | 'ATTACHMENT' | null\r\n /** Equivalente a `WorkflowActivityDefinition.sequence` */\r\n stateSequence: number\r\n /** `0` = atividade de usuário/sistema | `1` = gateway/decisão automática */\r\n stateType: number\r\n /** Timestamp numérico para ordenação — `null` em sub-registros sem posição cronológica */\r\n movementDate: number | null\r\n /** Hora no formato `\"HH:mm:ss\"` — desempate na ordenação quando `movementDate` é igual */\r\n movementHour: string | null\r\n /** Rótulo da atividade no motor BPM */\r\n labelActivity: string | null\r\n}\r\n\r\n/** Mapa bruto retornado por `urlHistory` — chaves são arbitrárias, ignorar na ordenação */\r\nexport type BpmHistoryMap = Record<string, BpmHistoryEntry>\r\n\r\n/** Histórico processado — alimenta `ScreenContext` para construir a barra de progresso */\r\nexport interface ProcessHistory {\r\n /** Estágios concluídos em ordem cronológica real; deduplica estágios repetidos */\r\n completedStages: string[]\r\n /** Estágio atual com seu status; `null` se a atividade atual não tiver stage mapeado */\r\n currentStage: { stage: string; status: 'current' | 'waiting' } | null\r\n}\r\n\r\n/**\r\n * Extrai os estágios concluídos do histórico BPM na ordem cronológica real.\r\n * Ignora gateways (`stateType === 1`), entradas `SYSTEM`, `OBSERVATION` e `ATTACHMENT`,\r\n * e sub-registros sem `movementDate`. Deduplica estágios — a primeira ocorrência\r\n * cronológica define a posição na barra de progresso.\r\n *\r\n * @param history Mapa bruto retornado por `urlHistory` do processo BPM\r\n * @param activities Array de definições de atividade do `WorkflowConfig`\r\n * @returns Array de stage IDs na ordem em que ocorreram no processo\r\n */\r\nexport function extractCompletedStages(\r\n history: BpmHistoryMap,\r\n activities: readonly WorkflowActivityDefinition[]\r\n): string[] {\r\n const entries = Object.values(history).filter(\r\n (e) =>\r\n e.historyType === null &&\r\n e.stateType !== 1 &&\r\n e.movementDate !== null\r\n )\r\n\r\n entries.sort((a, b) => {\r\n const dateDiff = (a.movementDate as number) - (b.movementDate as number)\r\n if (dateDiff !== 0) return dateDiff\r\n return (a.movementHour ?? '').localeCompare(b.movementHour ?? '')\r\n })\r\n\r\n const seenStages = new Set<string>()\r\n const result: string[] = []\r\n\r\n for (const entry of entries) {\r\n const actDef = activities.find((a) => a.sequence === entry.stateSequence)\r\n if (actDef?.stage && !seenStages.has(actDef.stage)) {\r\n seenStages.add(actDef.stage)\r\n result.push(actDef.stage)\r\n }\r\n }\r\n\r\n return result\r\n}\r\n\r\n/**\r\n * Determina o estágio atual e seu status (`'current'` ou `'waiting'`).\r\n * Retorna `null` se a sequência atual não tiver um `stage` mapeado na configuração.\r\n *\r\n * @param currentSequence Número de sequência da atividade atual do processo\r\n * @param currentHistoryType `historyType` da entrada atual — `null` para ação humana, `'SYSTEM'` para espera\r\n * @param activities Array de definições de atividade do `WorkflowConfig`\r\n * @returns Objeto com `stage` e `status`, ou `null`\r\n */\r\nexport function extractCurrentStage(\r\n currentSequence: number,\r\n currentHistoryType: 'SYSTEM' | null,\r\n activities: readonly WorkflowActivityDefinition[]\r\n): { stage: string; status: 'current' | 'waiting' } | null {\r\n const actDef = activities.find((a) => a.sequence === currentSequence)\r\n if (!actDef?.stage) return null\r\n return {\r\n stage: actDef.stage,\r\n status: currentHistoryType === 'SYSTEM' ? 'waiting' : 'current',\r\n }\r\n}\r\n","import type { WorkflowActivityDefinition } from './types'\r\nimport type { ProcessHistory } from './history-parser'\r\n\r\n/** Módulo com políticas de visibilidade e editabilidade resolvidas para a atividade atual */\r\nexport interface ResolvedModule {\r\n moduleId: string\r\n label: string\r\n icon: string\r\n order: number\r\n showInNavigation: boolean\r\n renderContent: boolean\r\n contentIncludePath: string\r\n isVisible: boolean\r\n isEditable: boolean\r\n isActive: boolean\r\n}\r\n\r\n/**\r\n * Contexto de tela para uma atividade de workflow.\r\n * Consultado por Presenters para decidir visibilidade/editabilidade\r\n * sem conhecer números de sequência.\r\n *\r\n * @hideconstructor\r\n */\r\nexport class ScreenContext {\r\n constructor(\r\n private readonly activity: WorkflowActivityDefinition,\r\n private readonly resolvedModules: readonly ResolvedModule[],\r\n private readonly history: ProcessHistory\r\n ) {}\r\n\r\n /**\r\n * Retorna `true` se o módulo é visível na atividade atual.\r\n *\r\n * @param moduleId Identificador do módulo\r\n */\r\n isVisible(moduleId: string): boolean {\r\n return this.resolvedModules.find((m) => m.moduleId === moduleId)?.isVisible ?? false\r\n }\r\n\r\n /**\r\n * Retorna `true` se o módulo é editável na atividade atual.\r\n *\r\n * @param moduleId Identificador do módulo\r\n */\r\n isEditable(moduleId: string): boolean {\r\n return this.resolvedModules.find((m) => m.moduleId === moduleId)?.isEditable ?? false\r\n }\r\n\r\n /**\r\n * Retorna `true` se o módulo é o ativo (tab selecionada) na atividade atual.\r\n *\r\n * @param moduleId Identificador do módulo\r\n */\r\n isActive(moduleId: string): boolean {\r\n return this.resolvedModules.find((m) => m.moduleId === moduleId)?.isActive ?? false\r\n }\r\n\r\n /**\r\n * Retorna o número de sequência da atividade atual no motor BPM EGD.\r\n *\r\n * Equivalente a `WorkflowActivityDefinition.sequence`. Exposto para presenters\r\n * que precisam do valor em regras de domínio baseadas em sequências específicas\r\n * (ex: listas de sequences especiais para exibir/ocultar campos).\r\n */\r\n getSequence(): number {\r\n return this.activity.sequence\r\n }\r\n\r\n /**\r\n * Retorna `true` se a atividade atual está aguardando um sistema externo\r\n * (`kind === 'system'` ou `currentStage.status === 'waiting'`).\r\n */\r\n isAwaitingSystem(): boolean {\r\n return this.activity.kind === 'system' || this.history.currentStage?.status === 'waiting'\r\n }\r\n\r\n /**\r\n * Retorna `true` se a atividade atual é uma atividade de suporte transversal.\r\n */\r\n isInSupport(): boolean {\r\n return this.activity.kind === 'support'\r\n }\r\n\r\n /**\r\n * Retorna os estágios para renderizar na barra de progresso.\r\n * Inclui os estágios concluídos do histórico (`'done'`) e o estágio atual\r\n * (`'current'` ou `'waiting'`), sem duplicar.\r\n */\r\n getProgressBarStages(): Array<{ stage: string; status: 'done' | 'current' | 'waiting' }> {\r\n const stages: Array<{ stage: string; status: 'done' | 'current' | 'waiting' }> = this.history.completedStages.map(\r\n (stage) => ({ stage, status: 'done' as const })\r\n )\r\n\r\n const current = this.history.currentStage\r\n if (current && !this.history.completedStages.includes(current.stage)) {\r\n stages.push({ stage: current.stage, status: current.status })\r\n }\r\n\r\n return stages\r\n }\r\n\r\n /**\r\n * Retorna todos os módulos resolvidos, incluindo os não-visíveis.\r\n */\r\n getModules(): readonly ResolvedModule[] {\r\n return this.resolvedModules\r\n }\r\n\r\n /**\r\n * Retorna apenas os módulos visíveis, ordenados por `order` ascendente.\r\n */\r\n getVisibleModules(): readonly ResolvedModule[] {\r\n return [...this.resolvedModules].filter((m) => m.isVisible).sort((a, b) => a.order - b.order)\r\n }\r\n\r\n /**\r\n * Retorna os módulos que aparecem na navegação (`showInNavigation && isVisible`),\r\n * ordenados por `order` ascendente.\r\n */\r\n getNavigationModules(): readonly ResolvedModule[] {\r\n return this.getVisibleModules().filter((m) => m.showInNavigation)\r\n }\r\n}\r\n","import type { WorkflowConfig } from './types'\r\nimport type { ProcessHistory } from './history-parser'\r\nimport { ScreenContext } from './screen-context'\r\nimport type { ResolvedModule } from './screen-context'\r\n\r\n/**\r\n * Resolve a tela para a sequência informada, cruzando a configuração do workflow\r\n * com o histórico do processo para produzir um `ScreenContext`.\r\n *\r\n * @param config Configuração gerada por `defineWorkflowConfig`\r\n * @param sequence Número de sequência da atividade atual no processo BPM\r\n * @param history Histórico processado via `extractCompletedStages` e `extractCurrentStage`\r\n * @returns `ScreenContext` pronto para consulta pelos Presenters\r\n *\r\n * @throws {Error} Se a sequência não estiver mapeada na configuração\r\n *\r\n * @example\r\n * const screen = resolveWorkflowScreen(workflowConfig, 53, processHistory)\r\n * screen.isVisible('juridico') // true\r\n * screen.isEditable('juridico') // true\r\n * screen.isInSupport() // false\r\n */\r\nexport function resolveWorkflowScreen(\r\n config: WorkflowConfig<readonly import('./types').WorkflowModuleDefinition[]>,\r\n sequence: number,\r\n history: ProcessHistory\r\n): ScreenContext {\r\n const activity = config.activities.find((a) => a.sequence === sequence)\r\n if (!activity) {\r\n throw new Error(`[jsegd-bpm] Sequência ${sequence} não encontrada na configuração do workflow.`)\r\n }\r\n\r\n const resolvedModules: ResolvedModule[] = config.modules.map((mod) => {\r\n const isVisible = activity.modules?.visible.includes(mod.moduleId) ?? false\r\n const isEditable = activity.modules?.editable.includes(mod.moduleId) ?? false\r\n const isActive = activity.modules?.active === mod.moduleId\r\n\r\n return {\r\n ...mod,\r\n isVisible,\r\n isEditable,\r\n isActive,\r\n }\r\n })\r\n\r\n // Se nenhum módulo for marcado como active, ativa o primeiro showInNavigation && isVisible\r\n const hasActive = resolvedModules.some((m) => m.isActive)\r\n if (!hasActive) {\r\n const firstVisible = resolvedModules.find((m) => m.showInNavigation && m.isVisible)\r\n if (firstVisible) {\r\n firstVisible.isActive = true\r\n }\r\n }\r\n\r\n return new ScreenContext(activity, resolvedModules, history)\r\n}\r\n","import type { Alpine } from 'alpinejs'\r\n\r\n/** Mapa de stores: chave = nome do store, valor = objeto do store */\r\nexport type StoreMap = Record<string, object>\r\n\r\n/**\r\n * Tipo utilitário que gera um proxy com getters tipados para cada store registrado.\r\n * Permite `stores.contador` ao invés de `Alpine.store('contador') as ContadorStore`.\r\n */\r\nexport type StoreProxy<T extends StoreMap> = {\r\n readonly [K in keyof T]: T[K]\r\n}\r\n\r\n/**\r\n * Registra múltiplos Alpine stores e retorna um proxy tipado para acesso direto.\r\n * Deve ser chamado no ponto de inicialização da aplicação, antes de `Alpine.start()`.\r\n *\r\n * @param alpine Instância Alpine — aceita `Pick<Alpine, 'store'>` para facilitar mock em testes\r\n * @param storeMap Objeto com pares `{ nomeDoStore: objetoInicial }`\r\n * @returns Proxy tipado para leitura dos stores sem casting manual\r\n *\r\n * @example\r\n * const stores = registerStores(Alpine, {\r\n * usuario: { nome: '', perfil: '' as PerfilId },\r\n * ui: { carregando: false, erro: null as string | null }\r\n * })\r\n * // stores.usuario.nome está tipado como string\r\n * // Internamente: Alpine.store('usuario', { nome: '', perfil: '' })\r\n */\r\nexport function registerStores<T extends StoreMap>(\r\n alpine: Pick<Alpine, 'store'>,\r\n storeMap: T\r\n): StoreProxy<T> {\r\n for (const [name, store] of Object.entries(storeMap)) {\r\n alpine.store(name, store)\r\n }\r\n return new Proxy(storeMap, {\r\n get: (_target, prop: string) => alpine.store(prop),\r\n }) as StoreProxy<T>\r\n}\r\n"],"names":["getStringFromWasm0","e","t","o","s","a","TextDecoder","ignoreBOM","fatal","decode","i","byteLength","Uint8Array","l","memory","buffer","subarray","FinalizationRegistry","__wbg_validate_free","__wbg_writtenout_free","c","TextEncoder","encodeInto","r","encode","set","read","length","written","LocalCache","static","dbPromise","isInitialized","cacheExpirationMs","storeName","constructor","getInstance","instance","initialize","this","Error","ensureInitialized","promisifyRequest","Promise","onsuccess","result","onerror","error","openDatabase","n","indexedDB","open","onupgradeneeded","objectStoreNames","contains","createObjectStore","keyPath","get","transaction","objectStore","Date","now","timestamp","remove","catch","data","key","put","oncomplete","delete","clear","purgeExpired","getAll","filter","u","d","f","ConstraintsType","Second","Minute","Hour","Day","Week","Month","Bimonth","Quarter","Semester","Year","BRL","USD","EUR","JPY","GBP","CNY","DOCUMENT","EMAIL","MOBILE","EVP","async","Object","getPrototypeOf","prototype","module_or_path","console","warn","URL","url","__proto__","__wbg_Error_960c155d3d49e4c2","__wbg___wbindgen_throw_6b64449b9b9ed33c","__wbindgen_cast_0000000000000001","__wbindgen_init_externref_table","__wbindgen_externrefs","grow","Request","fetch","module","Response","WebAssembly","instantiateStreaming","ok","type","headers","arrayBuffer","instantiate","Instance","exports","__wbindgen_start","WorkerManager","pool","workerMeta","Map","taskQueue","inFlight","cache","nextRequestId","options","poolSize","cacheOptions","lc","worker","Worker","onmessage","handleResponse","busy","push","query","baseUrl","params","buildUrl","wrapperPromise","then","cached","deduplicateOrEnqueue","canceller","promise","res","rej","abortRequest","cancel","terminate","has","enqueueRequest","requestId","requestUrl","payload","resolveFn","rejectFn","resolve","reject","pending","scheduleNext","meta","task","shift","currentKey","currentRequestId","postMessage","externalReject","queueIndex","findIndex","splice","response","aborted","success","searchParams","datasetId","field","forEach","append","undefined","offset","String","limit","orderby","constraintsField","constraintsInitialValue","v","constraintsFinalValue","constraintsType","constraintsLikeSearch","b","toString","GENERIC_ATTACHMENT_MARKER","METADATA_ATTACHMENT_NAME","getAttachmentOps","parent","WKFViewAttachment","getAllAttachments","openAttachmentView","colleagueId","documentId","version","downloadAttach","indexes","confirmRemoveAttach","editAttach","row","index","attachEdit","deleteAttachmentSilent","attachment","deleteAttachments","getProcessInfo","ECM","getUserPermissions","workflowView","userPermissions","getProcessInstanceId","processDefinition","processInstanceId","getTaskUserId","taskUserId","getWorkflowSequence","sequence","getTableData","attachmentTable","getData","getTableRow","getRow","getWorkflowContext","parentDocument","document","renderTemplate","template","mustache","Mustache","render","removeDragListeners","$","off","overrideSuccessRemoveAttachment","handler","successRemoveAttachment","bind","bindFileUploadHandlers","callbacks","getECM","on","validateUpload","includes","window","dispatchEvent","CustomEvent","FLUIGC","toast","message","duplicated","files","item","arr","indexOf","sort","idx","file","attachFileMonitor","add","name","fullPath","defFullPath","droppedZipZone","hasApprovers","defHasApprovers","isDuplicate","newAttachmentsDocs","some","maxMb","maxUploadSize","size","core","formatSize","datasUpload","id","context","onFileAdd","internalId","el","attr","cameraName","description","removeAttr","uploadId","startPublishingDocument","onFileDone","onFileFail","isMetadataAttachment","startsWith","getAttachmentsByDescription","toLowerCase","replace","filterPublishedAttachments","attachments","newAttach","findAttachmentTableIndex","predicate","hasPermission","isNewProcess","isOwnAttachment","canEditAttachment","sanitizeAttachmentName","input","sanitized","trim","substring","normalize","applyNextVersion","nextVersion","maxVersion","match","parseInt","Math","max","getNextVersion","AttachmentPickerModal","datatable","modal","callback","existing","getElementById","createModal","createTable","bindEvents","dataRequest","renderContent","header","title","multiSelect","search","enabled","onlyEnterkey","searchAreaStyle","onSearch","scroll","navButtons","tableStyle","emptyMessage","classSelected","actions","actionAreaStyle","draggable","onDrag","content","showHeader","showFooter","headerActions","headerContent","formModal","selectedIndex","destroy","Attach","interceptUploadEvents","addEventListener","detail","download","Array","isArray","_e","_data","source","currentUploadSource","accept","currentUploadAccept","attachmentDescription","element","setAttribute","click","view","publishedAttachments","edit","editableAttachments","downloadBlob","blob","filename","Blob","createObjectURL","createElement","href","revokeObjectURL","uploadBlob","mimeType","inputFile","safeDescription","File","dt","DataTransfer","items","Event","DragDropNameModal","onConfirm","from","rows","map","sanitizeAttributeValue","sanitizeText","join","cfg","label","classType","autoClose","handleUseOriginals","querySelector","confirm","target","querySelectorAll","disabled","checked","value","inputs","entries","removeEventListener","text","sessionCache","AttachmentMetadataFile","exists","findAttachment","att","find","load","force","credentials","status","raw","json","parseAndMigrate","save","metadata","updated","updatedAt","toISOString","ctx","JSON","stringify","empty","CURRENT_VERSION","buttons","CONTAINER_ID","TOOLBAR_ID","THEAD","TEMPLATE_BUTTONS_ONLY","TEMPLATE_SELF_MANAGED","TOOLBAR_HTML","AttachmentsTable","start","mode","attachInstance","hydrateFromMetadata","registerButton","registration","buttonRegistry","persistMetadata","resolveButtonRegistration","base","nativeContainer","style","display","attachmentsRoot","toolbarWrapper","innerHTML","appendChild","firstElementChild","container","event","openLink","closest","preventDefault","getAttribute","Number","downloadIcon","th","column","ascending","sortBy","editIcon","reversionIcon","btnDescription","btnAccept","deleteIcon","openNameInputModal","stopPropagation","classList","dataTransfer","allAttachments","newAttachment","record","buttonDescription","workflowSequence","uploadedAt","isSelfManaged","sanitizeAttachmentForDisplay","enableDownload","btn","enableView","enableEdit","enableReversion","enableDelete","buttonAccept","unpublishedVersion","current","reg","rawName","safeName","getRows","setOrder","tbody","valueA","getCellValue","valueB","localeCompare","textContent","AttachButton","HTMLElement","noaddbutton","noviewbutton","noeditbutton","nodeletebutton","handleSuccess","button","shadowRoot","color","backgroundColor","handleError","handleDefault","super","shadow","attachShadow","cloneNode","observedAttributes","attributeChangedCallback","_oldValue","newValue","isConnected","displayButtons","disconnectedCallback","connectedCallback","addButton","viewButton","editButton","removeButton","parentElement","showModal","attachModal","err","autocomplete","q","cb","matches","prefixes","Set","getGenericAttachmentDescriptions","highlight","displayKey","tagClass","toUpperCase","customElements","define","BeforeSendValidate","clearAllErrors","group","helperElement","throwValidationError","fields","errorMessage","clearErrorHandler","once","validMessages","combinedMessages","hooksMap","beforeValidate","afterValidate","onMoveSuccess","onMoveError","onCompletionLinkAdd","sendRequestEvent","enableButtons","enableSendButton","enableActionButtons","fn","nextActivityElement","nextActivity","selectActivity","callFormFunction","disableActionButtons","sendRequest","overrides","WorkflowViewPatcher","init","timeout","isInitializing","startTime","ECM_WKFView","setTimeout","patch","originalMethods","patchMany","attrs","patchAll","keys","restore","originalFn","k","getHooks","addBeforeValidate","addAfterValidate","addOnMoveSuccess","addOnMoveError","addOnCompletionLinkAdd","snakeToCamel","str","_","letter","camelToSnake","BpmFormRepository","section","prefix","domName","camelKey","slice","HTMLInputElement","loadTable","tableName","rowData","baseName","lastIndexOf","Boolean","saveTable","rowId","wdkAddChild","MockFormRepository","store","tables","reset","loadFields","fieldMap","modelKey","defineWorkflowConfig","config","extractCompletedStages","history","activities","values","historyType","stateType","movementDate","dateDiff","movementHour","seenStages","entry","actDef","stateSequence","stage","extractCurrentStage","currentSequence","currentHistoryType","ScreenContext","activity","resolvedModules","isVisible","moduleId","m","isEditable","isActive","getSequence","isAwaitingSystem","kind","currentStage","isInSupport","getProgressBarStages","stages","completedStages","getModules","getVisibleModules","order","getNavigationModules","showInNavigation","resolveWorkflowScreen","modules","mod","visible","editable","active","firstVisible","registerStores","alpine","storeMap","Proxy","_target","prop"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"jsegd-bpm.js","sources":["../node_modules/jsegd/dist/jsegd.js","../app/app/worker-manager/interfaces/ISearchParams.ts","../app/app/worker-manager/worker-manager.ts","../app/app/attachment/attachment.constants.ts","../app/app/process-context/index.ts","../app/app/attachment/workflow-context.ts","../app/app/attachment/attachment.utils.ts","../app/app/attachment/attachment.version.ts","../app/app/attachment/attachmentPickerModal.ts","../app/app/attachment/attach.ts","../app/app/attachment/drag-drop-name-modal.ts","../app/app/attachment/attachment-metadata.ts","../app/app/attachment/attachmentsTable.ts","../app/app/attachment/attachButton.ts","../app/attachment/assets/styles.css","../app/app/events/beforeSendValidate.ts","../app/app/workflow-view/hooks-registry.ts","../app/app/workflow-view/overrides/send-request.ts","../app/app/workflow-view/workflow-view-patcher.ts","../app/app/form-repository/nameUtils.ts","../app/app/form-repository/BpmFormRepository.ts","../app/app/form-repository/MockFormRepository.ts","../app/app/form-repository/loadFields.ts","../app/app/workflow/define-config.ts","../app/app/workflow/history-parser.ts","../app/app/workflow/screen-context.ts","../app/app/workflow/screen-resolver.ts","../app/app/alpine/register-stores.ts"],"sourcesContent":["let e=class{__destroy_into_raw(){const e=this.__wbg_ptr;return this.__wbg_ptr=0,r.unregister(this),e}free(){const e=this.__destroy_into_raw();l.__wbg_validate_free(e,0)}static is_valid_cep(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_;return 0!==l.validate_is_valid_cep(t,r)}static is_valid_cnpj(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_;return 0!==l.validate_is_valid_cnpj(t,r)}static is_valid_cpf(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_;return 0!==l.validate_is_valid_cpf(t,r)}static is_valid_email(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_;return 0!==l.validate_is_valid_email(t,r)}static is_valid_evp(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_;return 0!==l.validate_is_valid_evp(t,r)}static is_valid_mobile(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_;return 0!==l.validate_is_valid_mobile(t,r)}};Symbol.dispose&&(e.prototype[Symbol.dispose]=e.prototype.free);let t=class{__destroy_into_raw(){const e=this.__wbg_ptr;return this.__wbg_ptr=0,n.unregister(this),e}free(){const e=this.__destroy_into_raw();l.__wbg_writtenout_free(e,0)}static format_currency(e,t){let r,n;try{const s=l.writtenout_format_currency(e,t);var i=s[0],a=s[1];if(s[3])throw i=0,a=0,takeFromExternrefTable0(s[2]);return r=i,n=a,getStringFromWasm0(i,a)}finally{l.__wbindgen_free(r,n,1)}}static format_date(e){let t,r;try{const a=l.writtenout_format_date(e);var n=a[0],i=a[1];if(a[3])throw n=0,i=0,takeFromExternrefTable0(a[2]);return t=n,r=i,getStringFromWasm0(n,i)}finally{l.__wbindgen_free(t,r,1)}}static format_deadline(e,t){let r,n;try{const s=l.writtenout_format_deadline(e,t);var i=s[0],a=s[1];if(s[3])throw i=0,a=0,takeFromExternrefTable0(s[2]);return r=i,n=a,getStringFromWasm0(i,a)}finally{l.__wbindgen_free(r,n,1)}}static format_number(e){let t,r;try{const a=l.writtenout_format_number(e);var n=a[0],i=a[1];if(a[3])throw n=0,i=0,takeFromExternrefTable0(a[2]);return t=n,r=i,getStringFromWasm0(n,i)}finally{l.__wbindgen_free(t,r,1)}}};Symbol.dispose&&(t.prototype[Symbol.dispose]=t.prototype.free);const r=\"undefined\"==typeof FinalizationRegistry?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry((e=>l.__wbg_validate_free(e>>>0,1))),n=\"undefined\"==typeof FinalizationRegistry?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry((e=>l.__wbg_writtenout_free(e>>>0,1)));function getStringFromWasm0(e,t){return function(e,t){o+=t,o>=s&&(a=new TextDecoder(\"utf-8\",{ignoreBOM:!0,fatal:!0}),a.decode(),o=t);return a.decode(getUint8ArrayMemory0().subarray(e,e+t))}(e>>>=0,t)}let i=null;function getUint8ArrayMemory0(){return null!==i&&0!==i.byteLength||(i=new Uint8Array(l.memory.buffer)),i}function passStringToWasm0(e,t,r){if(void 0===r){const r=c.encode(e),n=t(r.length,1)>>>0;return getUint8ArrayMemory0().subarray(n,n+r.length).set(r),_=r.length,n}let n=e.length,i=t(n,1)>>>0;const a=getUint8ArrayMemory0();let s=0;for(;s<n;s++){const t=e.charCodeAt(s);if(t>127)break;a[i+s]=t}if(s!==n){0!==s&&(e=e.slice(s)),i=r(i,n,n=s+3*e.length,1)>>>0;const t=getUint8ArrayMemory0().subarray(i+s,i+n);s+=c.encodeInto(e,t).written,i=r(i,n,s,1)>>>0}return _=s,i}function takeFromExternrefTable0(e){const t=l.__wbindgen_externrefs.get(e);return l.__externref_table_dealloc(e),t}let a=new TextDecoder(\"utf-8\",{ignoreBOM:!0,fatal:!0});a.decode();const s=2146435072;let o=0;const c=new TextEncoder;\"encodeInto\"in c||(c.encodeInto=function(e,t){const r=c.encode(e);return t.set(r),{read:e.length,written:r.length}});let l,_=0;class LocalCache{static instance;dbPromise=null;isInitialized=!1;cacheExpirationMs;storeName;constructor(){}static getInstance(){return LocalCache.instance||(LocalCache.instance=new LocalCache),LocalCache.instance}initialize(e){if(this.isInitialized)throw new Error(`LocalCache already initialized with storeName=\"${this.storeName}\". Create a new instance or reuse the existing one.`);this.cacheExpirationMs=e.cacheExpirationMs,this.storeName=e.storeName,this.isInitialized=!0}ensureInitialized(){if(!this.isInitialized)throw new Error(\"LocalCache not initialized. Call getInstance().initialize({ storeName, cacheExpirationMs }) first.\")}promisifyRequest(e){return new Promise(((t,r)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>r(e.error)}))}async openDatabase(){if(this.ensureInitialized(),this.dbPromise)return this.dbPromise;const e=`jsegd_cache_${this.storeName}`;return this.dbPromise=new Promise(((t,r)=>{const n=indexedDB.open(e,1);n.onupgradeneeded=()=>{const e=n.result;e.objectStoreNames.contains(this.storeName)||e.createObjectStore(this.storeName,{keyPath:\"key\"})},n.onsuccess=()=>t(n.result),n.onerror=()=>{r(n.error)}})),this.dbPromise}async get(e){this.ensureInitialized();try{const t=await this.openDatabase(),r=t.transaction(this.storeName,\"readonly\").objectStore(this.storeName),n=await this.promisifyRequest(r.get(e));return n?Date.now()-n.timestamp>this.cacheExpirationMs?(await this.remove(e).catch((()=>{})),null):n.data:null}catch(e){return null}}async set(e,t){this.ensureInitialized();try{const r=(await this.openDatabase()).transaction(this.storeName,\"readwrite\"),n=r.objectStore(this.storeName),i={key:e,timestamp:Date.now(),data:t};await this.promisifyRequest(n.put(i)),await new Promise(((e,t)=>{r.oncomplete=()=>e(),r.onerror=()=>t(r.error)}))}catch(e){throw e}}async remove(e){this.ensureInitialized();try{const t=(await this.openDatabase()).transaction(this.storeName,\"readwrite\"),r=t.objectStore(this.storeName);await this.promisifyRequest(r.delete(e)),await new Promise(((e,r)=>{t.oncomplete=()=>e(),t.onerror=()=>r(t.error)}))}catch(e){throw e}}async clear(){this.ensureInitialized();try{const e=(await this.openDatabase()).transaction(this.storeName,\"readwrite\"),t=e.objectStore(this.storeName);await this.promisifyRequest(t.clear()),await new Promise(((t,r)=>{e.oncomplete=()=>t(),e.onerror=()=>r(e.error)}))}catch(e){throw e}}async purgeExpired(){this.ensureInitialized();try{const e=(await this.openDatabase()).transaction(this.storeName,\"readwrite\"),t=e.objectStore(this.storeName),r=await this.promisifyRequest(t.getAll()),n=Date.now(),i=r.filter((e=>n-e.timestamp>this.cacheExpirationMs));for(const e of i)await this.promisifyRequest(t.delete(e.key));return await new Promise(((t,r)=>{e.oncomplete=()=>t(),e.onerror=()=>r(e.error)})),i.length}catch(e){return 0}}}class EventBus{static instance;events={};constructor(){}static getInstance(){return EventBus.instance||(EventBus.instance=new EventBus),EventBus.instance}on(e,t){return this.events[e]||(this.events[e]=[]),this.events[e].push(t),()=>this.off(e,t)}once(e,t){const wrapper=(...r)=>{this.off(e,wrapper),t(...r)};return this.on(e,wrapper)}off(e,t){this.events[e]&&(this.events[e]=this.events[e].filter((e=>e!==t)),0===this.events[e].length&&delete this.events[e])}emit(e,...t){if(!this.events[e])return;const r=[...this.events[e]];for(const e of r)try{e(...t)}catch{}}clear(e){void 0!==e?delete this.events[e]:this.events={}}}var u,m;!function(e){e[e.Second=0]=\"Second\",e[e.Minute=1]=\"Minute\",e[e.Hour=2]=\"Hour\",e[e.Day=3]=\"Day\",e[e.Week=4]=\"Week\",e[e.Month=5]=\"Month\",e[e.Bimonth=6]=\"Bimonth\",e[e.Quarter=7]=\"Quarter\",e[e.Semester=8]=\"Semester\",e[e.Year=9]=\"Year\"}(u||(u={})),function(e){e[e.BRL=0]=\"BRL\",e[e.USD=1]=\"USD\",e[e.EUR=2]=\"EUR\",e[e.JPY=3]=\"JPY\",e[e.GBP=4]=\"GBP\",e[e.CNY=5]=\"CNY\"}(m||(m={}));class WrittenOut{static formatDeadline(e,r){return t.format_deadline(e,r)}static formatNumber(e){return t.format_number(e)}static formatCurrency(e,r){return t.format_currency(e,r)}static formatDate(e){return t.format_date(BigInt(e.getTime()))}}const d={[m.BRL]:{locale:\"pt-BR\",currency:\"BRL\"},[m.USD]:{locale:\"en-US\",currency:\"USD\"},[m.EUR]:{locale:\"de-DE\",currency:\"EUR\"},[m.JPY]:{locale:\"ja-JP\",currency:\"JPY\"},[m.GBP]:{locale:\"en-GB\",currency:\"GBP\"},[m.CNY]:{locale:\"zh-CN\",currency:\"CNY\"}};class Util{static async parseNumber(e){return function(e){const t=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),r=_,n=l.parse_number(t,r);if(n[2])throw takeFromExternrefTable0(n[1]);return n[0]}(e)}static convertToMonetaryValue(e,t=m.BRL){const{locale:r,currency:n}=d[t];return e.toLocaleString(r,{minimumFractionDigits:2,maximumFractionDigits:2,style:\"currency\",currency:n})}static async removeAccents(e){return function(e){let t,r;try{const n=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),i=_,a=l.remove_accents(n,i);return t=a[0],r=a[1],getStringFromWasm0(a[0],a[1])}finally{l.__wbindgen_free(t,r,1)}}(e)}static async abbreviate(e){return function(e){let t,r;try{const n=passStringToWasm0(e,l.__wbindgen_malloc,l.__wbindgen_realloc),i=_,a=l.abbreviate(n,i);return t=a[0],r=a[1],getStringFromWasm0(a[0],a[1])}finally{l.__wbindgen_free(t,r,1)}}(e)}}var f;!function(e){e[e.DOCUMENT=0]=\"DOCUMENT\",e[e.EMAIL=1]=\"EMAIL\",e[e.MOBILE=2]=\"MOBILE\",e[e.EVP=3]=\"EVP\"}(f||(f={}));class Validate{static async isValidEmail(t){return e.is_valid_email(t)}static async isValidMobile(t){return e.is_valid_mobile(t)}static async isValidCNPJ(t){return e.is_valid_cnpj(t)}static async isValidCPF(t){return e.is_valid_cpf(t)}static async isValidCEP(t){return e.is_valid_cep(t)}static async isValidEVP(t){return e.is_valid_evp(t)}static async isValidPix(t,r){switch(t){case f.DOCUMENT:if(11===r.length){if(!e.is_valid_cpf(r))throw new Error(\"O CPF informado é inválido\");return!0}if(14===r.length){if(!e.is_valid_cnpj(r))throw new Error(\"O CNPJ informado é inválido\");return!0}throw new Error(\"O documento informado deve conter 11 ou 14 dígitos\");case f.MOBILE:if(!e.is_valid_mobile(r))throw new Error(\"Chave PIX do tipo Número de Telefone possivelmente é inválida\");return!0;case f.EMAIL:if(!e.is_valid_email(r))throw new Error(\"Chave PIX do tipo E-mail possivelmente é inválida\");return!0;case f.EVP:if(!e.is_valid_evp(r))throw new Error(\"Chave PIX do tipo Chave aleatória possivelmente é inválida\");return!0;default:throw new Error(\"Informe o tipo da chave PIX\")}}}await async function(e){if(void 0!==l)return l;void 0!==e&&(Object.getPrototypeOf(e)===Object.prototype?({module_or_path:e}=e):console.warn(\"using deprecated parameters for the initialization function; pass a single object instead\")),void 0===e&&(e=new URL(\"jsegd_bg.wasm\",import.meta.url));const t={__proto__:null,\"./jsegd_bg.js\":{__proto__:null,__wbg_Error_960c155d3d49e4c2:function(e,t){return Error(getStringFromWasm0(e,t))},__wbg___wbindgen_throw_6b64449b9b9ed33c:function(e,t){throw new Error(getStringFromWasm0(e,t))},__wbindgen_cast_0000000000000001:function(e,t){return getStringFromWasm0(e,t)},__wbindgen_init_externref_table:function(){const e=l.__wbindgen_externrefs,t=e.grow(4);e.set(0,void 0),e.set(t+0,void 0),e.set(t+1,null),e.set(t+2,!0),e.set(t+3,!1)}}};(\"string\"==typeof e||\"function\"==typeof Request&&e instanceof Request||\"function\"==typeof URL&&e instanceof URL)&&(e=fetch(e));const{instance:r,module:n}=await async function(e,t){if(\"function\"==typeof Response&&e instanceof Response){if(\"function\"==typeof WebAssembly.instantiateStreaming)try{return await WebAssembly.instantiateStreaming(e,t)}catch(t){if(!e.ok||!function(e){switch(e){case\"basic\":case\"cors\":case\"default\":return!0}return!1}(e.type)||\"application/wasm\"===e.headers.get(\"Content-Type\"))throw t;console.warn(\"`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\\n\",t)}const r=await e.arrayBuffer();return await WebAssembly.instantiate(r,t)}{const r=await WebAssembly.instantiate(e,t);return r instanceof WebAssembly.Instance?{instance:r,module:e}:r}}(await e,t);return function(e){return l=e.exports,i=null,l.__wbindgen_start(),l}(r)}((function(e){return function(e,t,r,n){function _instantiateOrCompile(e,t,r){var n=r?WebAssembly.instantiateStreaming:WebAssembly.instantiate,i=r?WebAssembly.compileStreaming:WebAssembly.compile;return t?n(e,t):i(e)}if(\"undefined\"!=typeof process&&null!=process.versions&&null!=process.versions.node){var i=require(\"fs\"),a=require(\"path\");return new Promise(((e,r)=>{i.readFile(a.resolve(__dirname,t),((t,i)=>{null!=t?r(t):e(_instantiateOrCompile(i,n,!1))}))}))}return _instantiateOrCompile(fetch(t),n,!0)}(0,\"jsegd_bg.wasm\",0,e)}));export{m as Currency,u as DeadlineUnit,EventBus,LocalCache,f as TypePix,Util,Validate,WrittenOut};\n//# sourceMappingURL=jsegd.js.map\n","export enum ConstraintsType {\r\n MUST = 'MUST',\r\n MUST_NOT = 'MUST_NOT',\r\n SHOULD = 'SHOULD',\r\n}\r\n\r\nexport interface SearchParams {\r\n /** Código do dataset — obrigatório. */\r\n datasetId: string\r\n /** Campos a retornar; omitir para retornar todos os campos. */\r\n field?: string[]\r\n /** Registros a ignorar — usado para paginação (padrão: 0). */\r\n offset?: number\r\n /** Máximo de registros a retornar (padrão: 300; 0 = todos). */\r\n limit?: number\r\n /** Nome do campo para ordenação, opcionalmente sufixado com _ASC ou _DESC. */\r\n orderby?: string\r\n constraintsField?: string[]\r\n constraintsInitialValue?: string[]\r\n constraintsFinalValue?: string[]\r\n constraintsType?: ConstraintsType[]\r\n /** Quando verdadeiro, o curinga % é aceito no valor inicial/final correspondente. */\r\n constraintsLikeSearch?: boolean[]\r\n}\r\n","import type { ICache } from 'jsegd'\r\nimport { LocalCache } from 'jsegd'\r\nimport type { DatasetResponse } from './interfaces/IDataset'\r\nimport type { SearchParams, ConstraintsType } from './interfaces/ISearchParams'\r\nimport type { WorkerAbort, WorkerRequest, WorkerResponse } from './interfaces/IWorkerMessage'\r\nimport type { CancelablePromise, PendingRequest, Task, WorkerMeta } from './interfaces/IWorkerManager'\r\n\r\nexport type CacheOptions = { storeName: string; cacheExpirationMs: number }\r\n\r\nexport interface WorkerManagerOptions {\r\n poolSize?: number\r\n /** Injeta uma instância existente de ICache (compartilhada entre componentes). */\r\n cache?: ICache\r\n /** Cria um LocalCache interno com as opções fornecidas. */\r\n cacheOptions?: CacheOptions\r\n // Se nenhum dos dois for informado, o gerenciador opera sem cache.\r\n}\r\n\r\n/**\r\n * Gerencia um pool de Web Workers para executar consultas à API de Datasets do Fluig fora da thread principal.\r\n * Suporta deduplicacão de requisições, cache em IndexedDB e cancelamento HTTP real via AbortController.\r\n *\r\n * @example\r\n * ```typescript\r\n * import { WorkerManager, ConstraintsType } from 'jsegd-bpm'\r\n *\r\n * const manager = new WorkerManager({\r\n * poolSize: 4,\r\n * cacheOptions: { storeName: 'datasetCache', cacheExpirationMs: 24 * 60 * 60 * 1000 }\r\n * })\r\n *\r\n * const { promise, cancel } = manager.query('https://tenant.fluig.com', {\r\n * datasetId: 'dsColaboradores',\r\n * field: ['nome', 'email'],\r\n * constraintsField: ['ativo'],\r\n * constraintsInitialValue: ['true'],\r\n * constraintsType: [ConstraintsType.MUST],\r\n * })\r\n *\r\n * // Cancelar se necessário:\r\n * // cancel()\r\n *\r\n * const result = await promise\r\n * console.log(result.columns) // ['nome', 'email']\r\n * console.log(result.values) // [{ nome: 'João', email: 'joao@co.com' }, ...]\r\n * ```\r\n */\r\nexport class WorkerManager {\r\n private pool: Worker[] = []\r\n private workerMeta = new Map<Worker, WorkerMeta>()\r\n private taskQueue: Task[] = []\r\n private inFlight: Map<string, PendingRequest> = new Map()\r\n private cache: ICache | null = null\r\n private nextRequestId = 0\r\n\r\n constructor(options: WorkerManagerOptions = {}) {\r\n const poolSize = options.poolSize ?? 4\r\n\r\n if (options.cache) {\r\n this.cache = options.cache\r\n } else if (options.cacheOptions) {\r\n const lc = LocalCache.getInstance()\r\n lc.initialize(options.cacheOptions)\r\n this.cache = lc\r\n }\r\n\r\n for (let i = 0; i < poolSize; i++) {\r\n const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' })\r\n worker.onmessage = (e) => this.handleResponse(e.data as WorkerResponse, worker)\r\n this.workerMeta.set(worker, { busy: false })\r\n this.pool.push(worker)\r\n }\r\n }\r\n\r\n /**\r\n * Consulta a API de Datasets do Fluig. Retorna uma CancelablePromise.\r\n * Chame `cancel()` para abortar a requisição HTTP e liberar o worker imediatamente.\r\n */\r\n public query(baseUrl: string, params: SearchParams): CancelablePromise<DatasetResponse> {\r\n const url = this.buildUrl(baseUrl, params)\r\n const key = url\r\n\r\n const wrapperPromise = this.cache\r\n ? this.cache.get<DatasetResponse>(key).then((cached) => {\r\n if (cached) return cached\r\n return this.deduplicateOrEnqueue(key, url)\r\n })\r\n : this.deduplicateOrEnqueue(key, url)\r\n\r\n let canceller: () => void = () => {}\r\n const promise = new Promise<DatasetResponse>((res, rej) => {\r\n canceller = () => this.abortRequest(key, rej)\r\n wrapperPromise.then(res, rej)\r\n })\r\n\r\n return { promise, cancel: canceller }\r\n }\r\n\r\n /**\r\n * Encerra todos os workers do pool. Chame quando o gerenciador não for mais necessário\r\n * para evitar vazamentos de memória e workers zumbis.\r\n */\r\n public terminate(): void {\r\n for (const worker of this.pool) {\r\n worker.terminate()\r\n }\r\n this.pool = []\r\n this.workerMeta.clear()\r\n this.taskQueue = []\r\n this.inFlight.clear()\r\n }\r\n\r\n private deduplicateOrEnqueue(key: string, url: string): Promise<DatasetResponse> {\r\n if (this.inFlight.has(key)) {\r\n return this.inFlight.get(key)!.promise\r\n }\r\n return this.enqueueRequest(key, { type: 'request', requestId: ++this.nextRequestId, requestUrl: url })\r\n }\r\n\r\n private enqueueRequest(key: string, payload: WorkerRequest): Promise<any> {\r\n let resolveFn!: (v: any) => void\r\n let rejectFn!: (e: any) => void\r\n\r\n const promise = new Promise<any>((resolve, reject) => {\r\n resolveFn = resolve\r\n rejectFn = reject\r\n })\r\n\r\n const pending: PendingRequest = { promise, resolve: resolveFn, reject: rejectFn }\r\n this.inFlight.set(key, pending)\r\n this.taskQueue.push({ key, payload, pending })\r\n this.scheduleNext()\r\n return promise\r\n }\r\n\r\n private scheduleNext(): void {\r\n for (const worker of this.pool) {\r\n if (this.taskQueue.length === 0) break\r\n const meta = this.workerMeta.get(worker)!\r\n if (!meta.busy) {\r\n const task = this.taskQueue.shift()!\r\n meta.busy = true\r\n meta.currentKey = task.key\r\n meta.currentRequestId = task.payload.requestId\r\n worker.postMessage(task.payload)\r\n }\r\n }\r\n }\r\n\r\n private abortRequest(key: string, externalReject: (e: any) => void): void {\r\n externalReject(new Error('Request cancelled'))\r\n\r\n const queueIndex = this.taskQueue.findIndex((t) => t.key === key)\r\n if (queueIndex !== -1) {\r\n const [task] = this.taskQueue.splice(queueIndex, 1)\r\n this.inFlight.delete(key)\r\n task.pending.reject(new Error('Request cancelled'))\r\n return\r\n }\r\n\r\n // Already dispatched to a worker — send abort message\r\n for (const [worker, meta] of this.workerMeta) {\r\n if (meta.currentKey === key) {\r\n worker.postMessage({ type: 'abort', requestId: meta.currentRequestId! } satisfies WorkerAbort)\r\n break\r\n }\r\n }\r\n }\r\n\r\n private handleResponse(response: WorkerResponse, worker: Worker): void {\r\n const meta = this.workerMeta.get(worker)!\r\n const key = meta.currentKey!\r\n\r\n meta.busy = false\r\n delete meta.currentKey\r\n delete meta.currentRequestId\r\n\r\n const pending = this.inFlight.get(key)\r\n this.inFlight.delete(key)\r\n\r\n if (pending) {\r\n if (response.aborted) {\r\n pending.reject(new Error('Request cancelled'))\r\n } else if (response.success) {\r\n const data = response.data as DatasetResponse\r\n if (this.cache) {\r\n this.cache.set(key, data).catch(() => {})\r\n }\r\n pending.resolve(data)\r\n } else {\r\n pending.reject(new Error(response.error))\r\n }\r\n }\r\n\r\n this.scheduleNext()\r\n }\r\n\r\n private buildUrl(baseUrl: string, params: SearchParams): string {\r\n const url = new URL(`${baseUrl}/dataset/api/v2/dataset-handle/search`)\r\n url.searchParams.set('datasetId', params.datasetId)\r\n params.field?.forEach((f) => url.searchParams.append('field', f))\r\n if (params.offset !== undefined) url.searchParams.set('offset', String(params.offset))\r\n if (params.limit !== undefined) url.searchParams.set('limit', String(params.limit))\r\n if (params.orderby) url.searchParams.set('orderby', params.orderby)\r\n params.constraintsField?.forEach((f) => url.searchParams.append('constraintsField', f))\r\n params.constraintsInitialValue?.forEach((v) => url.searchParams.append('constraintsInitialValue', v))\r\n params.constraintsFinalValue?.forEach((v) => url.searchParams.append('constraintsFinalValue', v))\r\n params.constraintsType?.forEach((t) => url.searchParams.append('constraintsType', t))\r\n params.constraintsLikeSearch?.forEach((b) => url.searchParams.append('constraintsLikeSearch', String(b)))\r\n return url.toString()\r\n }\r\n}\r\n","/** Marcador de anexo genérico (sem descrição prévia definida no componente) */\r\nexport const GENERIC_ATTACHMENT_MARKER = '_Z_'\r\n\r\n/** Versão padrão exibida para documentos ainda não publicados no ECM */\r\nexport const UNPUBLISHED_VERSION_DISPLAY = 1000\r\n\r\n/** Descrição do arquivo de metadados interno gerenciado pela biblioteca */\r\nexport const METADATA_ATTACHMENT_NAME = '_jsegd_metadata'\r\n","/**\r\n * Fronteira única de acesso ao objeto `parent` do Fluig dentro do módulo `bpm/`.\r\n *\r\n * Isola todos os consumidores da dependência direta sobre o frame pai,\r\n * permitindo mock completo em testes unitários.\r\n * Cada função de fábrica valida apenas o objeto `parent.*` de que depende.\r\n *\r\n * **Regra de fronteira:** este é o único arquivo em `bpm/` autorizado a referenciar\r\n * `parent.WKFViewAttachment`, `parent.ECM`, `parent.Mustache`, `parent.$` e\r\n * `parent.document` (exceção: `workflow-view-patcher.ts` acessa `parent.ECM_WKFView`\r\n * por responsabilidade própria de patching).\r\n */\r\n\r\n/** Operações sobre anexos via `WKFViewAttachment` */\r\nexport interface IAttachmentOps {\r\n /**\r\n * Retorna todos os anexos do processo atual.\r\n */\r\n getAllAttachments(): Attachment[]\r\n\r\n /**\r\n * Abre o visualizador de documento do processo.\r\n */\r\n openAttachmentView(colleagueId: string, documentId: number, version: number): void\r\n\r\n /**\r\n * Inicia o download de anexos pelos índices na tabela.\r\n */\r\n downloadAttach(indexes: number[]): void\r\n\r\n /**\r\n * Exibe o diálogo de confirmação de remoção do processo.\r\n */\r\n confirmRemoveAttach(indexes: number[]): void\r\n\r\n /**\r\n * Abre o painel de edição de conteúdo/metadados para o anexo.\r\n */\r\n editAttach(row: { [key: string]: string }, index: number): void\r\n\r\n /**\r\n * Remove um anexo publicado diretamente, sem diálogo de confirmação e sem toast.\r\n * Uso exclusivo para remoção de arquivos internos da biblioteca (ex: `_jsegd_metadata`).\r\n */\r\n deleteAttachmentSilent(attachment: Attachment): void\r\n}\r\n\r\n/** Callbacks fornecidos por `Attach` para substituição dos handlers do jQuery File Upload */\r\nexport interface FileUploadCallbacks {\r\n /**\r\n * Chamado após todas as validações internas passarem em `fileuploadadd`.\r\n * Retornar `false` cancela o upload.\r\n */\r\n onFileAdd(event: unknown, data: unknown): boolean | void\r\n /**\r\n * Chamado quando o arquivo é publicado com sucesso via `startPublishingDocument`.\r\n * `item.description` contém o nome/descrição final do arquivo no ECM.\r\n */\r\n onFileDone(event: unknown, data: unknown, item: { description?: string; name?: string }): void\r\n /** Chamado quando o jQuery File Upload falha a nível de rede */\r\n onFileFail(event: unknown, data: unknown): void\r\n}\r\n\r\n/** Operações de substituição dos handlers de upload do Fluig */\r\nexport interface IUploadHandlerOps {\r\n /**\r\n * Substitui `WKFViewAttachment.successRemoveAttachment` pela função fornecida.\r\n * Necessário para que `jsegd:upload:reset` dispare no `window` do iframe.\r\n */\r\n overrideSuccessRemoveAttachment(handler: (data: unknown[]) => void): void\r\n\r\n /**\r\n * Vincula handlers TypeScript ao `#ecm_navigation_fileupload` (jQuery File Upload).\r\n * Substitui os handlers nativos do Fluig; realiza toda a validação ECM internamente\r\n * e delega os pontos de extensão aos callbacks fornecidos.\r\n */\r\n bindFileUploadHandlers(callbacks: FileUploadCallbacks): void\r\n}\r\n\r\n/** Dados de processo via `ECM` */\r\nexport interface IProcessInfo {\r\n /**\r\n * Retorna o vetor de letras de permissão do usuário no processo.\r\n */\r\n getUserPermissions(): string[]\r\n\r\n /**\r\n * Retorna o `processInstanceId` do processo em execução (0 quando não persistido).\r\n */\r\n getProcessInstanceId(): number\r\n\r\n /**\r\n * Retorna o identificador do responsável pela tarefa atual.\r\n */\r\n getTaskUserId(): string\r\n\r\n /**\r\n * Retorna o número de sequência da movimentação atual do processo.\r\n */\r\n getWorkflowSequence(): number\r\n\r\n /**\r\n * Retorna todas as linhas da tabela de anexos do ECM.\r\n */\r\n getTableData(): { [key: string]: string }[]\r\n\r\n /**\r\n * Retorna a linha de índice `index` da tabela de anexos do ECM.\r\n */\r\n getTableRow(index: number): { [key: string]: string }\r\n}\r\n\r\n/** Utilitários do frame pai (document, Mustache, jQuery) */\r\nexport interface IParentEnv {\r\n /**\r\n * Documento DOM do frame pai (janela do processo).\r\n * Usado para manipulação direta do DOM do processo.\r\n */\r\n parentDocument: Document\r\n\r\n /**\r\n * Renderiza um template Mustache com o contexto fornecido.\r\n *\r\n * @throws {Error} quando `Mustache` não está disponível no contexto do processo\r\n */\r\n renderTemplate(template: string, data: object): string\r\n\r\n /**\r\n * Remove listeners de arrastar-e-soltar legados do processo\r\n * para evitar upload acidental ao arrastar arquivos na página.\r\n */\r\n removeDragListeners(): void\r\n}\r\n\r\n/**\r\n * Retorna o adapter de operações sobre anexos via `WKFViewAttachment`.\r\n *\r\n * @throws {Error} quando `WKFViewAttachment` não está disponível\r\n */\r\nexport function getAttachmentOps(): IAttachmentOps {\r\n if (!parent.WKFViewAttachment) {\r\n throw new Error('WKFViewAttachment não disponível no contexto do processo')\r\n }\r\n\r\n const { WKFViewAttachment } = parent\r\n\r\n return {\r\n getAllAttachments(): Attachment[] {\r\n return WKFViewAttachment.getAllAttachments()\r\n },\r\n\r\n openAttachmentView(colleagueId: string, documentId: number, version: number): void {\r\n WKFViewAttachment.openAttachmentView(colleagueId, documentId, version)\r\n },\r\n\r\n downloadAttach(indexes: number[]): void {\r\n WKFViewAttachment.downloadAttach(indexes)\r\n },\r\n\r\n confirmRemoveAttach(indexes: number[]): void {\r\n WKFViewAttachment.confirmRemoveAttach(indexes)\r\n },\r\n\r\n editAttach(row: { [key: string]: string }, index: number): void {\r\n // attachEdit não está nos tipos públicos de WKFViewAttachment\r\n ;(WKFViewAttachment as any).attachEdit(row, index)\r\n },\r\n\r\n deleteAttachmentSilent(attachment: Attachment): void {\r\n ;(WKFViewAttachment as any).deleteAttachments([attachment])\r\n },\r\n }\r\n}\r\n\r\n/**\r\n * Retorna o adapter de dados de processo via `ECM`.\r\n *\r\n * @throws {Error} quando `ECM` não está disponível\r\n */\r\nexport function getProcessInfo(): IProcessInfo {\r\n if (!parent.ECM) {\r\n throw new Error('ECM não disponível no contexto do processo')\r\n }\r\n\r\n const { ECM } = parent\r\n\r\n return {\r\n getUserPermissions(): string[] {\r\n return (ECM.workflowView as any).userPermissions ?? []\r\n },\r\n\r\n getProcessInstanceId(): number {\r\n return ECM.workflowView.processDefinition.processInstanceId\r\n },\r\n\r\n getTaskUserId(): string {\r\n return ECM.workflowView.processDefinition.taskUserId\r\n },\r\n\r\n getWorkflowSequence(): number {\r\n return ECM.workflowView.sequence\r\n },\r\n\r\n getTableData(): { [key: string]: string }[] {\r\n return ECM.attachmentTable.getData()\r\n },\r\n\r\n getTableRow(index: number): { [key: string]: string } {\r\n return ECM.attachmentTable.getRow(index)\r\n },\r\n }\r\n}\r\n\r\n/**\r\n * Retorna o adapter de utilitários do frame pai.\r\n * `Mustache` e `$` são validados internamente no método que os utiliza.\r\n */\r\nexport function getParentEnv(): IParentEnv {\r\n return {\r\n parentDocument: parent.document,\r\n\r\n renderTemplate(template: string, data: object): string {\r\n const mustache = (parent as any).Mustache\r\n if (!mustache) {\r\n throw new Error('Mustache não disponível no contexto do processo')\r\n }\r\n return mustache.render(template, data)\r\n },\r\n\r\n removeDragListeners(): void {\r\n const $ = (parent as any).$\r\n if (typeof $ === 'function') {\r\n $('#ecm_wkfview').off('drop dragover dragenter')\r\n $('#ecm-workflowView-attachment').off('drop dragover dragenter')\r\n }\r\n },\r\n }\r\n}\r\n\r\n/**\r\n * Retorna o adapter de substituição dos handlers de upload do Fluig.\r\n * Toda referência a `parent.$` e `parent.ECM` permanece neste módulo.\r\n */\r\nexport function getUploadHandlerOps(): IUploadHandlerOps {\r\n return {\r\n overrideSuccessRemoveAttachment(handler: (data: unknown[]) => void): void {\r\n ;(parent as any).WKFViewAttachment.successRemoveAttachment = handler.bind((parent as any).WKFViewAttachment)\r\n },\r\n\r\n bindFileUploadHandlers(callbacks: FileUploadCallbacks): void {\r\n const $ = (parent as any).$\r\n if (typeof $ !== 'function') return\r\n const getECM = () => (parent as any).ECM\r\n\r\n $('#ecm_navigation_fileupload')\r\n .off('fileuploadadd')\r\n .on('fileuploadadd', (e: any, data: any) => {\r\n const ECM = getECM()\r\n // Bloqueia se outro modal de upload estiver aberto\r\n if (ECM?.WKFViewAttachment?.validateUpload?.()) return false\r\n // Verifica permissão de publicação\r\n if (!ECM?.workflowView?.userPermissions?.includes('P')) {\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:error'))\r\n FLUIGC.toast({\r\n message: 'Usuário não possui permissão para publicar anexos',\r\n type: 'warning',\r\n })\r\n return false\r\n }\r\n // Remove duplicatas no mesmo lote\r\n const duplicated: number[] = []\r\n ;(data.files as File[]).filter((item, index, arr) => {\r\n if (arr.indexOf(item) !== index) duplicated.push(index)\r\n })\r\n duplicated\r\n .sort((a, b) => b - a)\r\n .forEach((idx) => (data.files as File[]).splice(idx, 1))\r\n // Registra cada arquivo no FileMonitor e verifica duplicata/tamanho\r\n let item: any = null\r\n ;(data.files as File[]).forEach((file) => {\r\n item = ECM.attachFileMonitor?.add({\r\n name: file.name,\r\n fullPath: ECM.WKFViewAttachment?.defFullPath ?? 'BPM',\r\n droppedZipZone: false,\r\n hasApprovers: ECM.WKFViewAttachment?.defHasApprovers ?? false,\r\n })\r\n const isDuplicate = (ECM.newAttachmentsDocs as any[])?.some(\r\n (d) => d.name === item?.name\r\n )\r\n if (isDuplicate) {\r\n ECM.attachFileMonitor?.error(item, 'Arquivo duplicado. Você tentou enviar um arquivo já anexado com este nome. ')\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:error'))\r\n return false\r\n }\r\n const maxMb = ECM.maxUploadSize ?? 0\r\n if (maxMb > 0 && file.size >= maxMb * 1024 * 1024) {\r\n ECM.attachFileMonitor?.error(item, `Tamanho total do arquivo ultrapassou o limite de ${ECM.core?.formatSize?.(maxMb) ?? maxMb + ' MB'}`)\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:error'))\r\n return false\r\n }\r\n if (data) {\r\n const datasUpload = ECM.WKFViewAttachment?.datasUpload ?? (window as any).datasUpload\r\n if (datasUpload) datasUpload[item.id] = data\r\n }\r\n data.context = item?.context\r\n })\r\n return callbacks.onFileAdd(e, data)\r\n })\r\n .off('fileuploaddone')\r\n .on('fileuploaddone', (e: any, data: any) => {\r\n const ECM = getECM()\r\n ;(data.result?.files as any[])?.forEach((file) => {\r\n let item: any = {}\r\n if (data.context) {\r\n item.id = data.context.data?.('item-id')\r\n item.fullPath = data.context.data?.('item-full-path')\r\n item.droppedZipZone = data.context.data?.('item-dropped-zip-zone')\r\n }\r\n if (file.error) {\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:error'))\r\n ECM?.attachFileMonitor?.error(item, file.error)\r\n } else if (item) {\r\n item.name = file.name\r\n item.internalId = Date.now()\r\n const el = $?.('#ecm-navigation-inputFile-clone')\r\n if (el?.attr?.('data-on-camera') === 'true') {\r\n const cameraName = el.attr('data-file-name-camera')\r\n if (cameraName) item.description = cameraName\r\n el.removeAttr('data-on-camera')\r\n el.removeAttr('data-file-name-camera')\r\n }\r\n item.uploadId = file.uploadId\r\n ECM?.WKFViewAttachment?.startPublishingDocument?.(null, item)\r\n callbacks.onFileDone(e, data, { description: item.description, name: item.name })\r\n }\r\n })\r\n })\r\n .off('fileuploadfail')\r\n .on('fileuploadfail', (e: any, data: any) => {\r\n if (data?.context) {\r\n const ECM = getECM()\r\n const item: any = { id: data.context.data?.('item-id') }\r\n ECM?.attachFileMonitor?.cancel?.(item)\r\n }\r\n callbacks.onFileFail(e, data)\r\n })\r\n },\r\n }\r\n}\r\n","import { getAttachmentOps, getParentEnv, getProcessInfo, getUploadHandlerOps, type IAttachmentOps, type IParentEnv, type IProcessInfo, type IUploadHandlerOps } from '../process-context'\r\n\r\n/** Permissões de operação sobre anexos */\r\nexport type AttachmentPermission = 'R' | 'P' | 'E' | 'D' | 'M' | 'O'\r\n\r\n/** Linha da tabela de anexos do processo */\r\nexport type AttachmentRow = { [key: string]: string }\r\n\r\n/**\r\n * Composição de todas as operações necessárias do ambiente de processo.\r\n * União das quatro interfaces segregadas de `process-context`.\r\n */\r\nexport type WorkflowContext = IAttachmentOps & IProcessInfo & IParentEnv & IUploadHandlerOps\r\n\r\n/**\r\n * Retorna o adapter de contexto do processo em execução.\r\n * Delega para as fábricas segregadas de `process-context`, cada uma validando\r\n * apenas o objeto `parent.*` de que depende.\r\n * Para substituir em testes, basta reimplementar as fábricas individuais.\r\n *\r\n * @throws {Error} quando `WKFViewAttachment` não está disponível\r\n * @throws {Error} quando `ECM` não está disponível\r\n */\r\nexport function getWorkflowContext(): WorkflowContext {\r\n return {\r\n ...getAttachmentOps(),\r\n ...getProcessInfo(),\r\n ...getParentEnv(),\r\n ...getUploadHandlerOps(),\r\n }\r\n}\r\n","import { GENERIC_ATTACHMENT_MARKER } from './attachment.constants'\r\nimport { getWorkflowContext } from './workflow-context'\r\n\r\n/**\r\n * Retorna `true` para anexos internos da biblioteca (prefixo `_jsegd_`).\r\n * Esses documentos nunca devem ser exibidos ao usuário.\r\n */\r\nexport function isMetadataAttachment(attachment: Attachment): boolean {\r\n return attachment.description.startsWith('_jsegd_')\r\n}\r\n\r\n/**\r\n * Retorna todos os anexos cujo prefixo de descrição corresponde ao valor informado.\r\n * Quando `description` é o marcador genérico, retorna todos os anexos que o contêm.\r\n */\r\nexport function getAttachmentsByDescription(description: string): Attachment[] {\r\n const context = getWorkflowContext()\r\n if (description === GENERIC_ATTACHMENT_MARKER) {\r\n return context.getAllAttachments().filter((attachment) => attachment.description.toLowerCase().includes(description.toLowerCase()))\r\n }\r\n return context\r\n .getAllAttachments()\r\n .filter((attachment) => attachment.description.replace(/_V\\d+$/, '').toLowerCase() === description.toLowerCase())\r\n}\r\n\r\n/**\r\n * Filtra a lista retornando apenas anexos já publicados (não são novos uploads pendentes).\r\n */\r\nexport function filterPublishedAttachments(attachments: Attachment[]): Attachment[] {\r\n return attachments.filter((attachment) => attachment.newAttach !== true)\r\n}\r\n\r\n/**\r\n * Retorna o índice na tabela de anexos do processo para a linha que satisfaz o predicado.\r\n * Centraliza o padrão `getTableData().findIndex()` usado em múltiplos locais.\r\n */\r\nexport function findAttachmentTableIndex(predicate: (row: { [key: string]: string }) => boolean): number {\r\n return getWorkflowContext().getTableData().findIndex(predicate)\r\n}\r\n\r\n/**\r\n * Retorna as descrições sem sufixo de versão dos anexos genéricos existentes,\r\n * sem duplicatas. Usado pelo autocomplete do modal de descrição.\r\n */\r\nexport function getGenericAttachmentDescriptions(): string[] {\r\n const attachments = getAttachmentsByDescription(GENERIC_ATTACHMENT_MARKER)\r\n const prefixes = attachments.map((a) => a.description.replace(/_Z__V\\d+$/, '').replace(/_Z_$/, ''))\r\n return [...new Set(prefixes)]\r\n}\r\n\r\n/**\r\n * Verifica se o usuário atual possui a permissão especificada no processo em curso.\r\n */\r\nexport function hasPermission(type: 'R' | 'P' | 'E' | 'D' | 'M' | 'O'): boolean {\r\n return getWorkflowContext().getUserPermissions().indexOf(type) >= 0\r\n}\r\n\r\n/**\r\n * Retorna `true` se o processo ainda não foi persistido (processInstanceId === 0).\r\n * Downloads e visualizações de documentos não publicados são bloqueados nesse estado.\r\n */\r\nexport function isNewProcess(): boolean {\r\n return getWorkflowContext().getProcessInstanceId() === 0\r\n}\r\n\r\n/**\r\n * Retorna `true` se o anexo pertence ao usuário atual.\r\n */\r\nexport function isOwnAttachment(attachment: Attachment): boolean {\r\n return attachment.colleagueId === getWorkflowContext().getTaskUserId()\r\n}\r\n\r\n/**\r\n * Verifica se o usuário pode editar o anexo fornecido.\r\n * - 'M': editar anexo próprio\r\n * - 'O': editar anexo de outros\r\n */\r\nexport function canEditAttachment(attachment: Attachment): boolean {\r\n if (isOwnAttachment(attachment)) {\r\n return hasPermission('M')\r\n }\r\n return hasPermission('O')\r\n}\r\n\r\n/**\r\n * Sanitiza campos de texto de um anexo antes de renderização em template HTML.\r\n * Protege contra XSS em campos que podem vir de entrada de usuário (description).\r\n */\r\nexport function sanitizeAttachmentForDisplay(attachment: Attachment): Attachment {\r\n return {\r\n ...attachment,\r\n description: attachment.description.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"'),\r\n }\r\n}\r\n\r\n/**\r\n * Sanitiza um nome de arquivo/descrição para uso seguro em upload programático.\r\n * Remove caracteres inválidos em nomes de arquivo, normaliza espaços, limita a 100 caracteres\r\n * e remove acentuação para garantir compatibilidade com sistemas de arquivo.\r\n */\r\nexport function sanitizeAttachmentName(input: string): string {\r\n let sanitized = input.replace(/[<>:\"/\\\\|?*\\x00-\\x1F]/g, '')\r\n sanitized = sanitized.replace(/\\s+/g, ' ').trim()\r\n if (sanitized.length > 100) {\r\n sanitized = sanitized.substring(0, 100)\r\n }\r\n sanitized = sanitized.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '')\r\n return sanitized\r\n}\r\n","/**\r\n * Calcula a próxima versão com base no maior número `_V{n}` encontrado nas descrições.\r\n */\r\nexport function getNextVersion(attachments: Attachment[]): number {\r\n let maxVersion = 0\r\n attachments.forEach((attachment) => {\r\n const match = attachment.description.match(/_V(\\d+)$/)\r\n if (match) {\r\n const version = parseInt(match[1], 10)\r\n maxVersion = Math.max(maxVersion, version)\r\n }\r\n })\r\n return maxVersion + 1\r\n}\r\n\r\n/**\r\n * Aplica a próxima versão à descrição, substituindo `_V{n}` existente ou adicionando `_V{n+1}`.\r\n */\r\nexport function applyNextVersion(description: string, attachments: Attachment[]): string {\r\n const nextVersion = getNextVersion(attachments)\r\n return description.replace(/_V\\d+$/, '') + `_V${nextVersion}`\r\n}\r\n","export type CallbackView = (params: { colleagueId: string; documentId: number; version: number }) => void\r\n\r\nexport type CallbackRemove = (params: { description: string }) => void\r\n\r\n/**\r\n * Modal de seleção de anexos exibido quando há mais de um com a mesma descrição.\r\n * Renderiza uma tabela FLUIGC com os anexos disponíveis e executa o callback ao selecionar um item.\r\n */\r\nexport class AttachmentPickerModal {\r\n private datatable: Datatable\r\n private modal: Modal\r\n\r\n constructor(attachments: Attachment[], callback: CallbackView | CallbackRemove) {\r\n const existing = parent.document.getElementById('modalPesquisa')\r\n if (existing) existing.remove()\r\n this.modal = this.createModal()\r\n this.datatable = this.createTable(attachments)\r\n this.bindEvents(callback)\r\n }\r\n\r\n private createTable(attachments: Attachment[]) {\r\n return parent.FLUIGC.datatable('#targetModal', {\r\n dataRequest: attachments,\r\n renderContent: ['attachedActivity', 'attachedUser', 'description'],\r\n header: [{ title: 'Atividade' }, { title: 'Solicitante' }, { title: 'Descrição' }],\r\n multiSelect: false,\r\n search: {\r\n enabled: false,\r\n onlyEnterkey: false,\r\n searchAreaStyle: 'col-12',\r\n onSearch: () => {},\r\n },\r\n scroll: { enabled: false },\r\n navButtons: { enabled: false },\r\n tableStyle: 'table-striped table-hover table-condensed',\r\n emptyMessage: 'Nenhum dado encontrado',\r\n classSelected: '',\r\n actions: {\r\n enabled: true,\r\n template: '',\r\n actionAreaStyle: '',\r\n },\r\n draggable: {\r\n enabled: false,\r\n onDrag: () => {},\r\n },\r\n })\r\n }\r\n\r\n private createModal() {\r\n const templateModelo = `\r\n <div class=\"row\">\r\n <div class=\"col-xs-12 col-sm-12 col-md-12 fs-xs-padding\" id=\"targetModal\">\r\n </div>\r\n </div>\r\n `\r\n return parent.FLUIGC.modal(\r\n {\r\n title: 'Pesquisar',\r\n content: templateModelo,\r\n id: 'modalPesquisa',\r\n size: 'full',\r\n actions: [],\r\n showHeader: true,\r\n showFooter: true,\r\n headerActions: [],\r\n headerContent: '',\r\n formModal: false,\r\n },\r\n () => {}\r\n )\r\n }\r\n\r\n private bindEvents(callback: CallbackView | CallbackRemove) {\r\n this.datatable.on('fluig.datatable.onselectrow', (data: DataCallback) => {\r\n const attachment = this.datatable.getRow(data.selectedIndex[0], false) as Attachment\r\n callback(attachment)\r\n // destroy() não está nos tipos públicos de Datatable do FLUIG SDK\r\n if (typeof (this.datatable as any).destroy === 'function') {\r\n ;(this.datatable as any).destroy()\r\n }\r\n this.modal.remove()\r\n })\r\n }\r\n}\r\n","import './attachment.events'\r\nimport {\r\n canEditAttachment,\r\n filterPublishedAttachments,\r\n findAttachmentTableIndex,\r\n getAttachmentsByDescription,\r\n hasPermission,\r\n isNewProcess,\r\n isOwnAttachment,\r\n sanitizeAttachmentName,\r\n} from './attachment.utils'\r\nimport { applyNextVersion } from './attachment.version'\r\nimport { AttachmentPickerModal } from './attachmentPickerModal'\r\nimport { GENERIC_ATTACHMENT_MARKER } from './attachment.constants'\r\nimport { getWorkflowContext } from './workflow-context'\r\nimport type { AttachmentSource } from './attachment-metadata'\r\n\r\n/**\r\n * @protected\r\n */\r\nexport class Attach {\r\n private static instance: Attach\r\n\r\n /** Origem do último upload iniciado (atualizado por `add()` e `uploadBlob()`) */\r\n static currentUploadSource: AttachmentSource = 'button'\r\n /** Filtro de tipos do último upload iniciado */\r\n static currentUploadAccept: string | null = null\r\n\r\n private constructor() {\r\n this.interceptUploadEvents()\r\n window.addEventListener('jsegd:attachment:download', ({ detail }) => {\r\n Attach.download(detail.documentId)\r\n })\r\n }\r\n\r\n public static getInstance(): Attach {\r\n if (!Attach.instance) {\r\n Attach.instance = new Attach()\r\n }\r\n return Attach.instance\r\n }\r\n\r\n private interceptUploadEvents(): void {\r\n const context = getWorkflowContext()\r\n\r\n // Remove drag-and-drop nativo do Fluig\r\n context.removeDragListeners()\r\n\r\n // Sobrescreve handler de remoção para disparar evento no window do iframe\r\n context.overrideSuccessRemoveAttachment((data: unknown[]) => {\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:reset'))\r\n const message = Array.isArray(data) && data.length > 1\r\n ? 'Os anexos foram removidos'\r\n : 'O anexo foi removido'\r\n FLUIGC.toast({ message, type: 'success' })\r\n })\r\n\r\n // Vincula handlers TypeScript ao jQuery File Upload\r\n context.bindFileUploadHandlers({\r\n onFileAdd: (_e: unknown, _data: unknown) => {\r\n // Validação completa é realizada em process-context.bindFileUploadHandlers\r\n },\r\n onFileDone: (_e: unknown, _data: unknown, item: { description?: string; name?: string }) => {\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:success', {\r\n detail: {\r\n description: item.description ?? item.name,\r\n source: Attach.currentUploadSource,\r\n accept: Attach.currentUploadAccept,\r\n },\r\n }))\r\n },\r\n onFileFail: (_e: unknown, _data: unknown) => {\r\n window.dispatchEvent(new CustomEvent('jsegd:upload:error'))\r\n },\r\n })\r\n }\r\n\r\n /**\r\n * Abre o seletor de arquivos para adicionar um novo anexo ao processo.\r\n * Aplica versionamento automático ao nome quando já existe um anexo com a mesma descrição.\r\n *\r\n * @param attachmentDescription Descrição (label) do anexo — usada como nome do arquivo no ECM\r\n * @param accept Tipos de arquivo aceitos pelo seletor (ex: \".pdf,.docx\"). `null` aceita qualquer tipo.\r\n */\r\n add(attachmentDescription: string, accept: string | null | undefined) {\r\n Attach.currentUploadSource = attachmentDescription === GENERIC_ATTACHMENT_MARKER ? 'toolbar' : 'button'\r\n Attach.currentUploadAccept = accept ?? null\r\n const element = parent.document.getElementById('ecm-navigation-inputFile-clone') as HTMLInputElement\r\n const attachments = getAttachmentsByDescription(attachmentDescription)\r\n if (accept) {\r\n element.setAttribute('accept', accept)\r\n }\r\n attachmentDescription = applyNextVersion(attachmentDescription, attachments)\r\n element.setAttribute('data-on-camera', 'true')\r\n element.setAttribute('data-file-name-camera', attachmentDescription)\r\n element.click()\r\n }\r\n\r\n /**\r\n * Abre o visualizador de documentos para o anexo informado.\r\n * Quando há mais de um anexo com a mesma descrição, exibe um modal de seleção.\r\n * Bloqueia ação em processos não iniciados e valida permissões de leitura.\r\n *\r\n * @param attachmentDescription Descrição do anexo a ser visualizado\r\n */\r\n view(attachmentDescription: string) {\r\n if (isNewProcess()) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Não é possível visualizar anexos em um processo não iniciado',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n const attachments = getAttachmentsByDescription(attachmentDescription)\r\n if (attachments.length === 0) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Não há documentos em anexo',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n const publishedAttachments = filterPublishedAttachments(attachments)\r\n if (publishedAttachments.length === 0) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Não é possível visualizar documentos anexados nesta etapa do processo',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n if (!hasPermission('R') && !publishedAttachments.some(isOwnAttachment)) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Usuário não possui permissão para visualizar anexos',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n const callback = ({ colleagueId, documentId, version }: { colleagueId: string; documentId: number; version: number }) => {\r\n getWorkflowContext().openAttachmentView(colleagueId, documentId, version)\r\n }\r\n new AttachmentPickerModal(publishedAttachments, callback)\r\n }\r\n\r\n /**\r\n * Remove um anexo do processo após confirmação via modal.\r\n * Quando há mais de um anexo com a mesma descrição, exibe um modal de seleção.\r\n * Valida permissões de exclusão antes de prosseguir.\r\n *\r\n * @param attachmentDescription Descrição do anexo a ser removido\r\n */\r\n remove(attachmentDescription: string) {\r\n if (!hasPermission('E') && !hasPermission('D')) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Usuário não possui permissão para remover anexos',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n const attachments = getAttachmentsByDescription(attachmentDescription)\r\n if (attachments.length === 0) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Não há documentos em anexo',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n const context = getWorkflowContext()\r\n const callback = ({ description }: { description: string }) => {\r\n const index = findAttachmentTableIndex((row) => row['description'] === description)\r\n context.confirmRemoveAttach([index])\r\n }\r\n new AttachmentPickerModal(attachments, callback)\r\n }\r\n\r\n /**\r\n * Inicia o download de um anexo pelo seu identificador de documento.\r\n * Bloqueia a ação em processos não iniciados.\r\n *\r\n * @param documentId Identificador do documento a ser baixado\r\n */\r\n public static download(documentId: number): void {\r\n if (isNewProcess()) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Não é possível fazer download de anexos em um processo não iniciado',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n const index = findAttachmentTableIndex((row) => row['documentId'] === String(documentId))\r\n if (index >= 0) {\r\n getWorkflowContext().downloadAttach([index])\r\n }\r\n }\r\n\r\n /**\r\n * Abre o painel de edição de conteúdo para o anexo informado.\r\n * Filtra apenas anexos publicados que o usuário tem permissão de editar.\r\n * Quando há mais de um anexo editável, exibe modal de seleção.\r\n * Bloqueia a ação em processos não iniciados.\r\n *\r\n * @param attachmentDescription Descrição do anexo a ser editado\r\n */\r\n edit(attachmentDescription: string) {\r\n if (isNewProcess()) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Não é possível editar anexos em um processo não iniciado',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n const allAttachments = getAttachmentsByDescription(attachmentDescription)\r\n const editableAttachments = filterPublishedAttachments(allAttachments).filter(canEditAttachment)\r\n if (editableAttachments.length === 0) {\r\n FLUIGC.toast({\r\n title: 'Aviso',\r\n message: 'Nenhum anexo disponível para edição',\r\n type: 'warning',\r\n })\r\n return\r\n }\r\n const context = getWorkflowContext()\r\n const callback = ({ description }: { description: string }) => {\r\n const index = findAttachmentTableIndex((row) => row['description'] === description)\r\n if (index >= 0) {\r\n context.editAttach(context.getTableRow(index), index)\r\n }\r\n }\r\n new AttachmentPickerModal(editableAttachments, callback)\r\n }\r\n\r\n /**\r\n * Retorna todos os anexos do processo atual.\r\n * @returns Lista de todos os objetos `Attachment` presentes no processo\r\n */\r\n public static getAllAttachments(): Attachment[] {\r\n return getWorkflowContext().getAllAttachments()\r\n }\r\n\r\n /**\r\n * Inicia o download de um Blob diretamente no navegador do usuário,\r\n * sem interação com o ECM ou com o processo em execução.\r\n *\r\n * @param blob Conteúdo a ser baixado\r\n * @param filename Nome do arquivo que será sugerido ao navegador\r\n * @param type Tipo MIME do arquivo. Quando omitido, usa `blob.type`.\r\n */\r\n public static downloadBlob(blob: Blob, filename: string, type?: string): void {\r\n const file = type ? new Blob([blob], { type }) : blob\r\n const url = URL.createObjectURL(file)\r\n const a = document.createElement('a')\r\n a.href = url\r\n a.download = filename\r\n a.click()\r\n URL.revokeObjectURL(url)\r\n }\r\n\r\n /**\r\n * Faz upload programático de um Blob como anexo do processo,\r\n * sem abrir o seletor de arquivos nativo. Sanitiza o nome antes do envio.\r\n *\r\n * @param blob Arquivo no formato `Blob` — deve ser não-vazio\r\n * @param description Nome/descrição do arquivo que será exibido no ECM\r\n * @param type Tipo MIME do arquivo. Quando omitido, usa `blob.type`.\r\n * @throws {Error} Via toast quando o Blob é inválido, o MIME está ausente ou o contexto não está disponível\r\n */\r\n public static uploadBlob(blob: Blob, description: string, type?: string): void {\r\n Attach.currentUploadSource = 'drag-drop'\r\n Attach.currentUploadAccept = null\r\n if (!(blob instanceof Blob) || blob.size === 0) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Blob inválido ou vazio.',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n const mimeType = type || blob.type\r\n if (!mimeType) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Tipo MIME não especificado.',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n if (!parent || !parent.document) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Contexto parent.document não disponível.',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n const inputFile = parent.document.getElementById('ecm-navigation-inputFile-clone') as HTMLInputElement | null\r\n if (!inputFile) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Elemento de input de upload não encontrado.',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n const safeDescription = sanitizeAttachmentName(description)\r\n const file = new File([blob], safeDescription, { type: mimeType })\r\n const dt = new DataTransfer()\r\n dt.items.add(file)\r\n inputFile.files = dt.files\r\n inputFile.dispatchEvent(new Event('change'))\r\n }\r\n}\r\n","import { sanitizeAttachmentName } from './attachment.utils'\r\n\r\n/** Entrada de um arquivo para upload em lote via drag-and-drop */\r\nexport type DragDropEntry = { file: File; name: string }\r\n\r\n/**\r\n * Modal de associação de nomes para upload em lote via drag-and-drop.\r\n * Exibe todos os arquivos arrastados de uma vez, com campo de nome editável por linha\r\n * e checkbox global \"Usar nomes originais dos arquivos\".\r\n * @hideconstructor\r\n */\r\nexport class DragDropNameModal {\r\n private readonly modal: any\r\n private readonly files: File[]\r\n private readonly onConfirm: (entries: DragDropEntry[]) => void\r\n\r\n constructor(files: FileList, onConfirm: (entries: DragDropEntry[]) => void) {\r\n this.files = Array.from(files)\r\n this.onConfirm = onConfirm\r\n\r\n const rows = this.files\r\n .map(\r\n (f, i) => `\r\n <div style=\"display:flex;align-items:center;gap:8px;margin-bottom:6px\">\r\n <span style=\"flex:0 0 auto;font-size:12px;color:#555;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap\" title=\"${sanitizeAttributeValue(f.name)}\">${sanitizeText(f.name)}</span>\r\n <input\r\n type=\"text\"\r\n class=\"form-control input-sm drag-drop-name-input\"\r\n data-index=\"${i}\"\r\n value=\"${sanitizeAttributeValue(sanitizeAttachmentName(f.name))}\"\r\n style=\"flex:1\"\r\n />\r\n </div>`\r\n )\r\n .join('')\r\n\r\n const content = `\r\n <div id=\"drag-drop-name-modal-body\">\r\n <div style=\"margin-bottom:10px\">\r\n <label style=\"cursor:pointer;font-weight:normal\">\r\n <input type=\"checkbox\" id=\"drag-drop-use-originals\" style=\"margin-right:6px\">\r\n Usar nomes originais dos arquivos\r\n </label>\r\n </div>\r\n ${rows}\r\n </div>`\r\n\r\n const cfg = {\r\n title: 'Associar nomes aos arquivos',\r\n content: content,\r\n id: 'drag-drop-name-modal',\r\n size: 'medium',\r\n showHeader: true,\r\n showFooter: true,\r\n headerActions: [],\r\n headerContent: '',\r\n formModal: false,\r\n actions: [\r\n { label: 'Cancelar', classType: 'btn-default', autoClose: true },\r\n { label: 'Confirmar', classType: 'btn-primary', bind: 'data-drag-drop-confirm' },\r\n ],\r\n }\r\n\r\n this.modal = FLUIGC.modal(cfg, () => {})\r\n this.bindEvents()\r\n }\r\n\r\n private bindEvents(): void {\r\n // Checkbox \"usar nomes originais\"\r\n document.addEventListener('change', this.handleUseOriginals)\r\n\r\n // Botão confirmar\r\n document\r\n .querySelector('[data-drag-drop-confirm]')\r\n ?.addEventListener('click', () => this.confirm())\r\n }\r\n\r\n private handleUseOriginals = (e: Event): void => {\r\n const target = e.target as HTMLInputElement\r\n if (target.id !== 'drag-drop-use-originals') return\r\n const inputs = document.querySelectorAll<HTMLInputElement>('.drag-drop-name-input')\r\n inputs.forEach((input, i) => {\r\n input.disabled = target.checked\r\n if (target.checked) {\r\n input.value = sanitizeAttachmentName(this.files[i]?.name ?? '')\r\n }\r\n })\r\n }\r\n\r\n private confirm(): void {\r\n const inputs = document.querySelectorAll<HTMLInputElement>('.drag-drop-name-input')\r\n const entries: DragDropEntry[] = this.files.map((file, i) => ({\r\n file,\r\n name: sanitizeAttachmentName((inputs[i]?.value || file.name).trim()),\r\n }))\r\n\r\n document.removeEventListener('change', this.handleUseOriginals)\r\n this.modal?.remove?.()\r\n this.onConfirm(entries)\r\n }\r\n}\r\n\r\n/** Escapa texto para inserção como conteúdo de elemento HTML */\r\nfunction sanitizeText(text: string): string {\r\n return text\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n}\r\n\r\n/** Escapa texto para uso em atributos HTML entre aspas duplas */\r\nfunction sanitizeAttributeValue(text: string): string {\r\n return sanitizeText(text).replace(/\"/g, '"')\r\n}\r\n","import { Attach } from './attach'\r\nimport { METADATA_ATTACHMENT_NAME } from './attachment.constants'\r\nimport { getWorkflowContext } from './workflow-context'\r\n\r\n/** Origem do upload de um anexo */\r\nexport type AttachmentSource = 'button' | 'toolbar' | 'drag-drop'\r\n\r\n/**\r\n * Metadados associados a um único documento anexado ao processo.\r\n * Persiste informações que o ECM não armazena nativamente.\r\n */\r\nexport interface AttachmentRecord {\r\n /** ID do documento no ECM */\r\n documentId: number\r\n /** Mecanismo pelo qual o arquivo foi adicionado */\r\n source: AttachmentSource\r\n /**\r\n * Descrição base do `AttachButton` que originou o upload.\r\n * Presente apenas quando `source === 'button'`.\r\n */\r\n buttonDescription?: string\r\n /** Filtro de tipos de arquivo ativo no momento do upload (`null` = qualquer tipo) */\r\n accept: string | null\r\n /** Número de sequência da movimentação do processo em que foi anexado */\r\n workflowSequence: number\r\n /** Data e hora do upload em ISO 8601 */\r\n uploadedAt: string\r\n /**\r\n * Metadados arbitrários adicionados pelo consumidor da biblioteca.\r\n * Nunca interpretado internamente — apenas serializado/desserializado.\r\n */\r\n custom?: Record<string, unknown>\r\n}\r\n\r\n/** Configuração persistida de um `AttachButton` registrado */\r\nexport interface ButtonRecord {\r\n /** Filtro de tipos de arquivo definido no atributo `accept` do botão */\r\n accept: string | null\r\n}\r\n\r\n/** Schema do arquivo `_jsegd_metadata.json` armazenado como anexo interno do processo */\r\nexport interface AttachmentMetadata {\r\n /** Versão do schema — permite migrações sem quebra ao evoluir a estrutura */\r\n version: number\r\n /**\r\n * Registry de botões registrados.\r\n * Chave: `description` do botão em lowercase sem sufixo de versão.\r\n */\r\n buttons: Record<string, ButtonRecord>\r\n /**\r\n * Metadados por documento anexado.\r\n * Chave: `String(documentId)`.\r\n */\r\n attachments: Record<string, AttachmentRecord>\r\n /** Data e hora da última gravação em ISO 8601 */\r\n updatedAt: string\r\n}\r\n\r\n/**\r\n * Cache de sessão em memória.\r\n * `undefined` = não carregado; `null` = carregado, sem arquivo; objeto = dados válidos.\r\n */\r\nlet sessionCache: AttachmentMetadata | null | undefined = undefined\r\n\r\n/**\r\n * Gerencia o arquivo de metadados oculto `_jsegd_metadata` do processo.\r\n * @internal — não exportado pelo barrel público; uso exclusivo da biblioteca.\r\n */\r\nexport class AttachmentMetadataFile {\r\n private static readonly CURRENT_VERSION = 1\r\n\r\n /**\r\n * Verifica de forma síncrona se o arquivo de metadados já existe no processo.\r\n * Retorna `false` em nova solicitação (documentId ainda não atribuído).\r\n */\r\n static exists(): boolean {\r\n return !!AttachmentMetadataFile.findAttachment()\r\n }\r\n\r\n /**\r\n * Retorna o anexo de metadados se existir e já possuir `documentId`.\r\n * Retorna `undefined` quando não há anexo com a descrição interna\r\n * ou quando `documentId === 0` (nova solicitação).\r\n */\r\n private static findAttachment(): Attachment | undefined {\r\n const att = Attach.getAllAttachments().find(\r\n (a) => a.description === METADATA_ATTACHMENT_NAME\r\n )\r\n return att?.documentId ? att : undefined\r\n }\r\n\r\n /**\r\n * Carrega e desserializa o arquivo de metadados do processo.\r\n * Resultado memoizado durante a sessão.\r\n * Retorna `null` quando o arquivo não existe ou o processo é nova solicitação.\r\n *\r\n * @param force Ignora o cache de sessão e recarrega do ECM\r\n * @throws {Error} quando o fetch falha com status HTTP ≥ 400\r\n */\r\n static async load(force = false): Promise<AttachmentMetadata | null> {\r\n if (!force && sessionCache !== undefined) return sessionCache\r\n\r\n const attachment = AttachmentMetadataFile.findAttachment()\r\n if (!attachment) {\r\n sessionCache = null\r\n return null\r\n }\r\n\r\n // Content Management API v2 — não requer companyId nem version\r\n const url = `/content-management/api/v2/documents/${attachment.documentId}/stream`\r\n const response = await fetch(url, { credentials: 'include' })\r\n if (!response.ok) {\r\n throw new Error(`Falha ao carregar metadados: HTTP ${response.status}`)\r\n }\r\n\r\n const raw: unknown = await response.json()\r\n sessionCache = AttachmentMetadataFile.parseAndMigrate(raw)\r\n return sessionCache\r\n }\r\n\r\n /**\r\n * Persiste os metadados no processo atual.\r\n *\r\n * - Sempre atualiza o `sessionCache` em memória.\r\n * - Não persiste no ECM quando `processInstanceId === 0`\r\n * (nova solicitação — documentIds ainda não atribuídos).\r\n * - Remove o anexo anterior de forma silenciosa antes de subir o novo:\r\n * o Fluig não versiona pelo nome — cria um duplicado se o anterior existir.\r\n *\r\n * @param metadata Dados a persistir\r\n */\r\n static save(metadata: AttachmentMetadata): void {\r\n const updated: AttachmentMetadata = {\r\n ...metadata,\r\n updatedAt: new Date().toISOString(),\r\n }\r\n\r\n // Atualiza o memo imediatamente\r\n sessionCache = updated\r\n\r\n // Guard: nova solicitação ainda não tem processInstanceId\r\n const ctx = getWorkflowContext()\r\n if (!ctx.getProcessInstanceId()) return\r\n\r\n // Remove o anexo anterior silenciosamente (sem diálogo, sem toast).\r\n // Attach.remove() não pode ser usado — abre modal de confirmação.\r\n const existing = AttachmentMetadataFile.findAttachment()\r\n if (existing) {\r\n ctx.deleteAttachmentSilent(existing)\r\n }\r\n\r\n const json = JSON.stringify(updated, null, 2)\r\n const blob = new Blob([json], { type: 'application/json' })\r\n Attach.uploadBlob(blob, METADATA_ATTACHMENT_NAME, 'application/json')\r\n }\r\n\r\n /**\r\n * Desserializa e migra o schema se necessário.\r\n * Garante que dados corrompidos ou parciais resultam em estrutura válida.\r\n */\r\n private static parseAndMigrate(raw: unknown): AttachmentMetadata {\r\n if (typeof raw !== 'object' || raw === null) {\r\n return AttachmentMetadataFile.empty()\r\n }\r\n\r\n const data = raw as Partial<AttachmentMetadata>\r\n\r\n // Versão 1 é a inicial — sem migração necessária por enquanto\r\n // Estrutura para versões futuras:\r\n // if ((data.version ?? 0) < 2) data = migrateV1toV2(data)\r\n\r\n return {\r\n version: AttachmentMetadataFile.CURRENT_VERSION,\r\n buttons: data.buttons ?? {},\r\n attachments: data.attachments ?? {},\r\n updatedAt: data.updatedAt ?? new Date().toISOString(),\r\n }\r\n }\r\n\r\n /** Retorna um objeto de metadados vazio com a versão atual do schema */\r\n static empty(): AttachmentMetadata {\r\n return {\r\n version: AttachmentMetadataFile.CURRENT_VERSION,\r\n buttons: {},\r\n attachments: {},\r\n updatedAt: new Date().toISOString(),\r\n }\r\n }\r\n}\r\n","import { Attach } from './attach'\r\nimport {\r\n canEditAttachment,\r\n hasPermission,\r\n isMetadataAttachment,\r\n isNewProcess,\r\n isOwnAttachment,\r\n sanitizeAttachmentForDisplay,\r\n sanitizeAttachmentName,\r\n} from './attachment.utils'\r\nimport { GENERIC_ATTACHMENT_MARKER, UNPUBLISHED_VERSION_DISPLAY } from './attachment.constants'\r\nimport { getWorkflowContext } from './workflow-context'\r\nimport { DragDropNameModal } from './drag-drop-name-modal'\r\nimport { AttachmentMetadataFile } from './attachment-metadata'\r\nimport type { AttachmentRecord, AttachmentSource } from './attachment-metadata'\r\n\r\n/** Seletor do container raiz criado pela classe no DOM do frame pai */\r\nconst CONTAINER_ID = 'attachmentsCustom'\r\n/** Seletor do toolbar criado acima do container no modo `self-managed` */\r\nconst TOOLBAR_ID = 'attachmentsToolbar'\r\n\r\n/**\r\n * Modo de operação da tabela de anexos.\r\n * - `buttons-only` — somente download por linha; uploads exclusivamente via `AttachButton` externos\r\n * - `self-managed` — gerencia seu próprio ciclo de upload; exibe ações completas por linha;\r\n * aceita `AttachButton` externos cujos atributos são herdados pela linha do anexo\r\n */\r\nexport type AttachmentsTableMode = 'buttons-only' | 'self-managed'\r\n\r\n/** Opções de configuração de `AttachmentsTable` */\r\nexport interface AttachmentsTableOptions {\r\n /** Modo de operação. Obrigatório — sem valor padrão. */\r\n mode: AttachmentsTableMode\r\n /**\r\n * Tipos de arquivo aceitos nos uploads avulsos do modo `self-managed`.\r\n * Ex: `\".pdf,.docx\"`. `null` aceita qualquer tipo.\r\n */\r\n accept?: string | null\r\n}\r\n\r\n/**\r\n * Registro de um `AttachButton` na `AttachmentsTable`.\r\n * Armazenado para associar anexos existentes ao botão que os originou.\r\n */\r\nexport interface AttachButtonRegistration {\r\n /** Descrição base usada pelo botão (sem sufixo `_V\\d+`). */\r\n description: string\r\n /** Filtro de tipos de arquivo definido no botão. */\r\n accept: string | null\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Templates Mustache\r\n// ---------------------------------------------------------------------------\r\n\r\nconst THEAD = `\r\n <thead>\r\n <tr>\r\n <th data-sort=\"title\" data-order=\"asc\" style=\"cursor:pointer\">\r\n Nome <i class=\"flaticon flaticon-ordenation icon-xs\" aria-hidden=\"true\" style=\"margin-left:8px\"></i>\r\n </th>\r\n <th>Documento</th>\r\n <th>Versão</th>\r\n <th data-sort=\"user\" data-order=\"asc\" style=\"cursor:pointer\">\r\n Usuário <i class=\"flaticon flaticon-ordenation icon-xs\" aria-hidden=\"true\" style=\"margin-left:8px\"></i>\r\n </th>\r\n <th data-sort=\"date\" data-order=\"asc\" style=\"cursor:pointer\">\r\n Data <i class=\"flaticon flaticon-ordenation icon-xs\" aria-hidden=\"true\" style=\"margin-left:8px\"></i>\r\n </th>\r\n <th data-sort=\"activity\" data-order=\"asc\" style=\"cursor:pointer\">\r\n Atividade <i class=\"flaticon flaticon-ordenation icon-xs\" aria-hidden=\"true\" style=\"margin-left:8px\"></i>\r\n </th>\r\n <th></th>\r\n </tr>\r\n </thead>`\r\n\r\nconst TEMPLATE_BUTTONS_ONLY = `\r\n<table class=\"table table-condensed\" id=\"attachmentsTableCustom\">\r\n <caption>Lista de documentos anexados</caption>\r\n ${THEAD}\r\n <tbody>\r\n {{#attachments}}\r\n <tr>\r\n <td>\r\n {{#iconUrl}}<img src=\"/webdesk/{{iconPath}}\" class=\"iconAttachDoc\" />{{/iconUrl}}\r\n {{^iconUrl}}<i class=\"fluigicon fluigicon-md {{iconClass}}\"></i>{{/iconUrl}}\r\n <a href=\"#\"\r\n data-attachment-open\r\n data-colleague-id=\"{{colleagueId}}\"\r\n data-document-id=\"{{documentId}}\"\r\n data-version=\"{{version}}\"\r\n class=\"fs-sm-margin-left\">{{description}}</a>\r\n </td>\r\n <td>{{documentId}}</td>\r\n <td><span>{{#version}}{{version}}{{/version}}{{^version}}{{unpublishedVersion}}{{/version}}</span></td>\r\n <td>{{attachedUser}}</td>\r\n <td><span>{{#attachedDate}}{{attachedDate}}{{/attachedDate}}{{^attachedDate}}Ainda não publicado{{/attachedDate}}</span></td>\r\n <td>{{attachedActivity}}</td>\r\n <td>\r\n {{#enableDownload}}\r\n <i class=\"flaticon flaticon-download icon-sm\"\r\n aria-hidden=\"true\"\r\n data-attachment-download\r\n data-document-id=\"{{documentId}}\"\r\n style=\"cursor:pointer\"></i>\r\n {{/enableDownload}}\r\n </td>\r\n </tr>\r\n {{/attachments}}\r\n </tbody>\r\n</table>`\r\n\r\nconst TEMPLATE_SELF_MANAGED = `\r\n<table class=\"table table-condensed\" id=\"attachmentsTableCustom\">\r\n <caption>Lista de documentos anexados</caption>\r\n ${THEAD}\r\n <tbody>\r\n {{#attachments}}\r\n <tr>\r\n <td>\r\n {{#iconUrl}}<img src=\"/webdesk/{{iconPath}}\" class=\"iconAttachDoc\" />{{/iconUrl}}\r\n {{^iconUrl}}<i class=\"fluigicon fluigicon-md {{iconClass}}\"></i>{{/iconUrl}}\r\n <a href=\"#\"\r\n data-attachment-open\r\n data-colleague-id=\"{{colleagueId}}\"\r\n data-document-id=\"{{documentId}}\"\r\n data-version=\"{{version}}\"\r\n class=\"fs-sm-margin-left\">{{description}}</a>\r\n </td>\r\n <td>{{documentId}}</td>\r\n <td><span>{{#version}}{{version}}{{/version}}{{^version}}{{unpublishedVersion}}{{/version}}</span></td>\r\n <td>{{attachedUser}}</td>\r\n <td><span>{{#attachedDate}}{{attachedDate}}{{/attachedDate}}{{^attachedDate}}Ainda não publicado{{/attachedDate}}</span></td>\r\n <td>{{attachedActivity}}</td>\r\n <td class=\"attachments-actions\" style=\"white-space:nowrap\">\r\n {{#enableView}}\r\n <i class=\"flaticon flaticon-view icon-sm\" aria-hidden=\"true\"\r\n data-attachment-open\r\n data-colleague-id=\"{{colleagueId}}\"\r\n data-document-id=\"{{documentId}}\"\r\n data-version=\"{{version}}\"\r\n title=\"Visualizar\"\r\n style=\"cursor:pointer;margin-right:4px\"></i>\r\n {{/enableView}}\r\n {{#enableReversion}}\r\n <i class=\"flaticon flaticon-upload icon-sm\" aria-hidden=\"true\"\r\n data-attachment-reversion\r\n data-document-id=\"{{documentId}}\"\r\n data-button-description=\"{{buttonDescription}}\"\r\n data-button-accept=\"{{buttonAccept}}\"\r\n title=\"Nova versão\"\r\n style=\"cursor:pointer;margin-right:4px\"></i>\r\n {{/enableReversion}}\r\n {{#enableEdit}}\r\n <i class=\"flaticon flaticon-pencil icon-sm\" aria-hidden=\"true\"\r\n data-attachment-edit\r\n data-document-id=\"{{documentId}}\"\r\n title=\"Editar conteúdo\"\r\n style=\"cursor:pointer;margin-right:4px\"></i>\r\n {{/enableEdit}}\r\n {{#enableDownload}}\r\n <i class=\"flaticon flaticon-download icon-sm\" aria-hidden=\"true\"\r\n data-attachment-download\r\n data-document-id=\"{{documentId}}\"\r\n title=\"Download\"\r\n style=\"cursor:pointer;margin-right:4px\"></i>\r\n {{/enableDownload}}\r\n {{#enableDelete}}\r\n <i class=\"flaticon flaticon-trash icon-sm\" aria-hidden=\"true\"\r\n data-attachment-delete\r\n data-document-id=\"{{documentId}}\"\r\n title=\"Excluir\"\r\n style=\"cursor:pointer\"></i>\r\n {{/enableDelete}}\r\n </td>\r\n </tr>\r\n {{/attachments}}\r\n </tbody>\r\n</table>`\r\n\r\nconst TOOLBAR_HTML = `\r\n<div id=\"${TOOLBAR_ID}\" style=\"margin-bottom:8px\">\r\n <div class=\"btn-group\">\r\n <button type=\"button\" class=\"btn btn-sm btn-default\" data-attach-quick title=\"Anexar arquivo usando o nome original\">\r\n <i class=\"flaticon flaticon-add\" aria-hidden=\"true\"></i> Novo Anexo\r\n </button>\r\n <button type=\"button\" class=\"btn btn-sm btn-default dropdown-toggle\" data-toggle=\"dropdown\" aria-expanded=\"false\">\r\n <span class=\"caret\"></span>\r\n </button>\r\n <ul class=\"dropdown-menu\" role=\"menu\">\r\n <li><a href=\"#\" data-attach-quick>Usar nome do arquivo</a></li>\r\n <li><a href=\"#\" data-attach-named>Informar nome antes de anexar</a></li>\r\n </ul>\r\n </div>\r\n</div>`\r\n\r\n// ---------------------------------------------------------------------------\r\n// Classe principal\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Cria e gerencia uma tabela de anexos customizada no frame pai,\r\n * mantendo a tabela nativa do Fluig oculta.\r\n * @hideconstructor\r\n */\r\nexport class AttachmentsTable {\r\n private static instance: AttachmentsTable\r\n private static options: AttachmentsTableOptions\r\n private static attachInstance: Attach | null = null\r\n private static buttonRegistry: Map<string, AttachButtonRegistration> = new Map()\r\n\r\n private constructor() {\r\n AttachmentsTable.start()\r\n }\r\n\r\n /**\r\n * Retorna a instância singleton da tabela de anexos.\r\n * Deve ser chamado uma única vez durante a inicialização do form.\r\n *\r\n * @param options Configuração obrigatória de modo e accept\r\n */\r\n public static getInstance(options: AttachmentsTableOptions): AttachmentsTable {\r\n if (!AttachmentsTable.instance) {\r\n AttachmentsTable.options = options\r\n if (options.mode === 'self-managed') {\r\n AttachmentsTable.attachInstance = Attach.getInstance()\r\n }\r\n AttachmentsTable.instance = new AttachmentsTable()\r\n void AttachmentsTable.hydrateFromMetadata()\r\n }\r\n return AttachmentsTable.instance\r\n }\r\n\r\n /**\r\n * Registra um `AttachButton` para que seus metadados sejam associados\r\n * às linhas de anexo originadas por aquele botão.\r\n * Só tem efeito no modo `self-managed`.\r\n * @internal Chamado por `AttachButton` durante sua inicialização.\r\n */\r\n public static registerButton(registration: AttachButtonRegistration): void {\r\n if (AttachmentsTable.options?.mode !== 'self-managed') return\r\n AttachmentsTable.buttonRegistry.set(registration.description.toLowerCase(), registration)\r\n void AttachmentsTable.persistMetadata()\r\n }\r\n\r\n private static resolveButtonRegistration(attachment: Attachment): AttachButtonRegistration | undefined {\r\n const base = attachment.description.replace(/_V\\d+$/, '').toLowerCase()\r\n return AttachmentsTable.buttonRegistry.get(base)\r\n }\r\n\r\n private static start(): void {\r\n const context = getWorkflowContext()\r\n\r\n context.removeDragListeners()\r\n\r\n const nativeContainer = context.parentDocument.getElementById('ecm-workflowView-attachment') as HTMLElement | null\r\n if (nativeContainer) nativeContainer.style.display = 'none'\r\n\r\n const attachmentsRoot = context.parentDocument.getElementById('attachments')\r\n if (attachmentsRoot) {\r\n if (AttachmentsTable.options?.mode === 'self-managed') {\r\n const toolbarWrapper = context.parentDocument.createElement('div')\r\n toolbarWrapper.innerHTML = TOOLBAR_HTML\r\n attachmentsRoot.appendChild(toolbarWrapper.firstElementChild!)\r\n }\r\n const container = context.parentDocument.createElement('div')\r\n container.id = CONTAINER_ID\r\n attachmentsRoot.appendChild(container)\r\n }\r\n\r\n AttachmentsTable.render()\r\n\r\n // Event delegation — container\r\n context.parentDocument.getElementById(CONTAINER_ID)?.addEventListener('click', (event: Event) => {\r\n const target = event.target as HTMLElement\r\n\r\n const openLink = target.closest('[data-attachment-open]') as HTMLElement | null\r\n if (openLink) {\r\n event.preventDefault()\r\n const colleagueId = openLink.getAttribute('data-colleague-id') ?? ''\r\n const documentId = Number(openLink.getAttribute('data-document-id'))\r\n const version = Number(openLink.getAttribute('data-version'))\r\n context.openAttachmentView(colleagueId, documentId, version)\r\n return\r\n }\r\n\r\n const downloadIcon = target.closest('[data-attachment-download]') as HTMLElement | null\r\n if (downloadIcon) {\r\n event.preventDefault()\r\n const documentId = Number(downloadIcon.getAttribute('data-document-id'))\r\n window.dispatchEvent(new CustomEvent('jsegd:attachment:download', { detail: { documentId } }))\r\n return\r\n }\r\n\r\n const th = target.closest('th[data-sort]') as HTMLElement | null\r\n if (th) {\r\n const column = th.getAttribute('data-sort') as SortColumn\r\n const ascending = th.getAttribute('data-order') === 'asc'\r\n AttachmentsTable.sortBy(column, ascending)\r\n th.setAttribute('data-order', ascending ? 'desc' : 'asc')\r\n return\r\n }\r\n\r\n if (AttachmentsTable.options?.mode !== 'self-managed') return\r\n\r\n const editIcon = target.closest('[data-attachment-edit]') as HTMLElement | null\r\n if (editIcon) {\r\n event.preventDefault()\r\n const documentId = Number(editIcon.getAttribute('data-document-id'))\r\n const attachment = Attach.getAllAttachments().find((a) => a.documentId === documentId)\r\n if (attachment) AttachmentsTable.attachInstance?.edit(attachment.description)\r\n return\r\n }\r\n\r\n const reversionIcon = target.closest('[data-attachment-reversion]') as HTMLElement | null\r\n if (reversionIcon) {\r\n event.preventDefault()\r\n const btnDescription = reversionIcon.getAttribute('data-button-description') ?? ''\r\n const btnAccept = reversionIcon.getAttribute('data-button-accept') || null\r\n AttachmentsTable.attachInstance?.add(btnDescription, btnAccept)\r\n return\r\n }\r\n\r\n const deleteIcon = target.closest('[data-attachment-delete]') as HTMLElement | null\r\n if (deleteIcon) {\r\n event.preventDefault()\r\n const documentId = Number(deleteIcon.getAttribute('data-document-id'))\r\n const attachment = Attach.getAllAttachments().find((a) => a.documentId === documentId)\r\n if (attachment) AttachmentsTable.attachInstance?.remove(attachment.description)\r\n return\r\n }\r\n })\r\n\r\n // Event delegation — toolbar (self-managed)\r\n if (AttachmentsTable.options?.mode === 'self-managed') {\r\n context.parentDocument.getElementById(TOOLBAR_ID)?.addEventListener('click', (event: Event) => {\r\n const target = event.target as HTMLElement\r\n\r\n const quickBtn = target.closest('[data-attach-quick]') as HTMLElement | null\r\n if (quickBtn) {\r\n event.preventDefault()\r\n if (!hasPermission('P')) {\r\n FLUIGC.toast({ title: 'Aviso', message: 'Usuário não possui permissão para publicar anexos', type: 'warning' })\r\n return\r\n }\r\n AttachmentsTable.attachInstance?.add(GENERIC_ATTACHMENT_MARKER, AttachmentsTable.options.accept ?? null)\r\n return\r\n }\r\n\r\n const namedBtn = target.closest('[data-attach-named]') as HTMLElement | null\r\n if (namedBtn) {\r\n event.preventDefault()\r\n if (!hasPermission('P')) {\r\n FLUIGC.toast({ title: 'Aviso', message: 'Usuário não possui permissão para publicar anexos', type: 'warning' })\r\n return\r\n }\r\n AttachmentsTable.openNameInputModal(AttachmentsTable.options.accept ?? null)\r\n }\r\n })\r\n\r\n // Drag-and-drop\r\n const container = context.parentDocument.getElementById(CONTAINER_ID)!\r\n container.addEventListener('dragover', (e: DragEvent) => {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n container.classList.add('drag-over')\r\n })\r\n container.addEventListener('dragleave', () => container.classList.remove('drag-over'))\r\n container.addEventListener('drop', (e: DragEvent) => {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n container.classList.remove('drag-over')\r\n const files = e.dataTransfer?.files\r\n if (!files || files.length === 0) return\r\n if (!hasPermission('P')) {\r\n FLUIGC.toast({ title: 'Aviso', message: 'Usuário não possui permissão para publicar anexos', type: 'warning' })\r\n return\r\n }\r\n new DragDropNameModal(files, (entries) => {\r\n entries.forEach(({ file, name }) => {\r\n Attach.uploadBlob(file, name, file.type)\r\n })\r\n })\r\n })\r\n }\r\n\r\n window.addEventListener('jsegd:upload:reset', () => AttachmentsTable.render())\r\n\r\n window.addEventListener('jsegd:upload:success', async (e: Event) => {\r\n const detail = (e as CustomEvent<{\r\n description?: string\r\n source?: AttachmentSource\r\n accept?: string | null\r\n }>).detail\r\n\r\n AttachmentsTable.render()\r\n\r\n if (!detail?.source || AttachmentsTable.options?.mode !== 'self-managed') return\r\n if (!AttachmentsTable.attachInstance) return\r\n\r\n const allAttachments = Attach.getAllAttachments().filter((a) => !isMetadataAttachment(a))\r\n const newAttachment = allAttachments.find(\r\n (a) => a.description?.replace(/_V\\d+$/, '') === detail.description?.replace(/_V\\d+$/, '')\r\n )\r\n\r\n if (!newAttachment || !newAttachment.documentId) return\r\n\r\n const metadata = (await AttachmentMetadataFile.load()) ?? AttachmentMetadataFile.empty()\r\n const record: AttachmentRecord = {\r\n documentId: newAttachment.documentId,\r\n source: detail.source,\r\n buttonDescription: detail.source === 'button' ? detail.description : undefined,\r\n accept: detail.accept ?? null,\r\n workflowSequence: getWorkflowContext().getWorkflowSequence(),\r\n uploadedAt: new Date().toISOString(),\r\n }\r\n\r\n AttachmentMetadataFile.save(\r\n {\r\n ...metadata,\r\n attachments: {\r\n ...metadata.attachments,\r\n [String(newAttachment.documentId)]: record,\r\n },\r\n }\r\n )\r\n })\r\n }\r\n\r\n private static render(): void {\r\n const context = getWorkflowContext()\r\n const container = context.parentDocument.getElementById(CONTAINER_ID)\r\n if (!container) return\r\n\r\n const isSelfManaged = AttachmentsTable.options?.mode === 'self-managed'\r\n const template = isSelfManaged ? TEMPLATE_SELF_MANAGED : TEMPLATE_BUTTONS_ONLY\r\n\r\n const attachments = Attach.getAllAttachments()\r\n .filter((a) => !isMetadataAttachment(a))\r\n .map((attachment) => {\r\n const sanitized = sanitizeAttachmentForDisplay(attachment)\r\n if (!isSelfManaged) {\r\n return { ...sanitized, enableDownload: !isNewProcess() }\r\n }\r\n const btn = AttachmentsTable.resolveButtonRegistration(attachment)\r\n return {\r\n ...sanitized,\r\n enableView: !isNewProcess() && (hasPermission('R') || isOwnAttachment(attachment)),\r\n enableEdit: !attachment.newAttach && canEditAttachment(attachment),\r\n enableReversion: !!btn && hasPermission('P'),\r\n enableDownload: !isNewProcess(),\r\n enableDelete: hasPermission('E') || hasPermission('D'),\r\n buttonDescription: btn?.description ?? '',\r\n buttonAccept: btn?.accept ?? '',\r\n }\r\n })\r\n\r\n container.innerHTML = context.renderTemplate(template, {\r\n attachments,\r\n unpublishedVersion: UNPUBLISHED_VERSION_DISPLAY,\r\n })\r\n }\r\n\r\n private static async hydrateFromMetadata(): Promise<void> {\r\n const metadata = await AttachmentMetadataFile.load()\r\n if (!metadata) return\r\n\r\n for (const [description, record] of Object.entries(metadata.buttons)) {\r\n if (!AttachmentsTable.buttonRegistry.has(description)) {\r\n AttachmentsTable.buttonRegistry.set(description, {\r\n description,\r\n accept: record.accept,\r\n })\r\n }\r\n }\r\n }\r\n\r\n private static async persistMetadata(): Promise<void> {\r\n if (!AttachmentsTable.attachInstance) return\r\n\r\n const current = (await AttachmentMetadataFile.load()) ?? AttachmentMetadataFile.empty()\r\n const buttons: Record<string, { accept: string | null }> = {}\r\n for (const [key, reg] of AttachmentsTable.buttonRegistry.entries()) {\r\n buttons[key] = { accept: reg.accept }\r\n }\r\n\r\n AttachmentMetadataFile.save({ ...current, buttons })\r\n }\r\n\r\n private static openNameInputModal(accept: string | null): void {\r\n FLUIGC.modal(\r\n {\r\n title: 'Nome do anexo',\r\n content: `<div style=\"padding:8px 0\"><label for=\"attach-name-input\" style=\"display:block;margin-bottom:6px\">Informe o nome do arquivo:</label><input type=\"text\" id=\"attach-name-input\" class=\"form-control\" placeholder=\"Ex: Contrato assinado\" maxlength=\"200\"></div>`,\r\n id: 'attach-name-modal',\r\n size: 'small',\r\n showHeader: true,\r\n showFooter: true,\r\n headerActions: [],\r\n headerContent: '',\r\n formModal: false,\r\n actions: [\r\n { label: 'Cancelar', classType: 'btn-default', autoClose: true },\r\n { label: 'Anexar', classType: 'btn-primary', bind: 'data-attach-name-confirm' },\r\n ],\r\n },\r\n () => {}\r\n )\r\n\r\n document.querySelector('[data-attach-name-confirm]')?.addEventListener('click', () => {\r\n const input = document.getElementById('attach-name-input') as HTMLInputElement | null\r\n const rawName = input?.value?.trim() ?? ''\r\n if (!rawName) return\r\n const safeName = sanitizeAttachmentName(rawName)\r\n AttachmentsTable.attachInstance?.add(safeName, accept)\r\n })\r\n }\r\n\r\n private static getRows(): HTMLTableRowElement[] {\r\n return Array.from(\r\n getWorkflowContext().parentDocument.querySelectorAll(`#${CONTAINER_ID} table tbody tr`)\r\n ) as HTMLTableRowElement[]\r\n }\r\n\r\n private static setOrder(rows: HTMLTableRowElement[]): void {\r\n const tbody = getWorkflowContext().parentDocument.querySelector(\r\n `#${CONTAINER_ID} table tbody`\r\n ) as HTMLTableSectionElement | null\r\n if (!tbody) return\r\n rows.forEach((row) => tbody.appendChild(row))\r\n }\r\n\r\n private static sortBy(column: SortColumn, ascending: boolean): void {\r\n const rows = AttachmentsTable.getRows()\r\n rows.sort((a, b) => {\r\n const valueA = AttachmentsTable.getCellValue(a, column)\r\n const valueB = AttachmentsTable.getCellValue(b, column)\r\n if (valueA && valueB) {\r\n return ascending ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA)\r\n }\r\n return 0\r\n })\r\n AttachmentsTable.setOrder(rows)\r\n }\r\n\r\n private static getCellValue(row: HTMLTableRowElement, column: SortColumn): string | undefined {\r\n switch (column) {\r\n case 'title':\r\n return row.querySelector('[data-attachment-open]')?.closest('td')?.textContent?.trim()\r\n case 'user':\r\n return row.querySelector('td:nth-child(4)')?.textContent?.trim()\r\n case 'date':\r\n return row.querySelector('td:nth-child(5)')?.textContent?.trim()\r\n case 'activity':\r\n return row.querySelector('td:nth-child(6)')?.textContent?.trim()\r\n }\r\n }\r\n}\r\n\r\ntype SortColumn = 'title' | 'user' | 'date' | 'activity'\r\n\r\n","import html from './assets/index.html'\r\nimport styles from './assets/styles.css'\r\nimport { Attach } from './attach'\r\nimport { GENERIC_ATTACHMENT_MARKER } from './attachment.constants'\r\nimport './attachment.events'\r\nimport { getGenericAttachmentDescriptions } from './attachment.utils'\r\nimport { AttachmentsTable } from './attachmentsTable'\r\n\r\n/**\r\n * Implementa um botão para gerenciar anexos\r\n * @hideconstructor\r\n * @example\r\n * ```html\r\n * <attachment-button description=\"CONTRATO\"></attachment-button>\r\n * ```\r\n */\r\nexport class AttachButton extends HTMLElement {\r\n /**\r\n * Descrição do tipo de anexo gerenciado pelo botão.\r\n * Quando vazio, um modal é exibido para o usuário informar a descrição no momento do upload.\r\n * @defaultValue `''`\r\n */\r\n description: string\r\n\r\n /**\r\n * Filtro de tipos de arquivo aceitos pelo seletor nativo (ex: `\".pdf,.docx\"`).\r\n * `null` aceita qualquer tipo de arquivo.\r\n */\r\n accept: string | null\r\n\r\n noaddbutton: string | null = null\r\n noviewbutton: string | null = null\r\n noeditbutton: string | null = null\r\n nodeletebutton: string | null = null\r\n\r\n private handleSuccess: EventListener = () => {\r\n const button = this.shadowRoot?.querySelector('.dropdown-button') as HTMLButtonElement\r\n if (button) {\r\n button.style.color = 'rgb(255, 255, 255)'\r\n button.style.backgroundColor = 'rgb(26, 184, 63)'\r\n }\r\n }\r\n\r\n private handleError: EventListener = () => {\r\n const button = this.shadowRoot?.querySelector('.dropdown-button') as HTMLButtonElement\r\n if (button) {\r\n button.style.color = 'rgb(255, 255, 255)'\r\n button.style.backgroundColor = 'rgb(204, 61, 61)'\r\n }\r\n }\r\n\r\n private handleDefault: EventListener = () => {\r\n const button = this.shadowRoot?.querySelector('.dropdown-button') as HTMLButtonElement\r\n if (button) {\r\n button.style.color = 'rgb(85, 85, 85)'\r\n button.style.backgroundColor = 'rgb(255, 255, 255)'\r\n }\r\n }\r\n\r\n constructor() {\r\n super()\r\n const shadow = this.attachShadow({ mode: 'open' })\r\n const style = document.createElement('style')\r\n style.innerHTML = styles\r\n const template = document.createElement('template')\r\n template.innerHTML = html\r\n shadow.appendChild(style)\r\n\r\n shadow.appendChild(template.content.cloneNode(true))\r\n this.description = ''\r\n this.accept = null\r\n }\r\n\r\n static get observedAttributes() {\r\n return ['description', 'accept', 'noaddbutton', 'noviewbutton', 'noeditbutton', 'nodeletebutton']\r\n }\r\n\r\n attributeChangedCallback(name: string, _oldValue: string, newValue: string) {\r\n if (!this.isConnected) return\r\n switch (name) {\r\n case 'description':\r\n this.description = newValue || ''\r\n break\r\n case 'accept':\r\n this.accept = newValue\r\n break\r\n case 'noaddbutton':\r\n this.noaddbutton = newValue\r\n break\r\n case 'noviewbutton':\r\n this.noviewbutton = newValue\r\n break\r\n case 'noeditbutton':\r\n this.noeditbutton = newValue ?? 'true'\r\n break\r\n case 'nodeletebutton':\r\n this.nodeletebutton = newValue\r\n break\r\n }\r\n this.displayButtons()\r\n }\r\n\r\n disconnectedCallback() {\r\n parent.removeEventListener('jsegd:upload:success', this.handleSuccess)\r\n parent.removeEventListener('jsegd:upload:error', this.handleError)\r\n parent.removeEventListener('jsegd:upload:reset', this.handleDefault)\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n connectedCallback() {\r\n /**\r\n * Botões\r\n */\r\n this.noaddbutton = this.getAttribute('noAddButton')\r\n this.noviewbutton = this.getAttribute('noViewButton')\r\n this.noeditbutton = this.getAttribute('noEditButton') ?? 'true'\r\n this.nodeletebutton = this.getAttribute('noDeleteButton')\r\n this.displayButtons()\r\n /**\r\n *\r\n */\r\n this.accept = this.getAttribute('accept')\r\n this.description = this.getAttribute('description') || ''\r\n const attachment = Attach.getInstance()\r\n this.addButton(attachment)\r\n this.viewButton(attachment)\r\n this.editButton(attachment)\r\n this.removeButton(attachment)\r\n parent.addEventListener('jsegd:upload:success', this.handleSuccess)\r\n parent.addEventListener('jsegd:upload:error', this.handleError)\r\n parent.addEventListener('jsegd:upload:reset', this.handleDefault)\r\n AttachmentsTable.registerButton({ description: this.description, accept: this.accept ?? null })\r\n }\r\n\r\n private displayButtons() {\r\n if (this.noaddbutton !== 'true') {\r\n this.shadowRoot?.querySelector('#attach')?.parentElement?.classList.remove('fs-display-none')\r\n }\r\n if (this.noviewbutton !== 'true') {\r\n this.shadowRoot?.querySelector('#view')?.parentElement?.classList.remove('fs-display-none')\r\n }\r\n if (this.noeditbutton !== 'true') {\r\n this.shadowRoot?.querySelector('#edit')?.parentElement?.classList.remove('fs-display-none')\r\n }\r\n if (this.nodeletebutton !== 'true') {\r\n this.shadowRoot?.querySelector('#remove')?.parentElement?.classList.remove('fs-display-none')\r\n }\r\n }\r\n\r\n private addButton(attachment: Attach) {\r\n this.shadowRoot?.querySelector('#attach')?.addEventListener('click', (e) => {\r\n e.preventDefault()\r\n if (!this.description) {\r\n this.showModal()\r\n } else {\r\n attachment.add(this.description, this.accept)\r\n }\r\n })\r\n }\r\n private viewButton(attachment: Attach) {\r\n this.shadowRoot?.querySelector('#view')?.addEventListener('click', (e) => {\r\n e.preventDefault()\r\n attachment.view(!this.description ? GENERIC_ATTACHMENT_MARKER : this.description)\r\n })\r\n }\r\n private editButton(attachment: Attach) {\r\n this.shadowRoot?.querySelector('#edit')?.addEventListener('click', (e) => {\r\n e.preventDefault()\r\n attachment.edit(!this.description ? GENERIC_ATTACHMENT_MARKER : this.description)\r\n })\r\n }\r\n\r\n private removeButton(attachment: Attach) {\r\n this.shadowRoot?.querySelector('#remove')?.addEventListener('click', (e) => {\r\n e.preventDefault()\r\n attachment.remove(!this.description ? GENERIC_ATTACHMENT_MARKER : this.description)\r\n })\r\n }\r\n\r\n private showModal() {\r\n const template = `\r\n <div class=\"row\" style=\"height: 200px;\">\r\n <div class=\"col-xs-12 col-sm-12 col-md-12 col-lg-12\">\r\n <div class=\"form-group\">\r\n <label for=\"attach_description\">Descrição do anexo</label>\r\n <input type=\"text\" name=\"attach_description\" id=\"attach_description\"\r\n class=\"form-control\" />\r\n </div>\r\n </div>\r\n </div>\r\n `\r\n\r\n const attachModal = parent.FLUIGC.modal(\r\n {\r\n title: 'Informe a descrição do anexo',\r\n content: template,\r\n id: 'attachModal',\r\n showHeader: true,\r\n showFooter: true,\r\n actions: [\r\n {\r\n label: 'Salvar',\r\n bind: 'data-save-modal',\r\n },\r\n {\r\n label: 'Cancelar',\r\n bind: 'data-cancel-modal',\r\n },\r\n ],\r\n headerActions: [],\r\n headerContent: '',\r\n size: 'large',\r\n formModal: false,\r\n },\r\n (err, _data) => {\r\n if (!err) {\r\n parent.FLUIGC.autocomplete(\r\n '#attach_description',\r\n {\r\n source: (q: string, cb: (results: { description: string }[]) => void) => {\r\n const matches = getGenericAttachmentDescriptions()\r\n .filter((d) => d.toLowerCase().includes(q.toLowerCase()))\r\n .map((description) => ({ description }))\r\n cb(matches)\r\n },\r\n highlight: true,\r\n displayKey: 'description',\r\n tagClass: 'tag-gray',\r\n type: 'autocomplete',\r\n },\r\n () => {}\r\n )\r\n\r\n parent.document.querySelector('[data-save-modal]')?.addEventListener('click', () => {\r\n const { value } = parent.document.querySelector('#attach_description') as HTMLInputElement\r\n if (!value) {\r\n FLUIGC.toast({\r\n title: 'Erro',\r\n message: 'Informe a descrição do anexo',\r\n type: 'danger',\r\n })\r\n return\r\n }\r\n const description = `${value.toUpperCase()}_Z_`\r\n attachModal.remove()\r\n const attachment = Attach.getInstance()\r\n attachment.add(description, this.accept)\r\n })\r\n\r\n parent.document.querySelector('[data-cancel-modal]')?.addEventListener('click', () => {\r\n attachModal.remove()\r\n })\r\n }\r\n }\r\n )\r\n }\r\n}\r\n\r\nif (!customElements.get('attachment-button')) {\r\n customElements.define('attachment-button', AttachButton)\r\n}\r\n",":host {\n display: inline-block;\n position: relative;\n font-family: Arial, sans-serif;\n}\n\n.dropdown {\n position: relative;\n display: inline-block;\n}\n\n.dropdown-button {\n background-color: #fff;\n color: #555;\n padding: 6px 10px;\n font-size: 14px;\n border: 1px solid #ccc;\n cursor: pointer;\n border-radius: 0 5px 5px 0;\n display: flex;\n align-items: center;\n gap: 5px;\n height: 32px;\n}\n\n.dropdown-button:hover {\n color: #555;\n border-color: #adadad;\n background-color: #e6e6e6;\n}\n\n.dropdown-menu {\n display: none;\n position: absolute;\n top: 100%;\n right: 0;\n background-color: #fff;\n box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);\n min-width: 150px;\n list-style: none;\n padding: 0;\n margin: 0;\n border-radius: 0 0 2px 2px;\n}\n\n.dropdown-menu a {\n display: flex;\n gap: 10px;\n padding: 5px;\n box-sizing: border-box;\n width: 100%;\n text-decoration: none;\n color: #333;\n font-size: 14px;\n justify-content: end;\n align-items: center;\n line-height: 1.5rem;\n}\n\n.dropdown-menu a:hover {\n background-color: #f1f1f1;\n color: #1d1b1b;\n}\n\n.dropdown:hover .dropdown-menu {\n display: block;\n z-index: 9999;\n}\n\n.fs-display-none {\n display: none !important;\n}\r\n","export type FieldError = {\r\n field?: HTMLElement | null\r\n errorMessage: string\r\n}\r\n\r\nexport class BeforeSendValidate {\r\n private static clearAllErrors(): void {\r\n const allGroups = document.querySelectorAll('[data-group]')\r\n allGroups.forEach((group) => {\r\n group.classList.remove('has-error')\r\n const helperElement = group.querySelector('[data-helper]')\r\n if (helperElement) {\r\n helperElement.classList.add('fs-display-none')\r\n }\r\n })\r\n }\r\n\r\n static throwValidationError(fields: FieldError[]): never {\r\n if (!fields || fields.length === 0) {\r\n throw new Error('<div class=\"alert alert-danger\" role=\"alert\">Erro de validação</div>')\r\n }\r\n this.clearAllErrors()\r\n\r\n fields.forEach(({ field, errorMessage }) => {\r\n if (field) {\r\n const group = field.closest('[data-group]')\r\n if (group) {\r\n group.classList.add('has-error')\r\n const helperElement = group.querySelector('[data-helper]')\r\n if (helperElement) {\r\n helperElement.classList.remove('fs-display-none')\r\n helperElement.textContent = errorMessage\r\n }\r\n\r\n const clearErrorHandler = () => {\r\n group.classList.remove('has-error')\r\n if (helperElement) {\r\n helperElement.classList.add('fs-display-none')\r\n helperElement.textContent = ''\r\n }\r\n }\r\n\r\n group.addEventListener('click', clearErrorHandler, { once: true })\r\n group.addEventListener('focusin', clearErrorHandler, { once: true })\r\n }\r\n }\r\n })\r\n const validMessages = fields\r\n .filter(({ errorMessage }) => errorMessage && errorMessage.trim())\r\n .map(({ errorMessage }) => errorMessage.replace(/</g, '<').replace(/>/g, '>'))\r\n\r\n if (validMessages.length === 0) {\r\n throw new Error('<div class=\"alert alert-danger\" role=\"alert\">Erro de validação</div>')\r\n }\r\n const combinedMessages = validMessages.join('<br>')\r\n throw new Error(`<div class=\"alert alert-danger\" role=\"alert\">${combinedMessages}</div>`)\r\n }\r\n}\r\n","import type { ProcessCompletionMessage } from './interfaces/IWorkflowViewHooks'\r\n\r\n\r\nexport type HooksMap = {\r\n beforeValidate: Array<() => void | Promise<void>>\r\n afterValidate: Array<() => void | Promise<void>>\r\n onMoveSuccess: Array<() => void | Promise<void>>\r\n onMoveError: Array<() => void | Promise<void>>\r\n onCompletionLinkAdd: Array<(message: ProcessCompletionMessage) => void | Promise<void>>\r\n}\r\n\r\n/**\r\n * Registro mutável de hooks compartilhado entre `WorkflowViewPatcher` e `sendRequestEvent`.\r\n *\r\n * @internal\r\n */\r\nexport const hooksMap: HooksMap = {\r\n beforeValidate: [],\r\n afterValidate: [],\r\n onMoveSuccess: [],\r\n onMoveError: [],\r\n onCompletionLinkAdd: [],\r\n}\r\n","import { hooksMap } from '../hooks-registry'\r\nimport { getProcessInfo } from '../../process-context'\r\n\r\n/**\r\n * Override de `sendRequestEvent()` do widget de processo.\r\n * Executa os hooks `beforeValidate` e `afterValidate` em sequência antes de enviar a solicitação.\r\n * Reabilita os botões de ação em caso de erro ou quando a validação falha.\r\n */\r\nexport async function sendRequestEvent(this: ECM_WKFView) {\r\n const enableButtons = () => {\r\n this.enableSendButton()\r\n this.enableActionButtons()\r\n }\r\n\r\n // Executa todos os beforeValidate em sequência\r\n // Primeira exceção cancela o envio e reabilita os botões\r\n for (const fn of hooksMap.beforeValidate) {\r\n try {\r\n const result = fn()\r\n if (result instanceof Promise) {\r\n await result\r\n }\r\n } catch (e) {\r\n enableButtons()\r\n return\r\n }\r\n }\r\n\r\n const nextActivityElement = document.getElementById('nextActivity') as HTMLSelectElement | HTMLInputElement | null\r\n const nextActivity = nextActivityElement?.value || this.selectActivity()\r\n\r\n const isValid = await this.callFormFunction('beforeSendValidate', [getProcessInfo().getWorkflowSequence(), nextActivity])\r\n if (!isValid) {\r\n enableButtons()\r\n return\r\n }\r\n\r\n // Executa todos os afterValidate em sequência\r\n // Primeira exceção cancela o envio e reabilita os botões\r\n for (const fn of hooksMap.afterValidate) {\r\n try {\r\n const result = fn()\r\n if (result instanceof Promise) {\r\n await result\r\n }\r\n } catch (e) {\r\n enableButtons()\r\n return\r\n }\r\n }\r\n this.disableActionButtons()\r\n this.sendRequest(false, false)\r\n}\r\n","import { sendRequestEvent } from './overrides/send-request'\r\nimport type { ProcessCompletionMessage } from './interfaces/IWorkflowViewHooks'\r\nimport { hooksMap, type HooksMap } from './hooks-registry'\r\n\r\n/**\r\n * Mapa de substituições que serão aplicadas ao widget nativo de processo.\r\n */\r\nconst overrides = {\r\n sendRequestEvent: sendRequestEvent,\r\n}\r\n\r\n/**\r\n * Tipo do mapa de substituições.\r\n */\r\ntype OverrideMap = typeof overrides\r\n\r\n/**\r\n * Classe utilitária para substituir métodos no widget nativo de processo.\r\n *\r\n * Preserva os métodos originais para permitir reversão via `restore()`.\r\n *\r\n * @example\r\n * ```typescript\r\n * // Aguardar inicialização do widget de processo\r\n * await WorkflowViewPatcher.init()\r\n *\r\n * // Aplicar todos os patches registrados\r\n * WorkflowViewPatcher.patchAll()\r\n *\r\n * // Registrar hooks\r\n * WorkflowViewPatcher.addBeforeValidate(async () => {\r\n * console.log('Antes da validação')\r\n * })\r\n *\r\n * WorkflowViewPatcher.addAfterValidate(async () => {\r\n * console.log('Após a validação')\r\n * })\r\n * ```\r\n */\r\nexport class WorkflowViewPatcher {\r\n private static isInitialized = false\r\n private static isInitializing = false\r\n private static originalMethods: Partial<Record<keyof OverrideMap, Function>> = {}\r\n\r\n /**\r\n * Inicializa o patcher aguardando o carregamento do widget de processo no frame pai.\r\n *\r\n * Chamadas repetidas retornam imediatamente se já inicializado.\r\n *\r\n * @param timeout - Tempo máximo de espera em ms (padrão: 5000ms)\r\n * @returns Promise<void>\r\n *\r\n * @throws {Error} Se outra chamada a `init()` já estiver em progresso\r\n * @throws {Error} Se o widget `ECM_WKFView` não estiver disponível após o timeout\r\n *\r\n * @example\r\n * ```typescript\r\n * await WorkflowViewPatcher.init()\r\n * WorkflowViewPatcher.patchAll()\r\n * ```\r\n */\r\n static async init(timeout = 5000): Promise<void> {\r\n if (this.isInitialized) return\r\n if (this.isInitializing) {\r\n throw new Error('[WorkflowViewPatcher] init() já está em progresso')\r\n }\r\n\r\n this.isInitializing = true\r\n const startTime = Date.now()\r\n\r\n while (!parent.ECM_WKFView) {\r\n if (Date.now() - startTime > timeout) {\r\n this.isInitializing = false\r\n throw new Error('[WorkflowViewPatcher] Timeout: ECM_WKFView não disponível no contexto pai')\r\n }\r\n await new Promise((resolve) => setTimeout(resolve, 100))\r\n }\r\n\r\n this.isInitializing = false\r\n this.isInitialized = true\r\n }\r\n\r\n /**\r\n * Aplica o patch de um override específico no widget de processo.\r\n *\r\n * Salva o método original antes de sobrescrever, permitindo reversão via `restore()`.\r\n *\r\n * @param attr - Nome do método a ser substituído\r\n * @throws {Error} Se `init()` não tiver sido chamado antes\r\n * @throws {Error} Se o override não estiver registrado no mapa de substituições\r\n */\r\n static patch(attr: keyof OverrideMap) {\r\n if (!this.isInitialized) {\r\n throw new Error('[WorkflowViewPatcher] Chame init() antes de aplicar patches')\r\n }\r\n if (!parent.ECM_WKFView) return\r\n\r\n const fn = overrides[attr]\r\n if (!fn) {\r\n throw new Error(`[WorkflowViewPatcher] Override '${attr}' não registrado no mapa de substituições`)\r\n }\r\n if (!this.originalMethods[attr]) {\r\n this.originalMethods[attr] = parent.ECM_WKFView[attr]\r\n }\r\n parent.ECM_WKFView[attr] = fn.bind(parent.ECM_WKFView)\r\n }\r\n\r\n /**\r\n * Aplica patches para múltiplos métodos do widget de processo.\r\n *\r\n * @param attrs - Array com nomes dos métodos a serem substituídos\r\n * @throws {Error} Se `init()` não tiver sido chamado antes\r\n */\r\n static patchMany(attrs: (keyof OverrideMap)[]) {\r\n if (!this.isInitialized) {\r\n throw new Error('[WorkflowViewPatcher] Chame init() antes de aplicar patches')\r\n }\r\n attrs.forEach((attr) => this.patch(attr))\r\n }\r\n\r\n /**\r\n * Aplica todos os patches registrados no mapa de substituições.\r\n * @throws {Error} Se `init()` não tiver sido chamado antes\r\n */\r\n static patchAll() {\r\n if (!this.isInitialized) {\r\n throw new Error('[WorkflowViewPatcher] Chame init() antes de aplicar patches')\r\n }\r\n if (parent.ECM_WKFView) {\r\n Object.keys(overrides).forEach((attr) => {\r\n this.patch(attr as keyof OverrideMap)\r\n })\r\n }\r\n }\r\n\r\n /**\r\n * Restaura todos os métodos do widget para as implementações originais.\r\n *\r\n * Deve ser chamado ao desmontar o componente em SPAs, para evitar que os patches\r\n * persistam além do ciclo de vida do formulário. Também zera os flags de estado\r\n * interno, permitindo reinicialização via `init()`.\r\n *\r\n * @example\r\n * ```typescript\r\n * // Ao desmontar o formulário\r\n * WorkflowViewPatcher.restore()\r\n * ```\r\n */\r\n static restore() {\r\n if (!parent.ECM_WKFView) return\r\n\r\n Object.entries(this.originalMethods).forEach(([attr, originalFn]) => {\r\n const k = attr as keyof OverrideMap\r\n if (originalFn !== undefined) {\r\n ;(parent.ECM_WKFView as any)[k] = originalFn\r\n } else {\r\n delete (parent.ECM_WKFView as any)[k]\r\n }\r\n })\r\n\r\n this.originalMethods = {}\r\n this.isInitialized = false\r\n this.isInitializing = false\r\n hooksMap.beforeValidate.length = 0\r\n hooksMap.afterValidate.length = 0\r\n hooksMap.onMoveSuccess.length = 0\r\n hooksMap.onMoveError.length = 0\r\n hooksMap.onCompletionLinkAdd.length = 0\r\n }\r\n\r\n /**\r\n * Acessa a lista interna de hooks para um tipo específico.\r\n * Usado por `sendRequestEvent` para executar os hooks em sequência.\r\n *\r\n * @internal\r\n */\r\n static getHooks<K extends keyof HooksMap>(key: K): HooksMap[K] {\r\n return hooksMap[key]\r\n }\r\n\r\n /**\r\n * Registra uma função executada ANTES da validação principal do widget.\r\n *\r\n * Múltiplas chamadas acumulam handlers — nenhuma sobrescreve a anterior.\r\n * Se o handler lançar exceção (sync ou async), o envio é cancelado e os botões são reabilitados.\r\n *\r\n * @param fn - Função a ser executada (pode ser async).\r\n *\r\n * @example\r\n * ```typescript\r\n * WorkflowViewPatcher.addBeforeValidate(async () => {\r\n * const value = getValue('campo_obrigatorio')\r\n * if (!value) {\r\n * throw new Error('Campo obrigatório não preenchido')\r\n * }\r\n * })\r\n * ```\r\n */\r\n static addBeforeValidate(fn: () => void | Promise<void>) {\r\n hooksMap.beforeValidate.push(fn)\r\n }\r\n\r\n /**\r\n * Registra uma função executada APÓS `beforeSendValidate` retornar `true`,\r\n * mas ANTES do envio efetivo da solicitação.\r\n *\r\n * Múltiplas chamadas acumulam handlers — nenhuma sobrescreve a anterior.\r\n * Se o handler lançar exceção (sync ou async), o envio é cancelado e os botões são reabilitados.\r\n *\r\n * @param fn - Função a ser executada (pode ser async).\r\n *\r\n * @example\r\n * ```typescript\r\n * WorkflowViewPatcher.addAfterValidate(async () => {\r\n * console.log('Validação concluída, preparando envio...')\r\n * await salvarDadosLocais()\r\n * })\r\n * ```\r\n */\r\n static addAfterValidate(fn: () => void | Promise<void>) {\r\n hooksMap.afterValidate.push(fn)\r\n }\r\n\r\n /**\r\n * Registra uma função executada quando a movimentação do processo é concluída com sucesso.\r\n *\r\n * Múltiplas chamadas acumulam handlers — nenhuma sobrescreve a anterior.\r\n *\r\n * @param fn - Função callback executada em caso de sucesso (pode ser async).\r\n *\r\n * @example\r\n * ```typescript\r\n * WorkflowViewPatcher.addOnMoveSuccess(() => {\r\n * console.log('Processo movimentado com sucesso')\r\n * })\r\n * ```\r\n */\r\n static addOnMoveSuccess(fn: () => void | Promise<void>) {\r\n hooksMap.onMoveSuccess.push(fn)\r\n }\r\n\r\n /**\r\n * Registra uma função executada quando ocorre erro na movimentação do processo.\r\n *\r\n * Múltiplas chamadas acumulam handlers — nenhuma sobrescreve a anterior.\r\n *\r\n * @param fn - Função callback executada em caso de erro (pode ser async).\r\n *\r\n * @example\r\n * ```typescript\r\n * WorkflowViewPatcher.addOnMoveError(() => {\r\n * console.error('Erro ao movimentar processo')\r\n * })\r\n * ```\r\n */\r\n static addOnMoveError(fn: () => void | Promise<void>) {\r\n hooksMap.onMoveError.push(fn)\r\n }\r\n\r\n /**\r\n * Registra uma função para manipular os links da página de conclusão da movimentação.\r\n *\r\n * Múltiplas chamadas acumulam handlers — nenhuma sobrescreve a anterior.\r\n *\r\n * @param fn - Função que recebe o objeto de conclusão e pode adicionar ou modificar links (pode ser async).\r\n *\r\n * @example\r\n * ```typescript\r\n * WorkflowViewPatcher.addOnCompletionLinkAdd((message: ProcessCompletionMessage) => {\r\n * message.links.push({ description: 'Voltar ao início', href: '/inicio' })\r\n * })\r\n * ```\r\n */\r\n static addOnCompletionLinkAdd(fn: (message: ProcessCompletionMessage) => void | Promise<void>) {\r\n hooksMap.onCompletionLinkAdd.push(fn)\r\n }\r\n}\r\n","/**\r\n * Converte snake_case para camelCase.\r\n * @example snakeToCamel('primeiro_pagamento') → 'primeiroPagamento'\r\n * @example snakeToCamel('contrato_indice') → 'contratoIndice'\r\n */\r\nexport function snakeToCamel(str: string): string {\r\n return str.replace(/_([a-z])/g, (_, letter: string) => letter.toUpperCase())\r\n}\r\n\r\n/**\r\n * Converte camelCase para snake_case.\r\n * @example camelToSnake('primeiroPagamento') → 'primeiro_pagamento'\r\n * @example camelToSnake('contratoIndice') → 'contrato_indice'\r\n */\r\nexport function camelToSnake(str: string): string {\r\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)\r\n}\r\n","import type { IFormRepository } from './IFormRepository'\r\nimport { snakeToCamel, camelToSnake } from './nameUtils'\r\n\r\ndeclare function wdkAddChild(tableName: string, skipLoadZoom?: boolean): number\r\n\r\n/**\r\n * Adapter de produção que isola o acesso ao DOM do formulário BPM e às\r\n * funções globais `wdkAddChild`/`fnWdkRemoveChild` (definidas em `wdkdetail.js`).\r\n *\r\n * Segue o mesmo padrão de fronteira estabelecido por `process-context/` —\r\n * este é o único arquivo autorizado a referenciar as globais do formulário BPM.\r\n */\r\nexport class BpmFormRepository implements IFormRepository {\r\n load<T>(section: string): Partial<T> {\r\n const prefix = `${section}_`\r\n const result: Record<string, unknown> = {}\r\n const fields = document.querySelectorAll<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(\r\n `input[name^=\"${prefix}\"], select[name^=\"${prefix}\"], textarea[name^=\"${prefix}\"]`\r\n )\r\n fields.forEach((el) => {\r\n const domName = el.name\r\n if (!domName || domName.includes('___')) return\r\n const camelKey = snakeToCamel(domName.slice(prefix.length))\r\n if (el instanceof HTMLInputElement && el.type === 'checkbox') {\r\n result[camelKey] = el.checked\r\n } else {\r\n result[camelKey] = el.value\r\n }\r\n })\r\n return result as Partial<T>\r\n }\r\n\r\n loadTable<T>(tableName: string): T[] {\r\n const rows = document.querySelectorAll<HTMLTableRowElement>(\r\n `table[tablename=\"${tableName}\"] tbody tr:not([style*=\"display: none\"]):not([style*=\"display:none\"])`\r\n )\r\n const result: T[] = []\r\n rows.forEach((row) => {\r\n const rowData: Record<string, unknown> = {}\r\n const fields = row.querySelectorAll<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(\r\n 'input, select, textarea'\r\n )\r\n fields.forEach((el) => {\r\n if (!el.name) return\r\n const baseName = el.name.includes('___') ? el.name.substring(0, el.name.lastIndexOf('___')) : el.name\r\n if (el instanceof HTMLInputElement && el.type === 'checkbox') {\r\n rowData[baseName] = el.checked\r\n } else {\r\n rowData[baseName] = el.value\r\n }\r\n })\r\n result.push(rowData as T)\r\n })\r\n return result\r\n }\r\n\r\n save<T>(section: string, data: Partial<T>): void {\r\n const prefix = `${section}_`\r\n Object.entries(data as Record<string, unknown>).forEach(([camelKey, value]) => {\r\n const domName = `${prefix}${camelToSnake(camelKey)}`\r\n const el = document.querySelector<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(\r\n `[name=\"${domName}\"]`\r\n )\r\n if (!el) return\r\n if (el instanceof HTMLInputElement && el.type === 'checkbox') {\r\n el.checked = Boolean(value)\r\n } else {\r\n el.value = String(value ?? '')\r\n }\r\n })\r\n }\r\n\r\n saveTable<T>(tableName: string, rows: T[]): void {\r\n // Remove linhas existentes — equivalente a clearTables() de wdkdetail.js\r\n document.querySelectorAll<HTMLTableRowElement>(\r\n `table[tablename=\"${tableName}\"] tbody tr`\r\n ).forEach((row) => {\r\n if ((row as HTMLElement).style.display !== 'none') {\r\n row.remove()\r\n }\r\n })\r\n\r\n rows.forEach((rowData) => {\r\n const rowId = wdkAddChild(tableName, false)\r\n Object.entries(rowData as Record<string, unknown>).forEach(([key, value]) => {\r\n const el = document.querySelector<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(\r\n `[name=\"${key}___${rowId}\"]`\r\n )\r\n if (!el) return\r\n if (el instanceof HTMLInputElement && el.type === 'checkbox') {\r\n el.checked = Boolean(value)\r\n } else {\r\n el.value = String(value ?? '')\r\n }\r\n })\r\n })\r\n }\r\n}\r\n","import type { IFormRepository } from './IFormRepository'\r\nimport { snakeToCamel, camelToSnake } from './nameUtils'\r\n\r\n/**\r\n * Implementação em memória de `IFormRepository` para uso em testes unitários.\r\n * Não depende de DOM, jQuery ou da plataforma — permite testar Presenters em isolamento.\r\n *\r\n * Aplica a mesma lógica de prefixo e conversão de `BpmFormRepository`: armazena\r\n * internamente com o nome DOM completo (`{section}_{snake_case}`) e converte para\r\n * camelCase ao retornar — garantindo que os testes reflitam o comportamento real.\r\n *\r\n * @example\r\n * const repo = new MockFormRepository()\r\n * repo.save('vigencia', { prazo: '12', tipoDePrazo: 'Meses' })\r\n * const data = repo.load<Vigencia>('vigencia')\r\n * // data.prazo === '12'\r\n * // data.tipoDePrazo === 'Meses'\r\n *\r\n * @example\r\n * const repo = new MockFormRepository()\r\n * repo.save('imovel', { cep: '01310100', logradouro: 'Av. Paulista' })\r\n * repo.save('contrato', { indice: 'IGPM', primeiroPagamento: '2026-02-01' })\r\n * // imovel_cep e contrato_indice são domínios distintos — sem colisão\r\n */\r\nexport class MockFormRepository implements IFormRepository {\r\n /** Armazena valores com chave no formato DOM completo: `{section}_{snake_case}`. */\r\n private readonly store = new Map<string, unknown>()\r\n private readonly tables = new Map<string, unknown[]>()\r\n\r\n load<T>(section: string): Partial<T> {\r\n const prefix = `${section}_`\r\n const result: Record<string, unknown> = {}\r\n for (const [domName, value] of this.store.entries()) {\r\n if (domName.startsWith(prefix)) {\r\n const camelKey = snakeToCamel(domName.slice(prefix.length))\r\n result[camelKey] = value\r\n }\r\n }\r\n return result as Partial<T>\r\n }\r\n\r\n loadTable<T>(tableName: string): T[] {\r\n return (this.tables.get(tableName) ?? []) as T[]\r\n }\r\n\r\n save<T>(section: string, data: Partial<T>): void {\r\n const prefix = `${section}_`\r\n Object.entries(data as Record<string, unknown>).forEach(([camelKey, value]) => {\r\n this.store.set(`${prefix}${camelToSnake(camelKey)}`, value)\r\n })\r\n }\r\n\r\n saveTable<T>(tableName: string, rows: T[]): void {\r\n this.tables.set(tableName, [...rows])\r\n }\r\n\r\n /**\r\n * Limpa todo o estado interno — campos e tabelas.\r\n * Ideal para uso em `beforeEach` nos testes.\r\n */\r\n reset(): void {\r\n this.store.clear()\r\n this.tables.clear()\r\n }\r\n}\r\n","/**\r\n * Lê campos do formulário por mapeamento explícito `{ propriedadeModelo: nomeDOM }`.\r\n *\r\n * Utilitário para **processos legados** cujos campos não seguem a convenção\r\n * `{domínio}_{atributo}` — use quando o nome DOM não pode ser alterado sem\r\n * migração de dados no banco EGD.\r\n *\r\n * Novos processos devem usar `IFormRepository.load(section)` diretamente.\r\n *\r\n * @param fieldMap Mapeamento de propriedade do modelo → nome do campo no DOM\r\n * @returns Objeto parcial com os valores lidos, chaveado pelos atributos do modelo\r\n *\r\n * @example\r\n * ```typescript\r\n * // Processo legado: campos com sufixo em vez de prefixo\r\n * import { loadFields } from 'jsegd-bpm'\r\n *\r\n * interface Solicitante {\r\n * nome: string\r\n * email: string\r\n * }\r\n *\r\n * const dados = loadFields<Solicitante>({\r\n * nome: 'nome_solicitante',\r\n * email: 'email_solicitante',\r\n * })\r\n * // dados.nome === valor de input[name=\"nome_solicitante\"]\r\n * ```\r\n */\r\nexport function loadFields<T>(fieldMap: { [K in keyof T]?: string }): Partial<T> {\r\n const result: Partial<T> = {}\r\n for (const modelKey of Object.keys(fieldMap) as (keyof T)[]) {\r\n const domName = fieldMap[modelKey]\r\n if (!domName) continue\r\n const el = document.querySelector<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(\r\n `[name=\"${domName}\"]`\r\n )\r\n if (!el) continue\r\n result[modelKey] = (\r\n el instanceof HTMLInputElement && el.type === 'checkbox' ? el.checked : el.value\r\n ) as T[typeof modelKey]\r\n }\r\n return result\r\n}\r\n","import type { WorkflowModuleDefinition, WorkflowActivityDefinition, WorkflowConfig } from './types'\r\n\r\n/**\r\n * Define a configuração de workflow de um projeto BPM a partir de uma\r\n * declaração única de módulos e atividades. O tipo `ModuleId` é inferido\r\n * automaticamente do array de módulos — nenhum type alias manual é necessário.\r\n *\r\n * @param config Objeto com `modules` (definições de módulo) e `activities` (políticas por atividade)\r\n * @returns Configuração tipada pronta para uso em `resolveWorkflowScreen` e `extractCompletedStages`\r\n *\r\n * @example\r\n * const workflowConfig = defineWorkflowConfig({\r\n * modules: [\r\n * { moduleId: 'solicitante', label: 'Dados Iniciais', icon: 'file', order: 1,\r\n * showInNavigation: true, renderContent: true, contentIncludePath: 'solicitante.html' },\r\n * { moduleId: 'juridico', label: 'Jurídico', icon: 'gavel', order: 2,\r\n * showInNavigation: true, renderContent: true, contentIncludePath: 'juridico.html' },\r\n * ],\r\n * activities: [\r\n * { sequence: 9, description: 'Solicitação inicial', kind: 'human', stage: 'solicitacao',\r\n * modules: { visible: ['solicitante'], editable: ['solicitante'], active: 'solicitante' } },\r\n * { sequence: 88, description: 'Roteamento', kind: 'routing' },\r\n * ]\r\n * } as const)\r\n * // Tipo de ModuleId inferido automaticamente: 'solicitante' | 'juridico'\r\n */\r\nexport function defineWorkflowConfig<\r\n const M extends readonly (WorkflowModuleDefinition & { moduleId: string })[]\r\n>(config: {\r\n modules: M\r\n activities: readonly WorkflowActivityDefinition<M[number]['moduleId']>[]\r\n}): WorkflowConfig<M, M[number]['moduleId']> {\r\n return config\r\n}\r\n","import type { WorkflowActivityDefinition } from './types'\r\n\r\n/**\r\n * Entrada do histórico do processo BPM retornada por\r\n * `parent.ECM.workflowView.processDefinition.urlHistory`.\r\n * As chaves do objeto pai são arbitrárias — usar apenas `movementDate` e\r\n * `movementHour` para determinar a ordem cronológica real.\r\n */\r\nexport interface BpmHistoryEntry {\r\n /** `null` = ação de usuário; `'SYSTEM'` = tarefa de sistema; `'OBSERVATION'`/`'ATTACHMENT'` = ignorar */\r\n historyType: 'SYSTEM' | 'OBSERVATION' | 'ATTACHMENT' | null\r\n /** Equivalente a `WorkflowActivityDefinition.sequence` */\r\n stateSequence: number\r\n /** `0` = atividade de usuário/sistema | `1` = gateway/decisão automática */\r\n stateType: number\r\n /** Timestamp numérico para ordenação — `null` em sub-registros sem posição cronológica */\r\n movementDate: number | null\r\n /** Hora no formato `\"HH:mm:ss\"` — desempate na ordenação quando `movementDate` é igual */\r\n movementHour: string | null\r\n /** Rótulo da atividade no motor BPM */\r\n labelActivity: string | null\r\n}\r\n\r\n/** Mapa bruto retornado por `urlHistory` — chaves são arbitrárias, ignorar na ordenação */\r\nexport type BpmHistoryMap = Record<string, BpmHistoryEntry>\r\n\r\n/** Histórico processado — alimenta `ScreenContext` para construir a barra de progresso */\r\nexport interface ProcessHistory {\r\n /** Estágios concluídos em ordem cronológica real; deduplica estágios repetidos */\r\n completedStages: string[]\r\n /** Estágio atual com seu status; `null` se a atividade atual não tiver stage mapeado */\r\n currentStage: { stage: string; status: 'current' | 'waiting' } | null\r\n}\r\n\r\n/**\r\n * Extrai os estágios concluídos do histórico BPM na ordem cronológica real.\r\n * Ignora gateways (`stateType === 1`), entradas `SYSTEM`, `OBSERVATION` e `ATTACHMENT`,\r\n * e sub-registros sem `movementDate`. Deduplica estágios — a primeira ocorrência\r\n * cronológica define a posição na barra de progresso.\r\n *\r\n * @param history Mapa bruto retornado por `urlHistory` do processo BPM\r\n * @param activities Array de definições de atividade do `WorkflowConfig`\r\n * @returns Array de stage IDs na ordem em que ocorreram no processo\r\n */\r\nexport function extractCompletedStages(\r\n history: BpmHistoryMap,\r\n activities: readonly WorkflowActivityDefinition[]\r\n): string[] {\r\n const entries = Object.values(history).filter(\r\n (e) =>\r\n e.historyType === null &&\r\n e.stateType !== 1 &&\r\n e.movementDate !== null\r\n )\r\n\r\n entries.sort((a, b) => {\r\n const dateDiff = (a.movementDate as number) - (b.movementDate as number)\r\n if (dateDiff !== 0) return dateDiff\r\n return (a.movementHour ?? '').localeCompare(b.movementHour ?? '')\r\n })\r\n\r\n const seenStages = new Set<string>()\r\n const result: string[] = []\r\n\r\n for (const entry of entries) {\r\n const actDef = activities.find((a) => a.sequence === entry.stateSequence)\r\n if (actDef?.stage && !seenStages.has(actDef.stage)) {\r\n seenStages.add(actDef.stage)\r\n result.push(actDef.stage)\r\n }\r\n }\r\n\r\n return result\r\n}\r\n\r\n/**\r\n * Determina o estágio atual e seu status (`'current'` ou `'waiting'`).\r\n * Retorna `null` se a sequência atual não tiver um `stage` mapeado na configuração.\r\n *\r\n * @param currentSequence Número de sequência da atividade atual do processo\r\n * @param currentHistoryType `historyType` da entrada atual — `null` para ação humana, `'SYSTEM'` para espera\r\n * @param activities Array de definições de atividade do `WorkflowConfig`\r\n * @returns Objeto com `stage` e `status`, ou `null`\r\n */\r\nexport function extractCurrentStage(\r\n currentSequence: number,\r\n currentHistoryType: 'SYSTEM' | null,\r\n activities: readonly WorkflowActivityDefinition[]\r\n): { stage: string; status: 'current' | 'waiting' } | null {\r\n const actDef = activities.find((a) => a.sequence === currentSequence)\r\n if (!actDef?.stage) return null\r\n return {\r\n stage: actDef.stage,\r\n status: currentHistoryType === 'SYSTEM' ? 'waiting' : 'current',\r\n }\r\n}\r\n","import type { WorkflowActivityDefinition } from './types'\r\nimport type { ProcessHistory } from './history-parser'\r\n\r\n/** Módulo com políticas de visibilidade e editabilidade resolvidas para a atividade atual */\r\nexport interface ResolvedModule {\r\n moduleId: string\r\n label: string\r\n icon: string\r\n order: number\r\n showInNavigation: boolean\r\n renderContent: boolean\r\n contentIncludePath: string\r\n isVisible: boolean\r\n isEditable: boolean\r\n isActive: boolean\r\n}\r\n\r\n/**\r\n * Contexto de tela para uma atividade de workflow.\r\n * Consultado por Presenters para decidir visibilidade/editabilidade\r\n * sem conhecer números de sequência.\r\n *\r\n * @hideconstructor\r\n */\r\nexport class ScreenContext {\r\n constructor(\r\n private readonly activity: WorkflowActivityDefinition,\r\n private readonly resolvedModules: readonly ResolvedModule[],\r\n private readonly history: ProcessHistory\r\n ) {}\r\n\r\n /**\r\n * Retorna `true` se o módulo é visível na atividade atual.\r\n *\r\n * @param moduleId Identificador do módulo\r\n */\r\n isVisible(moduleId: string): boolean {\r\n return this.resolvedModules.find((m) => m.moduleId === moduleId)?.isVisible ?? false\r\n }\r\n\r\n /**\r\n * Retorna `true` se o módulo é editável na atividade atual.\r\n *\r\n * @param moduleId Identificador do módulo\r\n */\r\n isEditable(moduleId: string): boolean {\r\n return this.resolvedModules.find((m) => m.moduleId === moduleId)?.isEditable ?? false\r\n }\r\n\r\n /**\r\n * Retorna `true` se o módulo é o ativo (tab selecionada) na atividade atual.\r\n *\r\n * @param moduleId Identificador do módulo\r\n */\r\n isActive(moduleId: string): boolean {\r\n return this.resolvedModules.find((m) => m.moduleId === moduleId)?.isActive ?? false\r\n }\r\n\r\n /**\r\n * Retorna o número de sequência da atividade atual no motor BPM EGD.\r\n *\r\n * Equivalente a `WorkflowActivityDefinition.sequence`. Exposto para presenters\r\n * que precisam do valor em regras de domínio baseadas em sequências específicas\r\n * (ex: listas de sequences especiais para exibir/ocultar campos).\r\n */\r\n getSequence(): number {\r\n return this.activity.sequence\r\n }\r\n\r\n /**\r\n * Retorna `true` se a atividade atual está aguardando um sistema externo\r\n * (`kind === 'system'` ou `currentStage.status === 'waiting'`).\r\n */\r\n isAwaitingSystem(): boolean {\r\n return this.activity.kind === 'system' || this.history.currentStage?.status === 'waiting'\r\n }\r\n\r\n /**\r\n * Retorna `true` se a atividade atual é uma atividade de suporte transversal.\r\n */\r\n isInSupport(): boolean {\r\n return this.activity.kind === 'support'\r\n }\r\n\r\n /**\r\n * Retorna os estágios para renderizar na barra de progresso.\r\n * Inclui os estágios concluídos do histórico (`'done'`) e o estágio atual\r\n * (`'current'` ou `'waiting'`), sem duplicar.\r\n */\r\n getProgressBarStages(): Array<{ stage: string; status: 'done' | 'current' | 'waiting' }> {\r\n const stages: Array<{ stage: string; status: 'done' | 'current' | 'waiting' }> = this.history.completedStages.map(\r\n (stage) => ({ stage, status: 'done' as const })\r\n )\r\n\r\n const current = this.history.currentStage\r\n if (current && !this.history.completedStages.includes(current.stage)) {\r\n stages.push({ stage: current.stage, status: current.status })\r\n }\r\n\r\n return stages\r\n }\r\n\r\n /**\r\n * Retorna todos os módulos resolvidos, incluindo os não-visíveis.\r\n */\r\n getModules(): readonly ResolvedModule[] {\r\n return this.resolvedModules\r\n }\r\n\r\n /**\r\n * Retorna apenas os módulos visíveis, ordenados por `order` ascendente.\r\n */\r\n getVisibleModules(): readonly ResolvedModule[] {\r\n return [...this.resolvedModules].filter((m) => m.isVisible).sort((a, b) => a.order - b.order)\r\n }\r\n\r\n /**\r\n * Retorna os módulos que aparecem na navegação (`showInNavigation && isVisible`),\r\n * ordenados por `order` ascendente.\r\n */\r\n getNavigationModules(): readonly ResolvedModule[] {\r\n return this.getVisibleModules().filter((m) => m.showInNavigation)\r\n }\r\n}\r\n","import type { WorkflowConfig } from './types'\r\nimport type { ProcessHistory } from './history-parser'\r\nimport { ScreenContext } from './screen-context'\r\nimport type { ResolvedModule } from './screen-context'\r\n\r\n/**\r\n * Resolve a tela para a sequência informada, cruzando a configuração do workflow\r\n * com o histórico do processo para produzir um `ScreenContext`.\r\n *\r\n * @param config Configuração gerada por `defineWorkflowConfig`\r\n * @param sequence Número de sequência da atividade atual no processo BPM\r\n * @param history Histórico processado via `extractCompletedStages` e `extractCurrentStage`\r\n * @returns `ScreenContext` pronto para consulta pelos Presenters\r\n *\r\n * @throws {Error} Se a sequência não estiver mapeada na configuração\r\n *\r\n * @example\r\n * const screen = resolveWorkflowScreen(workflowConfig, 53, processHistory)\r\n * screen.isVisible('juridico') // true\r\n * screen.isEditable('juridico') // true\r\n * screen.isInSupport() // false\r\n */\r\nexport function resolveWorkflowScreen(\r\n config: WorkflowConfig<readonly import('./types').WorkflowModuleDefinition[]>,\r\n sequence: number,\r\n history: ProcessHistory\r\n): ScreenContext {\r\n const activity = config.activities.find((a) => a.sequence === sequence)\r\n if (!activity) {\r\n throw new Error(`[jsegd-bpm] Sequência ${sequence} não encontrada na configuração do workflow.`)\r\n }\r\n\r\n const resolvedModules: ResolvedModule[] = config.modules.map((mod) => {\r\n const isVisible = activity.modules?.visible.includes(mod.moduleId) ?? false\r\n const isEditable = activity.modules?.editable.includes(mod.moduleId) ?? false\r\n const isActive = activity.modules?.active === mod.moduleId\r\n\r\n return {\r\n ...mod,\r\n isVisible,\r\n isEditable,\r\n isActive,\r\n }\r\n })\r\n\r\n // Se nenhum módulo for marcado como active, ativa o primeiro showInNavigation && isVisible\r\n const hasActive = resolvedModules.some((m) => m.isActive)\r\n if (!hasActive) {\r\n const firstVisible = resolvedModules.find((m) => m.showInNavigation && m.isVisible)\r\n if (firstVisible) {\r\n firstVisible.isActive = true\r\n }\r\n }\r\n\r\n return new ScreenContext(activity, resolvedModules, history)\r\n}\r\n","import type { Alpine } from 'alpinejs'\r\n\r\n/** Mapa de stores: chave = nome do store, valor = objeto do store */\r\nexport type StoreMap = Record<string, object>\r\n\r\n/**\r\n * Tipo utilitário que gera um proxy com getters tipados para cada store registrado.\r\n * Permite `stores.contador` ao invés de `Alpine.store('contador') as ContadorStore`.\r\n */\r\nexport type StoreProxy<T extends StoreMap> = {\r\n readonly [K in keyof T]: T[K]\r\n}\r\n\r\n/**\r\n * Registra múltiplos Alpine stores e retorna um proxy tipado para acesso direto.\r\n * Deve ser chamado no ponto de inicialização da aplicação, antes de `Alpine.start()`.\r\n *\r\n * @param alpine Instância Alpine — aceita `Pick<Alpine, 'store'>` para facilitar mock em testes\r\n * @param storeMap Objeto com pares `{ nomeDoStore: objetoInicial }`\r\n * @returns Proxy tipado para leitura dos stores sem casting manual\r\n *\r\n * @example\r\n * const stores = registerStores(Alpine, {\r\n * usuario: { nome: '', perfil: '' as PerfilId },\r\n * ui: { carregando: false, erro: null as string | null }\r\n * })\r\n * // stores.usuario.nome está tipado como string\r\n * // Internamente: Alpine.store('usuario', { nome: '', perfil: '' })\r\n */\r\nexport function registerStores<T extends StoreMap>(\r\n alpine: Pick<Alpine, 'store'>,\r\n storeMap: T\r\n): StoreProxy<T> {\r\n for (const [name, store] of Object.entries(storeMap)) {\r\n alpine.store(name, store)\r\n }\r\n return new Proxy(storeMap, {\r\n get: (_target, prop: string) => alpine.store(prop),\r\n }) as StoreProxy<T>\r\n}\r\n"],"names":["getStringFromWasm0","e","t","o","s","a","TextDecoder","ignoreBOM","fatal","decode","i","byteLength","Uint8Array","l","memory","buffer","subarray","FinalizationRegistry","__wbg_validate_free","__wbg_writtenout_free","c","TextEncoder","encodeInto","r","encode","set","read","length","written","LocalCache","static","dbPromise","isInitialized","cacheExpirationMs","storeName","constructor","getInstance","instance","initialize","this","Error","ensureInitialized","promisifyRequest","Promise","onsuccess","result","onerror","error","openDatabase","n","indexedDB","open","onupgradeneeded","objectStoreNames","contains","createObjectStore","keyPath","get","transaction","objectStore","Date","now","timestamp","remove","catch","data","key","put","oncomplete","delete","clear","purgeExpired","getAll","filter","u","m","f","ConstraintsType","Second","Minute","Hour","Day","Week","Month","Bimonth","Quarter","Semester","Year","BRL","USD","EUR","JPY","GBP","CNY","DOCUMENT","EMAIL","MOBILE","EVP","async","Object","getPrototypeOf","prototype","module_or_path","console","warn","URL","url","__proto__","__wbg_Error_960c155d3d49e4c2","__wbg___wbindgen_throw_6b64449b9b9ed33c","__wbindgen_cast_0000000000000001","__wbindgen_init_externref_table","__wbindgen_externrefs","grow","Request","fetch","module","Response","WebAssembly","instantiateStreaming","ok","type","headers","arrayBuffer","instantiate","Instance","exports","__wbindgen_start","_instantiateOrCompile","compileStreaming","compile","process","versions","node","require","readFile","resolve","__dirname","WorkerManager","pool","workerMeta","Map","taskQueue","inFlight","cache","nextRequestId","options","poolSize","cacheOptions","lc","worker","Worker","onmessage","handleResponse","busy","push","query","baseUrl","params","buildUrl","wrapperPromise","then","cached","deduplicateOrEnqueue","canceller","promise","res","rej","abortRequest","cancel","terminate","has","enqueueRequest","requestId","requestUrl","payload","resolveFn","rejectFn","reject","pending","scheduleNext","meta","task","shift","currentKey","currentRequestId","postMessage","externalReject","queueIndex","findIndex","splice","response","aborted","success","searchParams","datasetId","field","forEach","append","undefined","offset","String","limit","orderby","constraintsField","constraintsInitialValue","v","constraintsFinalValue","constraintsType","constraintsLikeSearch","b","toString","GENERIC_ATTACHMENT_MARKER","METADATA_ATTACHMENT_NAME","getAttachmentOps","parent","WKFViewAttachment","getAllAttachments","openAttachmentView","colleagueId","documentId","version","downloadAttach","indexes","confirmRemoveAttach","editAttach","row","index","attachEdit","deleteAttachmentSilent","attachment","deleteAttachments","getProcessInfo","ECM","getUserPermissions","workflowView","userPermissions","getProcessInstanceId","processDefinition","processInstanceId","getTaskUserId","taskUserId","getWorkflowSequence","sequence","getTableData","attachmentTable","getData","getTableRow","getRow","getWorkflowContext","parentDocument","document","renderTemplate","template","mustache","Mustache","render","removeDragListeners","$","off","overrideSuccessRemoveAttachment","handler","successRemoveAttachment","bind","bindFileUploadHandlers","callbacks","getECM","on","validateUpload","includes","window","dispatchEvent","CustomEvent","FLUIGC","toast","message","duplicated","files","item","arr","indexOf","sort","idx","file","attachFileMonitor","add","name","fullPath","defFullPath","droppedZipZone","hasApprovers","defHasApprovers","isDuplicate","newAttachmentsDocs","some","d","maxMb","maxUploadSize","size","core","formatSize","datasUpload","id","context","onFileAdd","internalId","el","attr","cameraName","description","removeAttr","uploadId","startPublishingDocument","onFileDone","onFileFail","isMetadataAttachment","startsWith","getAttachmentsByDescription","toLowerCase","replace","filterPublishedAttachments","attachments","newAttach","findAttachmentTableIndex","predicate","hasPermission","isNewProcess","isOwnAttachment","canEditAttachment","sanitizeAttachmentName","input","sanitized","trim","substring","normalize","applyNextVersion","nextVersion","maxVersion","match","parseInt","Math","max","getNextVersion","AttachmentPickerModal","datatable","modal","callback","existing","getElementById","createModal","createTable","bindEvents","dataRequest","renderContent","header","title","multiSelect","search","enabled","onlyEnterkey","searchAreaStyle","onSearch","scroll","navButtons","tableStyle","emptyMessage","classSelected","actions","actionAreaStyle","draggable","onDrag","content","showHeader","showFooter","headerActions","headerContent","formModal","selectedIndex","destroy","Attach","interceptUploadEvents","addEventListener","detail","download","Array","isArray","_e","_data","source","currentUploadSource","accept","currentUploadAccept","attachmentDescription","element","setAttribute","click","view","publishedAttachments","edit","editableAttachments","downloadBlob","blob","filename","Blob","createObjectURL","createElement","href","revokeObjectURL","uploadBlob","mimeType","inputFile","safeDescription","File","dt","DataTransfer","items","Event","DragDropNameModal","onConfirm","from","rows","map","sanitizeAttributeValue","sanitizeText","join","cfg","label","classType","autoClose","handleUseOriginals","querySelector","confirm","target","querySelectorAll","disabled","checked","value","inputs","entries","removeEventListener","text","sessionCache","AttachmentMetadataFile","exists","findAttachment","att","find","load","force","credentials","status","raw","json","parseAndMigrate","save","metadata","updated","updatedAt","toISOString","ctx","JSON","stringify","empty","CURRENT_VERSION","buttons","CONTAINER_ID","TOOLBAR_ID","THEAD","TEMPLATE_BUTTONS_ONLY","TEMPLATE_SELF_MANAGED","TOOLBAR_HTML","AttachmentsTable","start","mode","attachInstance","hydrateFromMetadata","registerButton","registration","buttonRegistry","persistMetadata","resolveButtonRegistration","base","nativeContainer","style","display","attachmentsRoot","toolbarWrapper","innerHTML","appendChild","firstElementChild","container","event","openLink","closest","preventDefault","getAttribute","Number","downloadIcon","th","column","ascending","sortBy","editIcon","reversionIcon","btnDescription","btnAccept","deleteIcon","openNameInputModal","stopPropagation","classList","dataTransfer","allAttachments","newAttachment","record","buttonDescription","workflowSequence","uploadedAt","isSelfManaged","sanitizeAttachmentForDisplay","enableDownload","btn","enableView","enableEdit","enableReversion","enableDelete","buttonAccept","unpublishedVersion","current","reg","rawName","safeName","getRows","setOrder","tbody","valueA","getCellValue","valueB","localeCompare","textContent","AttachButton","HTMLElement","noaddbutton","noviewbutton","noeditbutton","nodeletebutton","handleSuccess","button","shadowRoot","color","backgroundColor","handleError","handleDefault","super","shadow","attachShadow","cloneNode","observedAttributes","attributeChangedCallback","_oldValue","newValue","isConnected","displayButtons","disconnectedCallback","connectedCallback","addButton","viewButton","editButton","removeButton","parentElement","showModal","attachModal","err","autocomplete","q","cb","matches","prefixes","Set","getGenericAttachmentDescriptions","highlight","displayKey","tagClass","toUpperCase","customElements","define","BeforeSendValidate","clearAllErrors","group","helperElement","throwValidationError","fields","errorMessage","clearErrorHandler","once","validMessages","combinedMessages","hooksMap","beforeValidate","afterValidate","onMoveSuccess","onMoveError","onCompletionLinkAdd","sendRequestEvent","enableButtons","enableSendButton","enableActionButtons","fn","nextActivityElement","nextActivity","selectActivity","callFormFunction","disableActionButtons","sendRequest","overrides","WorkflowViewPatcher","init","timeout","isInitializing","startTime","ECM_WKFView","setTimeout","patch","originalMethods","patchMany","attrs","patchAll","keys","restore","originalFn","k","getHooks","addBeforeValidate","addAfterValidate","addOnMoveSuccess","addOnMoveError","addOnCompletionLinkAdd","snakeToCamel","str","_","letter","camelToSnake","BpmFormRepository","section","prefix","domName","camelKey","slice","HTMLInputElement","loadTable","tableName","rowData","baseName","lastIndexOf","Boolean","saveTable","rowId","wdkAddChild","MockFormRepository","store","tables","reset","loadFields","fieldMap","modelKey","defineWorkflowConfig","config","extractCompletedStages","history","activities","values","historyType","stateType","movementDate","dateDiff","movementHour","seenStages","entry","actDef","stateSequence","stage","extractCurrentStage","currentSequence","currentHistoryType","ScreenContext","activity","resolvedModules","isVisible","moduleId","isEditable","isActive","getSequence","isAwaitingSystem","kind","currentStage","isInSupport","getProgressBarStages","stages","completedStages","getModules","getVisibleModules","order","getNavigationModules","showInNavigation","resolveWorkflowScreen","modules","mod","visible","editable","active","hasActive","firstVisible","registerStores","alpine","storeMap","Proxy","_target","prop"],"mappings":"AAA06E,SAASA,mBAAmBC,EAAEC,GAAG,OAAO,SAASD,EAAEC,GAAkF,OAA/EC,GAAGD,EAAEC,GAAGC,IAAIC,EAAE,IAAIC,YAAY,QAAQ,CAACC,WAAU,EAAGC,OAAM,IAAKH,EAAEI,SAASN,EAAED,GAAUG,EAAEI,QAA4G,OAAOC,GAAG,IAAIA,EAAEC,aAAaD,EAAE,IAAIE,WAAWC,EAAEC,OAAOC,SAASL,GAA9IM,SAASf,EAAEA,EAAEC,GAAG,CAApJ,CAAsJD,KAAK,EAAEC,EAAE,CAAje,oBAAoBe,sBAAyD,IAAIA,qBAAsBhB,GAAGY,EAAEK,oBAAoBjB,IAAI,EAAE,IAAO,oBAAoBgB,sBAAyD,IAAIA,qBAAsBhB,GAAGY,EAAEM,sBAAsBlB,IAAI,EAAE,IAA6M,IAAIS,EAAE,KAA8qB,IAAIL,EAAE,IAAIC,YAAY,QAAQ,CAACC,WAAU,EAAGC,OAAM,IAAKH,EAAEI,SAAS,MAAML,EAAE,WAAW,IAAID,EAAE,EAAE,MAAMiB,EAAE,IAAIC,YAAoI,IAACR,EAAzH,eAAeO,IAAIA,EAAEE,WAAW,SAASrB,EAAEC,GAAG,MAAMqB,EAAEH,EAAEI,OAAOvB,GAAG,OAAOC,EAAEuB,IAAIF,GAAG,CAACG,KAAKzB,EAAE0B,OAAOC,QAAQL,EAAEI,OAAO,GAAa,MAAME,WAAWC,gBAAgBC,UAAU,KAAKC,eAAc,EAAGC,kBAAkBC,UAAU,WAAAC,GAAc,CAAC,kBAAOC,GAAc,OAAOP,WAAWQ,WAAWR,WAAWQ,SAAS,IAAIR,YAAYA,WAAWQ,QAAQ,CAAC,UAAAC,CAAWrC,GAAG,GAAGsC,KAAKP,cAAc,MAAM,IAAIQ,MAAM,kDAAkDD,KAAKL,gEAAgEK,KAAKN,kBAAkBhC,EAAEgC,kBAAkBM,KAAKL,UAAUjC,EAAEiC,UAAUK,KAAKP,eAAc,CAAE,CAAC,iBAAAS,GAAoB,IAAIF,KAAKP,cAAc,MAAM,IAAIQ,MAAM,qGAAqG,CAAC,gBAAAE,CAAiBzC,GAAG,OAAO,IAAI0C,QAAO,CAAGzC,EAAEqB,KAAKtB,EAAE2C,UAAU,IAAI1C,EAAED,EAAE4C,QAAQ5C,EAAE6C,QAAQ,IAAIvB,EAAEtB,EAAE8C,MAAO,EAAE,CAAC,kBAAMC,GAAe,GAAGT,KAAKE,oBAAoBF,KAAKR,UAAU,OAAOQ,KAAKR,UAAU,MAAM9B,EAAE,eAAesC,KAAKL,YAAY,OAAOK,KAAKR,UAAU,IAAIY,QAAO,CAAGzC,EAAEqB,KAAK,MAAM0B,EAAEC,UAAUC,KAAKlD,EAAE,GAAGgD,EAAEG,gBAAgB,KAAK,MAAMnD,EAAEgD,EAAEJ,OAAO5C,EAAEoD,iBAAiBC,SAASf,KAAKL,YAAYjC,EAAEsD,kBAAkBhB,KAAKL,UAAU,CAACsB,QAAQ,SAASP,EAAEL,UAAU,IAAI1C,EAAE+C,EAAEJ,QAAQI,EAAEH,QAAQ,KAAKvB,EAAE0B,EAAEF,OAAQ,GAAGR,KAAKR,SAAS,CAAC,SAAM0B,CAAIxD,GAAGsC,KAAKE,oBAAoB,IAAI,MAAkClB,SAApBgB,KAAKS,gBAAmBU,YAAYnB,KAAKL,UAAU,YAAYyB,YAAYpB,KAAKL,WAAWe,QAAQV,KAAKG,iBAAiBnB,EAAEkC,IAAIxD,IAAI,OAAOgD,EAAEW,KAAKC,MAAMZ,EAAEa,UAAUvB,KAAKN,yBAAyBM,KAAKwB,OAAO9D,GAAG+D,MAAK,KAAQ,GAAG,MAAMf,EAAEgB,KAAK,IAAI,CAAC,MAAMhE,GAAG,OAAO,IAAI,CAAC,CAAC,SAAMwB,CAAIxB,EAAEC,GAAGqC,KAAKE,oBAAoB,IAAI,MAAMlB,SAASgB,KAAKS,gBAAgBU,YAAYnB,KAAKL,UAAU,aAAae,EAAE1B,EAAEoC,YAAYpB,KAAKL,WAAWxB,EAAE,CAACwD,IAAIjE,EAAE6D,UAAUF,KAAKC,MAAMI,KAAK/D,SAASqC,KAAKG,iBAAiBO,EAAEkB,IAAIzD,UAAU,IAAIiC,QAAO,CAAG1C,EAAEC,KAAKqB,EAAE6C,WAAW,IAAInE,IAAIsB,EAAEuB,QAAQ,IAAI5C,EAAEqB,EAAEwB,MAAO,EAAE,CAAC,MAAM9C,GAAG,MAAMA,CAAC,CAAC,CAAC,YAAM8D,CAAO9D,GAAGsC,KAAKE,oBAAoB,IAAI,MAAMvC,SAASqC,KAAKS,gBAAgBU,YAAYnB,KAAKL,UAAU,aAAaX,EAAErB,EAAEyD,YAAYpB,KAAKL,iBAAiBK,KAAKG,iBAAiBnB,EAAE8C,OAAOpE,UAAU,IAAI0C,QAAO,CAAG1C,EAAEsB,KAAKrB,EAAEkE,WAAW,IAAInE,IAAIC,EAAE4C,QAAQ,IAAIvB,EAAErB,EAAE6C,MAAO,EAAE,CAAC,MAAM9C,GAAG,MAAMA,CAAC,CAAC,CAAC,WAAMqE,GAAQ/B,KAAKE,oBAAoB,IAAI,MAAMxC,SAASsC,KAAKS,gBAAgBU,YAAYnB,KAAKL,UAAU,aAAahC,EAAED,EAAE0D,YAAYpB,KAAKL,iBAAiBK,KAAKG,iBAAiBxC,EAAEoE,eAAe,IAAI3B,QAAO,CAAGzC,EAAEqB,KAAKtB,EAAEmE,WAAW,IAAIlE,IAAID,EAAE6C,QAAQ,IAAIvB,EAAEtB,EAAE8C,MAAO,EAAE,CAAC,MAAM9C,GAAG,MAAMA,CAAC,CAAC,CAAC,kBAAMsE,GAAehC,KAAKE,oBAAoB,IAAI,MAAMxC,SAASsC,KAAKS,gBAAgBU,YAAYnB,KAAKL,UAAU,aAAahC,EAAED,EAAE0D,YAAYpB,KAAKL,WAAWX,QAAQgB,KAAKG,iBAAiBxC,EAAEsE,UAAUvB,EAAEW,KAAKC,MAAMnD,EAAEa,EAAEkD,OAAQxE,GAAGgD,EAAEhD,EAAE6D,UAAUvB,KAAKN,mBAAoB,IAAI,MAAMhC,KAAKS,QAAQ6B,KAAKG,iBAAiBxC,EAAEmE,OAAOpE,EAAEiE,MAAM,aAAa,IAAIvB,QAAO,CAAGzC,EAAEqB,KAAKtB,EAAEmE,WAAW,IAAIlE,IAAID,EAAE6C,QAAQ,IAAIvB,EAAEtB,EAAE8C,MAAO,GAAGrC,EAAEiB,MAAM,CAAC,MAAM1B,GAAG,OAAO,CAAC,CAAC,EAA+mB,IAAIyE,EAAEC,EAAY1E,EAA2sD2E,ECA7kRC,GDAk4N5E,EAA8NyE,IAAIA,EAAE,CAAA,IAA/NzE,EAAE6E,OAAO,GAAG,SAAS7E,EAAEA,EAAE8E,OAAO,GAAG,SAAS9E,EAAEA,EAAE+E,KAAK,GAAG,OAAO/E,EAAEA,EAAEgF,IAAI,GAAG,MAAMhF,EAAEA,EAAEiF,KAAK,GAAG,OAAOjF,EAAEA,EAAEkF,MAAM,GAAG,QAAQlF,EAAEA,EAAEmF,QAAQ,GAAG,UAAUnF,EAAEA,EAAEoF,QAAQ,GAAG,UAAUpF,EAAEA,EAAEqF,SAAS,GAAG,WAAWrF,EAAEA,EAAEsF,KAAK,GAAG,OAAmB,SAAStF,GAAGA,EAAEA,EAAEuF,IAAI,GAAG,MAAMvF,EAAEA,EAAEwF,IAAI,GAAG,MAAMxF,EAAEA,EAAEyF,IAAI,GAAG,MAAMzF,EAAEA,EAAE0F,IAAI,GAAG,MAAM1F,EAAEA,EAAE2F,IAAI,GAAG,MAAM3F,EAAEA,EAAE4F,IAAI,GAAG,KAAK,CAAjH,CAAmHlB,IAAIA,EAAE,CAAA,IAAmQA,EAAEa,IAAsCb,EAAEc,IAAsCd,EAAEe,IAAsCf,EAAEgB,IAAsChB,EAAEiB,IAAsCjB,EAAEkB,IAA+5B,SAAS5F,GAAGA,EAAEA,EAAE6F,SAAS,GAAG,WAAW7F,EAAEA,EAAE8F,MAAM,GAAG,QAAQ9F,EAAEA,EAAE+F,OAAO,GAAG,SAAS/F,EAAEA,EAAEgG,IAAI,GAAG,KAAK,CAAnG,CAAqGrB,IAAIA,EAAE,CAAA,UAAgkCsB,eAAejG,GAAG,QAAG,IAASY,EAAE,OAAOA,OAAE,IAASZ,IAAIkG,OAAOC,eAAenG,KAAKkG,OAAOE,YAAYC,eAAerG,GAAGA,GAAGsG,QAAQC,KAAK,mGAA8F,IAASvG,IAAIA,EAAE,IAAIwG,IAAI,4BAA4BC,MAAM,MAAMxG,EAAE,CAACyG,UAAU,KAAK,gBAAgB,CAACA,UAAU,KAAKC,6BAA6B,SAAS3G,EAAEC,GAAG,OAAOsC,MAAMxC,mBAAmBC,EAAEC,GAAG,EAAE2G,wCAAwC,SAAS5G,EAAEC,GAAG,MAAM,IAAIsC,MAAMxC,mBAAmBC,EAAEC,GAAG,EAAE4G,iCAAiC,SAAS7G,EAAEC,GAAG,OAAOF,mBAAmBC,EAAEC,EAAE,EAAE6G,gCAAgC,WAAW,MAAM9G,EAAEY,EAAEmG,sBAAsB9G,EAAED,EAAEgH,KAAK,GAAGhH,EAAEwB,IAAI,OAAE,GAAQxB,EAAEwB,IAAIvB,EAAE,OAAE,GAAQD,EAAEwB,IAAIvB,EAAE,EAAE,MAAMD,EAAEwB,IAAIvB,EAAE,GAAE,GAAID,EAAEwB,IAAIvB,EAAE,GAAE,EAAG,KAAK,iBAAiBD,GAAG,mBAAmBiH,SAASjH,aAAaiH,SAAS,mBAAmBT,KAAKxG,aAAawG,OAAOxG,EAAEkH,MAAMlH,IAAI,MAAMoC,SAASd,EAAE6F,OAAOnE,SAASiD,eAAejG,EAAEC,GAAG,GAAG,mBAAmBmH,UAAUpH,aAAaoH,SAAS,CAAC,GAAG,mBAAmBC,YAAYC,qBAAqB,IAAI,aAAaD,YAAYC,qBAAqBtH,EAAEC,EAAE,CAAC,MAAMA,GAAG,IAAID,EAAEuH,KAAK,SAASvH,GAAG,OAAOA,GAAG,IAAI,QAAQ,IAAI,OAAO,IAAI,UAAU,OAAM,EAAG,OAAM,CAAE,CAA5E,CAA8EA,EAAEwH,OAAO,qBAAqBxH,EAAEyH,QAAQjE,IAAI,gBAAgB,MAAMvD,EAAEqG,QAAQC,KAAK,oMAAoMtG,EAAE,CAAC,MAAMqB,QAAQtB,EAAE0H,cAAc,aAAaL,YAAYM,YAAYrG,EAAErB,EAAE,CAAC,CAAC,MAAMqB,QAAQ+F,YAAYM,YAAY3H,EAAEC,GAAG,OAAOqB,aAAa+F,YAAYO,SAAS,CAACxF,SAASd,EAAE6F,OAAOnH,GAAGsB,CAAC,CAAC,CAAxuB2E,OAAgvBjG,EAAEC,GAAG,OAAO,SAASD,GAAG,OAAOY,EAAEZ,EAAE6H,QAAQpH,EAAE,KAAKG,EAAEkH,mBAAmBlH,CAAC,CAA5D,CAA8DU,EAAE,CAA1tD2E,CAA2tD,SAAWjG,GAAG,OAAO,SAASA,EAAEC,EAAEqB,EAAE0B,GAAG,SAAS+E,sBAAsB/H,EAAEC,EAAEqB,GAAG,IAAI0B,EAAE1B,EAAE+F,YAAYC,qBAAqBD,YAAYM,YAAYlH,EAAEa,EAAE+F,YAAYW,iBAAiBX,YAAYY,QAAQ,OAAOhI,EAAE+C,EAAEhD,EAAEC,GAAGQ,EAAET,EAAE,CAAC,GAAG,oBAAoBkI,SAAS,MAAMA,QAAQC,UAAU,MAAMD,QAAQC,SAASC,KAAK,CAAC,IAAI3H,EAAE4H,QAAQ,MAAMjI,EAAEiI,QAAQ,QAAQ,OAAO,IAAI3F,QAAO,CAAG1C,EAAEsB,KAAKb,EAAE6H,SAASlI,EAAEmI,QAAQC,UAAUvI,GAAE,CAAGA,EAAEQ,KAAK,MAAMR,EAAEqB,EAAErB,GAAGD,EAAE+H,sBAAsBtH,EAAEuC,GAAE,GAAK,EAAG,EAAE,CAAC,OAAO+E,sBAAsBb,MAAMjH,GAAG+C,GAAE,EAAG,CAApe,CAAse,EAAE,gBAAgB,EAAEhD,EAAG,SE+Cv+XyI,cACDC,KAAiB,GACjBC,WAAa,IAAIC,IACjBC,UAAoB,GACpBC,SAAwC,IAAIF,IAC5CG,MAAuB,KACvBC,cAAgB,EAExB,WAAA9G,CAAY+G,EAAgC,IACxC,MAAMC,EAAWD,EAAQC,UAAY,EAErC,GAAID,EAAQF,MACRzG,KAAKyG,MAAQE,EAAQF,WAClB,GAAIE,EAAQE,aAAc,CAC7B,MAAMC,EAAKxH,WAAWO,cACtBiH,EAAG/G,WAAW4G,EAAQE,cACtB7G,KAAKyG,MAAQK,CACjB,CAEA,IAAK,IAAI3I,EAAI,EAAGA,EAAIyI,EAAUzI,IAAK,CAC/B,MAAM4I,EAAS,IAAIC,OAAO,IAAI9C,IAAI,0BAA2BC,KAAM,CAAEe,KAAM,WAC3E6B,EAAOE,UAAavJ,GAAMsC,KAAKkH,eAAexJ,EAAEgE,KAAwBqF,GACxE/G,KAAKqG,WAAWnH,IAAI6H,EAAQ,CAAEI,MAAM,IACpCnH,KAAKoG,KAAKgB,KAAKL,EACnB,CACJ,CAMO,KAAAM,CAAMC,EAAiBC,GAC1B,MAAMpD,EAAMnE,KAAKwH,SAASF,EAASC,GAC7B5F,EAAMwC,EAENsD,EAAiBzH,KAAKyG,MACtBzG,KAAKyG,MAAMvF,IAAqBS,GAAK+F,KAAMC,GACnCA,GACG3H,KAAK4H,qBAAqBjG,EAAKwC,IAE1CnE,KAAK4H,qBAAqBjG,EAAKwC,GAErC,IAAI0D,UAAwB,OAM5B,MAAO,CAAEC,QALO,IAAI1H,QAAyB,CAAC2H,EAAKC,KAC/CH,UAAY,IAAM7H,KAAKiI,aAAatG,EAAKqG,GACzCP,EAAeC,KAAKK,EAAKC,KAGXE,OAAQL,UAC9B,CAMO,SAAAM,GACH,IAAK,MAAMpB,KAAU/G,KAAKoG,KACtBW,EAAOoB,YAEXnI,KAAKoG,KAAO,GACZpG,KAAKqG,WAAWtE,QAChB/B,KAAKuG,UAAY,GACjBvG,KAAKwG,SAASzE,OAClB,CAEQ,oBAAA6F,CAAqBjG,EAAawC,GACtC,OAAInE,KAAKwG,SAAS4B,IAAIzG,GACX3B,KAAKwG,SAAStF,IAAIS,GAAMmG,QAE5B9H,KAAKqI,eAAe1G,EAAK,CAAEuD,KAAM,UAAWoD,YAAatI,KAAK0G,cAAe6B,WAAYpE,GACpG,CAEQ,cAAAkE,CAAe1G,EAAa6G,GAChC,IAAIC,EACAC,EAEJ,MAAMZ,EAAU,IAAI1H,QAAa,CAAC6F,EAAS0C,KACvCF,EAAYxC,EACZyC,EAAWC,IAGTC,EAA0B,CAAEd,UAAS7B,QAASwC,EAAWE,OAAQD,GAIvE,OAHA1I,KAAKwG,SAAStH,IAAIyC,EAAKiH,GACvB5I,KAAKuG,UAAUa,KAAK,CAAEzF,MAAK6G,UAASI,YACpC5I,KAAK6I,eACEf,CACX,CAEQ,YAAAe,GACJ,IAAK,MAAM9B,KAAU/G,KAAKoG,KAAM,CAC5B,GAA8B,IAA1BpG,KAAKuG,UAAUnH,OAAc,MACjC,MAAM0J,EAAO9I,KAAKqG,WAAWnF,IAAI6F,GACjC,IAAK+B,EAAK3B,KAAM,CACZ,MAAM4B,EAAO/I,KAAKuG,UAAUyC,QAC5BF,EAAK3B,MAAO,EACZ2B,EAAKG,WAAaF,EAAKpH,IACvBmH,EAAKI,iBAAmBH,EAAKP,QAAQF,UACrCvB,EAAOoC,YAAYJ,EAAKP,QAC5B,CACJ,CACJ,CAEQ,YAAAP,CAAatG,EAAayH,GAC9BA,EAAe,IAAInJ,MAAM,sBAEzB,MAAMoJ,EAAarJ,KAAKuG,UAAU+C,UAAW3L,GAAMA,EAAEgE,MAAQA,GAC7D,IAAmB,IAAf0H,EAAmB,CACnB,MAAON,GAAQ/I,KAAKuG,UAAUgD,OAAOF,EAAY,GAGjD,OAFArJ,KAAKwG,SAAS1E,OAAOH,QACrBoH,EAAKH,QAAQD,OAAO,IAAI1I,MAAM,qBAElC,CAGA,IAAK,MAAO8G,EAAQ+B,KAAS9I,KAAKqG,WAC9B,GAAIyC,EAAKG,aAAetH,EAAK,CACzBoF,EAAOoC,YAAY,CAAEjE,KAAM,QAASoD,UAAWQ,EAAKI,mBACpD,KACJ,CAER,CAEQ,cAAAhC,CAAesC,EAA0BzC,GAC7C,MAAM+B,EAAO9I,KAAKqG,WAAWnF,IAAI6F,GAC3BpF,EAAMmH,EAAKG,WAEjBH,EAAK3B,MAAO,SACL2B,EAAKG,kBACLH,EAAKI,iBAEZ,MAAMN,EAAU5I,KAAKwG,SAAStF,IAAIS,GAGlC,GAFA3B,KAAKwG,SAAS1E,OAAOH,GAEjBiH,EACA,GAAIY,EAASC,QACTb,EAAQD,OAAO,IAAI1I,MAAM,2BACtB,GAAIuJ,EAASE,QAAS,CACzB,MAAMhI,EAAO8H,EAAS9H,KAClB1B,KAAKyG,OACLzG,KAAKyG,MAAMvH,IAAIyC,EAAKD,GAAMD,MAAM,QAEpCmH,EAAQ3C,QAAQvE,EACpB,MACIkH,EAAQD,OAAO,IAAI1I,MAAMuJ,EAAShJ,QAI1CR,KAAK6I,cACT,CAEQ,QAAArB,CAASF,EAAiBC,GAC9B,MAAMpD,EAAM,IAAID,IAAI,GAAGoD,0CAWvB,OAVAnD,EAAIwF,aAAazK,IAAI,YAAaqI,EAAOqC,WACzCrC,EAAOsC,OAAOC,QAASzH,GAAM8B,EAAIwF,aAAaI,OAAO,QAAS1H,SACxC2H,IAAlBzC,EAAO0C,QAAsB9F,EAAIwF,aAAazK,IAAI,SAAUgL,OAAO3C,EAAO0C,cACzDD,IAAjBzC,EAAO4C,OAAqBhG,EAAIwF,aAAazK,IAAI,QAASgL,OAAO3C,EAAO4C,QACxE5C,EAAO6C,SAASjG,EAAIwF,aAAazK,IAAI,UAAWqI,EAAO6C,SAC3D7C,EAAO8C,kBAAkBP,QAASzH,GAAM8B,EAAIwF,aAAaI,OAAO,mBAAoB1H,IACpFkF,EAAO+C,yBAAyBR,QAASS,GAAMpG,EAAIwF,aAAaI,OAAO,0BAA2BQ,IAClGhD,EAAOiD,uBAAuBV,QAASS,GAAMpG,EAAIwF,aAAaI,OAAO,wBAAyBQ,IAC9FhD,EAAOkD,iBAAiBX,QAASnM,GAAMwG,EAAIwF,aAAaI,OAAO,kBAAmBpM,IAClF4J,EAAOmD,uBAAuBZ,QAASa,GAAMxG,EAAIwF,aAAaI,OAAO,wBAAyBG,OAAOS,KAC9FxG,EAAIyG,UACf,GDlNJ,SAAYtI,GACRA,EAAA,KAAA,OACAA,EAAA,SAAA,WACAA,EAAA,OAAA,QACH,CAJD,CAAYA,IAAAA,EAAe,CAAA,IECpB,MAAMuI,EAA4B,MAM5BC,EAA2B,2BCoIxBC,mBACZ,IAAKC,OAAOC,kBACR,MAAM,IAAIhL,MAAM,4DAGpB,MAAMgL,kBAAEA,GAAsBD,OAE9B,MAAO,CACHE,kBAAiB,IACND,EAAkBC,oBAG7B,kBAAAC,CAAmBC,EAAqBC,EAAoBC,GACxDL,EAAkBE,mBAAmBC,EAAaC,EAAYC,EAClE,EAEA,cAAAC,CAAeC,GACXP,EAAkBM,eAAeC,EACrC,EAEA,mBAAAC,CAAoBD,GAChBP,EAAkBQ,oBAAoBD,EAC1C,EAEA,UAAAE,CAAWC,EAAgCC,GAErCX,EAA0BY,WAAWF,EAAKC,EAChD,EAEA,sBAAAE,CAAuBC,GACjBd,EAA0Be,kBAAkB,CAACD,GACnD,EAER,UAOgBE,iBACZ,IAAKjB,OAAOkB,IACR,MAAM,IAAIjM,MAAM,8CAGpB,MAAMiM,IAAEA,GAAQlB,OAEhB,MAAO,CACHmB,mBAAkB,IACND,EAAIE,aAAqBC,iBAAmB,GAGxDC,qBAAoB,IACTJ,EAAIE,aAAaG,kBAAkBC,kBAG9CC,cAAa,IACFP,EAAIE,aAAaG,kBAAkBG,WAG9CC,oBAAmB,IACRT,EAAIE,aAAaQ,SAG5BC,aAAY,IACDX,EAAIY,gBAAgBC,UAG/BC,YAAYpB,GACDM,EAAIY,gBAAgBG,OAAOrB,GAG9C,UC5LgBsB,qBACZ,MAAO,IACAnC,sBACAkB,oBDgMA,CACHkB,eAAgBnC,OAAOoC,SAEvB,cAAAC,CAAeC,EAAkB5L,GAC7B,MAAM6L,EAAYvC,OAAewC,SACjC,IAAKD,EACD,MAAM,IAAItN,MAAM,mDAEpB,OAAOsN,EAASE,OAAOH,EAAU5L,EACrC,EAEA,mBAAAgM,GACI,MAAMC,EAAK3C,OAAe2C,EACT,mBAANA,IACPA,EAAE,gBAAgBC,IAAI,2BACtBD,EAAE,gCAAgCC,IAAI,2BAE9C,MASG,CACH,+BAAAC,CAAgCC,GAC1B9C,OAAeC,kBAAkB8C,wBAA0BD,EAAQE,KAAMhD,OAAeC,kBAC9F,EAEA,sBAAAgD,CAAuBC,GACnB,MAAMP,EAAK3C,OAAe2C,EAC1B,GAAiB,mBAANA,EAAkB,OAC7B,MAAMQ,OAAS,IAAOnD,OAAekB,IAErCyB,EAAE,8BACGC,IAAI,iBACJQ,GAAG,gBAAiB,CAAC1Q,EAAQgE,KAC1B,MAAMwK,EAAMiC,SAEZ,GAAIjC,GAAKjB,mBAAmBoD,mBAAoB,OAAO,EAEvD,IAAKnC,GAAKE,cAAcC,iBAAiBiC,SAAS,KAM9C,OALAC,OAAOC,cAAc,IAAIC,YAAY,uBACrCC,OAAOC,MAAM,CACTC,QAAS,oDACT1J,KAAM,aAEH,EAGX,MAAM2J,EAAuB,GAC3BnN,EAAKoN,MAAiB5M,OAAO,CAAC6M,EAAMnD,EAAOoD,KACrCA,EAAIC,QAAQF,KAAUnD,GAAOiD,EAAWzH,KAAKwE,KAErDiD,EACKK,KAAK,CAACpR,EAAG6M,IAAMA,EAAI7M,GACnBgM,QAASqF,GAASzN,EAAKoN,MAAiBvF,OAAO4F,EAAK,IAEzD,IAAIJ,EAAY,KA4BhB,OA3BErN,EAAKoN,MAAiBhF,QAASsF,IAC7BL,EAAO7C,EAAImD,mBAAmBC,IAAI,CAC9BC,KAAMH,EAAKG,KACXC,SAAUtD,EAAIjB,mBAAmBwE,aAAe,MAChDC,gBAAgB,EAChBC,aAAczD,EAAIjB,mBAAmB2E,kBAAmB,IAE5D,MAAMC,EAAe3D,EAAI4D,oBAA8BC,KAClDC,GAAMA,EAAET,OAASR,GAAMQ,MAE5B,GAAIM,EAGA,OAFA3D,EAAImD,mBAAmB7O,MAAMuO,EAAM,+EACnCR,OAAOC,cAAc,IAAIC,YAAY,wBAC9B,EAEX,MAAMwB,EAAQ/D,EAAIgE,eAAiB,EACnC,GAAID,EAAQ,GAAKb,EAAKe,MAAgB,KAARF,EAAe,KAGzC,OAFA/D,EAAImD,mBAAmB7O,MAAMuO,EAAM,oDAAoD7C,EAAIkE,MAAMC,aAAaJ,IAAUA,EAAQ,SAChI1B,OAAOC,cAAc,IAAIC,YAAY,wBAC9B,EAEX,GAAI/M,EAAM,CACN,MAAM4O,EAAcpE,EAAIjB,mBAAmBqF,aAAgB/B,OAAe+B,YACtEA,IAAaA,EAAYvB,EAAKwB,IAAM7O,EAC5C,CACAA,EAAK8O,QAAUzB,GAAMyB,UAElBtC,EAAUuC,UAAU/S,EAAGgE,KAEjCkM,IAAI,kBACJQ,GAAG,iBAAkB,CAAC1Q,EAAQgE,KAC3B,MAAMwK,EAAMiC,SACVzM,EAAKpB,QAAQwO,OAAiBhF,QAASsF,IACrC,IAAIL,EAAY,CAAA,EAMhB,GALIrN,EAAK8O,UACLzB,EAAKwB,GAAK7O,EAAK8O,QAAQ9O,OAAO,WAC9BqN,EAAKS,SAAW9N,EAAK8O,QAAQ9O,OAAO,kBACpCqN,EAAKW,eAAiBhO,EAAK8O,QAAQ9O,OAAO,0BAE1C0N,EAAK5O,MACL+N,OAAOC,cAAc,IAAIC,YAAY,uBACrCvC,GAAKmD,mBAAmB7O,MAAMuO,EAAMK,EAAK5O,YACtC,GAAIuO,EAAM,CACbA,EAAKQ,KAAOH,EAAKG,KACjBR,EAAK2B,WAAarP,KAAKC,MACvB,MAAMqP,EAAKhD,IAAI,mCACf,GAAqC,SAAjCgD,GAAIC,OAAO,kBAA8B,CACzC,MAAMC,EAAaF,EAAGC,KAAK,yBACvBC,IAAY9B,EAAK+B,YAAcD,GACnCF,EAAGI,WAAW,kBACdJ,EAAGI,WAAW,wBAClB,CACAhC,EAAKiC,SAAW5B,EAAK4B,SACrB9E,GAAKjB,mBAAmBgG,0BAA0B,KAAMlC,GACxDb,EAAUgD,WAAWxT,EAAGgE,EAAM,CAAEoP,YAAa/B,EAAK+B,YAAavB,KAAMR,EAAKQ,MAC9E,MAGP3B,IAAI,kBACJQ,GAAG,iBAAkB,CAAC1Q,EAAQgE,KAC3B,GAAIA,GAAM8O,QAAS,CACf,MAAMtE,EAAMiC,SACNY,EAAY,CAAEwB,GAAI7O,EAAK8O,QAAQ9O,OAAO,YAC5CwK,GAAKmD,mBAAmBnH,SAAS6G,EACrC,CACAb,EAAUiD,WAAWzT,EAAGgE,IAEpC,GC5TR,CCvBM,SAAU0P,qBAAqBrF,GACjC,OAAOA,EAAW+E,YAAYO,WAAW,UAC7C,CAMM,SAAUC,4BAA4BR,GACxC,MAAMN,EAAUtD,qBAChB,OAAI4D,IAAgBjG,EACT2F,EAAQtF,oBAAoBhJ,OAAQ6J,GAAeA,EAAW+E,YAAYS,cAAcjD,SAASwC,EAAYS,gBAEjHf,EACFtF,oBACAhJ,OAAQ6J,GAAeA,EAAW+E,YAAYU,QAAQ,SAAU,IAAID,gBAAkBT,EAAYS,cAC3G,CAKM,SAAUE,2BAA2BC,GACvC,OAAOA,EAAYxP,OAAQ6J,IAAwC,IAAzBA,EAAW4F,UACzD,CAMM,SAAUC,yBAAyBC,GACrC,OAAO3E,qBAAqBL,eAAevD,UAAUuI,EACzD,CAeM,SAAUC,cAAc5M,GAC1B,OAAOgI,qBAAqBf,qBAAqB8C,QAAQ/J,IAAS,CACtE,UAMgB6M,eACZ,OAAuD,IAAhD7E,qBAAqBZ,sBAChC,CAKM,SAAU0F,gBAAgBjG,GAC5B,OAAOA,EAAWX,cAAgB8B,qBAAqBT,eAC3D,CAOM,SAAUwF,kBAAkBlG,GAC9B,OAAIiG,gBAAgBjG,GACT+F,cAAc,KAElBA,cAAc,IACzB,CAkBM,SAAUI,uBAAuBC,GACnC,IAAIC,EAAYD,EAAMX,QAAQ,yBAA0B,IAMxD,OALAY,EAAYA,EAAUZ,QAAQ,OAAQ,KAAKa,OACvCD,EAAUhT,OAAS,MACnBgT,EAAYA,EAAUE,UAAU,EAAG,MAEvCF,EAAYA,EAAUG,UAAU,OAAOf,QAAQ,mBAAoB,IAC5DY,CACX,CC1FM,SAAUI,iBAAiB1B,EAAqBY,GAClD,MAAMe,EAhBJ,SAAyBf,GAC3B,IAAIgB,EAAa,EAQjB,OAPAhB,EAAY5H,QAASiC,IACjB,MAAM4G,EAAQ5G,EAAW+E,YAAY6B,MAAM,YAC3C,GAAIA,EAAO,CACP,MAAMrH,EAAUsH,SAASD,EAAM,GAAI,IACnCD,EAAaG,KAAKC,IAAIJ,EAAYpH,EACtC,IAEGoH,EAAa,CACxB,CAMwBK,CAAerB,GACnC,OAAOZ,EAAYU,QAAQ,SAAU,IAAM,KAAKiB,GACpD,OCbaO,sBACDC,UACAC,MAER,WAAAtT,CAAY8R,EAA2ByB,GACnC,MAAMC,EAAWpI,OAAOoC,SAASiG,eAAe,iBAC5CD,GAAUA,EAAS5R,SACvBxB,KAAKkT,MAAQlT,KAAKsT,cAClBtT,KAAKiT,UAAYjT,KAAKuT,YAAY7B,GAClC1R,KAAKwT,WAAWL,EACpB,CAEQ,WAAAI,CAAY7B,GAChB,OAAO1G,OAAO0D,OAAOuE,UAAU,eAAgB,CAC3CQ,YAAa/B,EACbgC,cAAe,CAAC,mBAAoB,eAAgB,eACpDC,OAAQ,CAAC,CAAEC,MAAO,aAAe,CAAEA,MAAO,eAAiB,CAAEA,MAAO,cACpEC,aAAa,EACbC,OAAQ,CACJC,SAAS,EACTC,cAAc,EACdC,gBAAiB,SACjBC,SAAU,QAEdC,OAAQ,CAAEJ,SAAS,GACnBK,WAAY,CAAEL,SAAS,GACvBM,WAAY,4CACZC,aAAc,yBACdC,cAAe,GACfC,QAAS,CACLT,SAAS,EACTzG,SAAU,GACVmH,gBAAiB,IAErBC,UAAW,CACPX,SAAS,EACTY,OAAQ,SAGpB,CAEQ,WAAArB,GAOJ,OAAOtI,OAAO0D,OAAOwE,MACjB,CACIU,MAAO,YACPgB,QATe,wLAUfrE,GAAI,gBACJJ,KAAM,OACNqE,QAAS,GACTK,YAAY,EACZC,YAAY,EACZC,cAAe,GACfC,cAAe,GACfC,WAAW,GAEf,OAER,CAEQ,UAAAzB,CAAWL,GACfnT,KAAKiT,UAAU7E,GAAG,8BAAgC1M,IAC9C,MAAMqK,EAAa/L,KAAKiT,UAAUhG,OAAOvL,EAAKwT,cAAc,IAAI,GAChE/B,EAASpH,GAEsC,mBAAnC/L,KAAKiT,UAAkBkC,SAC7BnV,KAAKiT,UAAkBkC,UAE7BnV,KAAKkT,MAAM1R,UAEnB,QC/DS4T,OACD7V,gBAGRA,2BAA+C,SAE/CA,2BAA4C,KAE5C,WAAAK,GACII,KAAKqV,wBACL9G,OAAO+G,iBAAiB,4BAA6B,EAAGC,aACpDH,OAAOI,SAASD,EAAOlK,aAE/B,CAEO,kBAAOxL,GAIV,OAHKuV,OAAOtV,WACRsV,OAAOtV,SAAW,IAAIsV,QAEnBA,OAAOtV,QAClB,CAEQ,qBAAAuV,GACJ,MAAM7E,EAAUtD,qBAGhBsD,EAAQ9C,sBAGR8C,EAAQ3C,gCAAiCnM,IACrC6M,OAAOC,cAAc,IAAIC,YAAY,uBACrC,MAAMG,EAAU6G,MAAMC,QAAQhU,IAASA,EAAKtC,OAAS,EAC/C,4BACA,uBACNsP,OAAOC,MAAM,CAAEC,UAAS1J,KAAM,cAIlCsL,EAAQvC,uBAAuB,CAC3BwC,UAAW,CAACkF,EAAaC,OAGzB1E,WAAY,CAACyE,EAAaC,EAAgB7G,KACtCR,OAAOC,cAAc,IAAIC,YAAY,uBAAwB,CACzD8G,OAAQ,CACJzE,YAAa/B,EAAK+B,aAAe/B,EAAKQ,KACtCsG,OAAQT,OAAOU,oBACfC,OAAQX,OAAOY,yBAI3B7E,WAAY,CAACwE,EAAaC,KACtBrH,OAAOC,cAAc,IAAIC,YAAY,yBAGjD,CASA,GAAAa,CAAI2G,EAA+BF,GAC/BX,OAAOU,oBAAsBG,IAA0BpL,EAA4B,UAAY,SAC/FuK,OAAOY,oBAAsBD,GAAU,KACvC,MAAMG,EAAUlL,OAAOoC,SAASiG,eAAe,kCACzC3B,EAAcJ,4BAA4B2E,GAC5CF,GACAG,EAAQC,aAAa,SAAUJ,GAEnCE,EAAwBzD,iBAAiByD,EAAuBvE,GAChEwE,EAAQC,aAAa,iBAAkB,QACvCD,EAAQC,aAAa,wBAAyBF,GAC9CC,EAAQE,OACZ,CASA,IAAAC,CAAKJ,GACD,GAAIlE,eAMA,YALArD,OAAOC,MAAM,CACTiF,MAAO,QACPhF,QAAS,+DACT1J,KAAM,YAId,MAAMwM,EAAcJ,4BAA4B2E,GAChD,GAA2B,IAAvBvE,EAAYtS,OAMZ,YALAsP,OAAOC,MAAM,CACTiF,MAAO,OACPhF,QAAS,6BACT1J,KAAM,WAId,MAAMoR,EAAuB7E,2BAA2BC,GACxD,GAAoC,IAAhC4E,EAAqBlX,OAMrB,YALAsP,OAAOC,MAAM,CACTiF,MAAO,QACPhF,QAAS,wEACT1J,KAAM,YAId,IAAK4M,cAAc,OAASwE,EAAqBvG,KAAKiC,iBAMlD,YALAtD,OAAOC,MAAM,CACTiF,MAAO,QACPhF,QAAS,sDACT1J,KAAM,YAOd,IAAI8N,sBAAsBsD,EAHT,EAAGlL,cAAaC,aAAYC,cACzC4B,qBAAqB/B,mBAAmBC,EAAaC,EAAYC,IAGzE,CASA,MAAA9J,CAAOyU,GACH,IAAKnE,cAAc,OAASA,cAAc,KAMtC,YALApD,OAAOC,MAAM,CACTiF,MAAO,QACPhF,QAAS,mDACT1J,KAAM,YAId,MAAMwM,EAAcJ,4BAA4B2E,GAChD,GAA2B,IAAvBvE,EAAYtS,OAMZ,YALAsP,OAAOC,MAAM,CACTiF,MAAO,OACPhF,QAAS,6BACT1J,KAAM,WAId,MAAMsL,EAAUtD,qBAKhB,IAAI8F,sBAAsBtB,EAJT,EAAGZ,kBAChB,MAAMlF,EAAQgG,yBAA0BjG,GAAQA,EAAiB,cAAMmF,GACvEN,EAAQ/E,oBAAoB,CAACG,KAGrC,CAQO,eAAO4J,CAASnK,GACnB,GAAI0G,eAMA,YALArD,OAAOC,MAAM,CACTiF,MAAO,QACPhF,QAAS,sEACT1J,KAAM,YAId,MAAM0G,EAAQgG,yBAA0BjG,GAAQA,EAAgB,aAAMzB,OAAOmB,IACzEO,GAAS,GACTsB,qBAAqB3B,eAAe,CAACK,GAE7C,CAUA,IAAA2K,CAAKN,GACD,GAAIlE,eAMA,YALArD,OAAOC,MAAM,CACTiF,MAAO,QACPhF,QAAS,2DACT1J,KAAM,YAId,MACMsR,EAAsB/E,2BADLH,4BAA4B2E,IACoB/T,OAAO+P,mBAC9E,GAAmC,IAA/BuE,EAAoBpX,OAMpB,YALAsP,OAAOC,MAAM,CACTiF,MAAO,QACPhF,QAAS,sCACT1J,KAAM,YAId,MAAMsL,EAAUtD,qBAOhB,IAAI8F,sBAAsBwD,EANT,EAAG1F,kBAChB,MAAMlF,EAAQgG,yBAA0BjG,GAAQA,EAAiB,cAAMmF,GACnElF,GAAS,GACT4E,EAAQ9E,WAAW8E,EAAQxD,YAAYpB,GAAQA,IAI3D,CAMO,wBAAOV,GACV,OAAOgC,qBAAqBhC,mBAChC,CAUO,mBAAOuL,CAAaC,EAAYC,EAAkBzR,GACrD,MAAMkK,EAAOlK,EAAO,IAAI0R,KAAK,CAACF,GAAO,CAAExR,SAAUwR,EAC3CvS,EAAMD,IAAI2S,gBAAgBzH,GAC1BtR,EAAIsP,SAAS0J,cAAc,KACjChZ,EAAEiZ,KAAO5S,EACTrG,EAAE0X,SAAWmB,EACb7Y,EAAEsY,QACFlS,IAAI8S,gBAAgB7S,EACxB,CAWO,iBAAO8S,CAAWP,EAAY5F,EAAqB5L,GAGtD,GAFAkQ,OAAOU,oBAAsB,YAC7BV,OAAOY,oBAAsB,OACvBU,aAAgBE,OAAuB,IAAdF,EAAKvG,KAMhC,YALAzB,OAAOC,MAAM,CACTiF,MAAO,OACPhF,QAAS,0BACT1J,KAAM,WAId,MAAMgS,EAAWhS,GAAQwR,EAAKxR,KAC9B,IAAKgS,EAMD,YALAxI,OAAOC,MAAM,CACTiF,MAAO,OACPhF,QAAS,8BACT1J,KAAM,WAId,IAAK8F,SAAWA,OAAOoC,SAMnB,YALAsB,OAAOC,MAAM,CACTiF,MAAO,OACPhF,QAAS,2CACT1J,KAAM,WAId,MAAMiS,EAAYnM,OAAOoC,SAASiG,eAAe,kCACjD,IAAK8D,EAMD,YALAzI,OAAOC,MAAM,CACTiF,MAAO,OACPhF,QAAS,8CACT1J,KAAM,WAId,MAAMkS,EAAkBlF,uBAAuBpB,GACzC1B,EAAO,IAAIiI,KAAK,CAACX,GAAOU,EAAiB,CAAElS,KAAMgS,IACjDI,EAAK,IAAIC,aACfD,EAAGE,MAAMlI,IAAIF,GACb+H,EAAUrI,MAAQwI,EAAGxI,MACrBqI,EAAU3I,cAAc,IAAIiJ,MAAM,UACtC,QChTSC,kBACQxE,MACApE,MACA6I,UAEjB,WAAA/X,CAAYkP,EAAiB6I,GACzB3X,KAAK8O,MAAQ2G,MAAMmC,KAAK9I,GACxB9O,KAAK2X,UAAYA,EAEjB,MAAME,EAAO7X,KAAK8O,MACbgJ,IACG,CAACzV,EAAGlE,IAAM,iPAE+H4Z,uBAAuB1V,EAAEkN,UAAUyI,aAAa3V,EAAEkN,kLAIzKpR,kCACL4Z,uBAAuB7F,uBAAuB7P,EAAEkN,uFAKhE0I,KAAK,IAaJC,EAAM,CACRtE,MAAO,8BACPgB,QAbY,wZAQNiD,wBAMNtH,GAAI,uBACJJ,KAAM,SACN0E,YAAY,EACZC,YAAY,EACZC,cAAe,GACfC,cAAe,GACfC,WAAW,EACXT,QAAS,CACL,CAAE2D,MAAO,WAAYC,UAAW,cAAeC,WAAW,GAC1D,CAAEF,MAAO,YAAaC,UAAW,cAAepK,KAAM,4BAI9DhO,KAAKkT,MAAQxE,OAAOwE,MAAMgF,EAAK,QAC/BlY,KAAKwT,YACT,CAEQ,UAAAA,GAEJpG,SAASkI,iBAAiB,SAAUtV,KAAKsY,oBAGzClL,SACKmL,cAAc,6BACbjD,iBAAiB,QAAS,IAAMtV,KAAKwY,UAC/C,CAEQF,mBAAsB5a,IAC1B,MAAM+a,EAAS/a,EAAE+a,OACjB,GAAkB,4BAAdA,EAAOlI,GAAkC,OAC9BnD,SAASsL,iBAAmC,yBACpD5O,QAAQ,CAACqI,EAAOhU,KACnBgU,EAAMwG,SAAWF,EAAOG,QACpBH,EAAOG,UACPzG,EAAM0G,MAAQ3G,uBAAuBlS,KAAK8O,MAAM3Q,IAAIoR,MAAQ,QAKhE,OAAAiJ,GACJ,MAAMM,EAAS1L,SAASsL,iBAAmC,yBACrDK,EAA2B/Y,KAAK8O,MAAMgJ,IAAI,CAAC1I,EAAMjR,KAAC,CACpDiR,OACAG,KAAM2C,wBAAwB4G,EAAO3a,IAAI0a,OAASzJ,EAAKG,MAAM8C,WAGjEjF,SAAS4L,oBAAoB,SAAUhZ,KAAKsY,oBAC5CtY,KAAKkT,OAAO1R,WACZxB,KAAK2X,UAAUoB,EACnB,EAIJ,SAASf,aAAaiB,GAClB,OAAOA,EACFzH,QAAQ,KAAM,SACdA,QAAQ,KAAM,QACdA,QAAQ,KAAM,OACvB,CAGA,SAASuG,uBAAuBkB,GAC5B,OAAOjB,aAAaiB,GAAMzH,QAAQ,KAAM,SAC5C,CCnDA,IAAI0H,QAMSC,uBACD5Z,uBAAkC,EAM1C,aAAO6Z,GACH,QAASD,uBAAuBE,gBACpC,CAOQ,qBAAOA,GACX,MAAMC,EAAMlE,OAAOlK,oBAAoBqO,KAClCzb,GAAMA,EAAEgT,cAAgBhG,GAE7B,OAAOwO,GAAKjO,WAAaiO,OAAMtP,CACnC,CAUA,iBAAawP,CAAKC,GAAQ,GACtB,IAAKA,QAA0BzP,IAAjBkP,EAA4B,OAAOA,EAEjD,MAAMnN,EAAaoN,uBAAuBE,iBAC1C,IAAKtN,EAED,OADAmN,EAAe,KACR,KAIX,MAAM/U,EAAM,wCAAwC4H,EAAWV,oBACzD7B,QAAiB5E,MAAMT,EAAK,CAAEuV,YAAa,YACjD,IAAKlQ,EAASvE,GACV,MAAM,IAAIhF,MAAM,qCAAqCuJ,EAASmQ,UAGlE,MAAMC,QAAqBpQ,EAASqQ,OAEpC,OADAX,EAAeC,uBAAuBW,gBAAgBF,GAC/CV,CACX,CAaA,WAAOa,CAAKC,GACR,MAAMC,EAA8B,IAC7BD,EACHE,WAAW,IAAI7Y,MAAO8Y,eAI1BjB,EAAee,EAGf,MAAMG,EAAMlN,qBACZ,IAAKkN,EAAI9N,uBAAwB,OAIjC,MAAM8G,EAAW+F,uBAAuBE,iBACpCjG,GACAgH,EAAItO,uBAAuBsH,GAG/B,MAAMyG,EAAOQ,KAAKC,UAAUL,EAAS,KAAM,GACrCvD,EAAO,IAAIE,KAAK,CAACiD,GAAO,CAAE3U,KAAM,qBACtCkQ,OAAO6B,WAAWP,EAAM5L,EAA0B,mBACtD,CAMQ,sBAAOgP,CAAgBF,GAC3B,GAAmB,iBAARA,GAA4B,OAARA,EAC3B,OAAOT,uBAAuBoB,QAGlC,MAAM7Y,EAAOkY,EAMb,MAAO,CACHtO,QAAS6N,uBAAuBqB,gBAChCC,QAAS/Y,EAAK+Y,SAAW,CAAA,EACzB/I,YAAahQ,EAAKgQ,aAAe,CAAA,EACjCwI,UAAWxY,EAAKwY,YAAa,IAAI7Y,MAAO8Y,cAEhD,CAGA,YAAOI,GACH,MAAO,CACHjP,QAAS6N,uBAAuBqB,gBAChCC,QAAS,CAAA,EACT/I,YAAa,CAAA,EACbwI,WAAW,IAAI7Y,MAAO8Y,cAE9B,EC1KJ,MAAMO,EAAe,oBAEfC,EAAa,qBAoCbC,EAAQ,83BAqBRC,EAAwB,6HAG1BD,kqCAiCEE,EAAwB,6HAG1BF,wkFAiEEG,EAAe,cACVJ,otBAwBEK,iBACDzb,gBACAA,eACAA,sBAAuC,KACvCA,sBAA+D,IAAI+G,IAE3E,WAAA1G,GACIob,iBAAiBC,OACrB,CAQO,kBAAOpb,CAAY8G,GAStB,OARKqU,iBAAiBlb,WAClBkb,iBAAiBrU,QAAUA,EACN,iBAAjBA,EAAQuU,OACRF,iBAAiBG,eAAiB/F,OAAOvV,eAE7Cmb,iBAAiBlb,SAAW,IAAIkb,iBAC3BA,iBAAiBI,uBAEnBJ,iBAAiBlb,QAC5B,CAQO,qBAAOub,CAAeC,GACc,iBAAnCN,iBAAiBrU,SAASuU,OAC9BF,iBAAiBO,eAAerc,IAAIoc,EAAaxK,YAAYS,cAAe+J,GACvEN,iBAAiBQ,kBAC1B,CAEQ,gCAAOC,CAA0B1P,GACrC,MAAM2P,EAAO3P,EAAW+E,YAAYU,QAAQ,SAAU,IAAID,cAC1D,OAAOyJ,iBAAiBO,eAAera,IAAIwa,EAC/C,CAEQ,YAAOT,GACX,MAAMzK,EAAUtD,qBAEhBsD,EAAQ9C,sBAER,MAAMiO,EAAkBnL,EAAQrD,eAAekG,eAAe,+BAC1DsI,IAAiBA,EAAgBC,MAAMC,QAAU,QAErD,MAAMC,EAAkBtL,EAAQrD,eAAekG,eAAe,eAC9D,GAAIyI,EAAiB,CACjB,GAAuC,iBAAnCd,iBAAiBrU,SAASuU,KAAyB,CACnD,MAAMa,EAAiBvL,EAAQrD,eAAe2J,cAAc,OAC5DiF,EAAeC,UAAYjB,EAC3Be,EAAgBG,YAAYF,EAAeG,kBAC/C,CACA,MAAMC,EAAY3L,EAAQrD,eAAe2J,cAAc,OACvDqF,EAAU5L,GAAKmK,EACfoB,EAAgBG,YAAYE,EAChC,CAkEA,GAhEAnB,iBAAiBvN,SAGjB+C,EAAQrD,eAAekG,eAAeqH,IAAepF,iBAAiB,QAAU8G,IAC5E,MAAM3D,EAAS2D,EAAM3D,OAEf4D,EAAW5D,EAAO6D,QAAQ,0BAChC,GAAID,EAAU,CACVD,EAAMG,iBACN,MAAMnR,EAAciR,EAASG,aAAa,sBAAwB,GAC5DnR,EAAaoR,OAAOJ,EAASG,aAAa,qBAC1ClR,EAAUmR,OAAOJ,EAASG,aAAa,iBAE7C,YADAhM,EAAQrF,mBAAmBC,EAAaC,EAAYC,EAExD,CAEA,MAAMoR,EAAejE,EAAO6D,QAAQ,8BACpC,GAAII,EAAc,CACdN,EAAMG,iBACN,MAAMlR,EAAaoR,OAAOC,EAAaF,aAAa,qBAEpD,YADAjO,OAAOC,cAAc,IAAIC,YAAY,4BAA6B,CAAE8G,OAAQ,CAAElK,gBAElF,CAEA,MAAMsR,EAAKlE,EAAO6D,QAAQ,iBAC1B,GAAIK,EAAI,CACJ,MAAMC,EAASD,EAAGH,aAAa,aACzBK,EAA8C,QAAlCF,EAAGH,aAAa,cAGlC,OAFAxB,iBAAiB8B,OAAOF,EAAQC,QAChCF,EAAGxG,aAAa,aAAc0G,EAAY,OAAS,MAEvD,CAEA,GAAuC,iBAAnC7B,iBAAiBrU,SAASuU,KAAyB,OAEvD,MAAM6B,EAAWtE,EAAO6D,QAAQ,0BAChC,GAAIS,EAAU,CACVX,EAAMG,iBACN,MAAMlR,EAAaoR,OAAOM,EAASP,aAAa,qBAC1CzQ,EAAaqJ,OAAOlK,oBAAoBqO,KAAMzb,GAAMA,EAAEuN,aAAeA,GAE3E,YADIU,GAAYiP,iBAAiBG,gBAAgB5E,KAAKxK,EAAW+E,aAErE,CAEA,MAAMkM,EAAgBvE,EAAO6D,QAAQ,+BACrC,GAAIU,EAAe,CACfZ,EAAMG,iBACN,MAAMU,EAAiBD,EAAcR,aAAa,4BAA8B,GAC1EU,EAAYF,EAAcR,aAAa,uBAAyB,KAEtE,YADAxB,iBAAiBG,gBAAgB7L,IAAI2N,EAAgBC,EAEzD,CAEA,MAAMC,EAAa1E,EAAO6D,QAAQ,4BAClC,GAAIa,EAAY,CACZf,EAAMG,iBACN,MAAMlR,EAAaoR,OAAOU,EAAWX,aAAa,qBAC5CzQ,EAAaqJ,OAAOlK,oBAAoBqO,KAAMzb,GAAMA,EAAEuN,aAAeA,GAE3E,YADIU,GAAYiP,iBAAiBG,gBAAgB3Z,OAAOuK,EAAW+E,aAEvE,IAImC,iBAAnCkK,iBAAiBrU,SAASuU,KAAyB,CACnD1K,EAAQrD,eAAekG,eAAesH,IAAarF,iBAAiB,QAAU8G,IAC1E,MAAM3D,EAAS2D,EAAM3D,OAGrB,GADiBA,EAAO6D,QAAQ,uBAG5B,OADAF,EAAMG,iBACDzK,cAAc,UAInBkJ,iBAAiBG,gBAAgB7L,IAAIzE,EAA2BmQ,iBAAiBrU,QAAQoP,QAAU,WAH/FrH,OAAOC,MAAM,CAAEiF,MAAO,QAAShF,QAAS,oDAAqD1J,KAAM,YAQ3G,GADiBuT,EAAO6D,QAAQ,uBAClB,CAEV,GADAF,EAAMG,kBACDzK,cAAc,KAEf,YADApD,OAAOC,MAAM,CAAEiF,MAAO,QAAShF,QAAS,oDAAqD1J,KAAM,YAGvG8V,iBAAiBoC,mBAAmBpC,iBAAiBrU,QAAQoP,QAAU,KAC3E,IAIJ,MAAMoG,EAAY3L,EAAQrD,eAAekG,eAAeqH,GACxDyB,EAAU7G,iBAAiB,WAAa5X,IACpCA,EAAE6e,iBACF7e,EAAE2f,kBACFlB,EAAUmB,UAAUhO,IAAI,eAE5B6M,EAAU7G,iBAAiB,YAAa,IAAM6G,EAAUmB,UAAU9b,OAAO,cACzE2a,EAAU7G,iBAAiB,OAAS5X,IAChCA,EAAE6e,iBACF7e,EAAE2f,kBACFlB,EAAUmB,UAAU9b,OAAO,aAC3B,MAAMsN,EAAQpR,EAAE6f,cAAczO,MACzBA,GAA0B,IAAjBA,EAAM1P,SACf0S,cAAc,KAInB,IAAI4F,kBAAkB5I,EAAQiK,IAC1BA,EAAQjP,QAAQ,EAAGsF,OAAMG,WACrB6F,OAAO6B,WAAW7H,EAAMG,EAAMH,EAAKlK,UALvCwJ,OAAOC,MAAM,CAAEiF,MAAO,QAAShF,QAAS,oDAAqD1J,KAAM,cAS/G,CAEAqJ,OAAO+G,iBAAiB,qBAAsB,IAAM0F,iBAAiBvN,UAErEc,OAAO+G,iBAAiB,uBAAwB3R,MAAOjG,IACnD,MAAM6X,EAAU7X,EAIZ6X,OAIJ,GAFAyF,iBAAiBvN,UAEZ8H,GAAQM,QAA6C,iBAAnCmF,iBAAiBrU,SAASuU,KAAyB,OAC1E,IAAKF,iBAAiBG,eAAgB,OAEtC,MAAMqC,EAAiBpI,OAAOlK,oBAAoBhJ,OAAQpE,IAAOsT,qBAAqBtT,IAChF2f,EAAgBD,EAAejE,KAChCzb,GAAMA,EAAEgT,aAAaU,QAAQ,SAAU,MAAQ+D,EAAOzE,aAAaU,QAAQ,SAAU,KAG1F,IAAKiM,IAAkBA,EAAcpS,WAAY,OAEjD,MAAM2O,QAAkBb,uBAAuBK,QAAWL,uBAAuBoB,QAC3EmD,EAA2B,CAC7BrS,WAAYoS,EAAcpS,WAC1BwK,OAAQN,EAAOM,OACf8H,kBAAqC,WAAlBpI,EAAOM,OAAsBN,EAAOzE,iBAAc9G,EACrE+L,OAAQR,EAAOQ,QAAU,KACzB6H,iBAAkB1Q,qBAAqBP,sBACvCkR,YAAY,IAAIxc,MAAO8Y,eAG3BhB,uBAAuBY,KACnB,IACOC,EACHtI,YAAa,IACNsI,EAAStI,YACZ,CAACxH,OAAOuT,EAAcpS,aAAcqS,MAKxD,CAEQ,aAAOjQ,GACX,MAAM+C,EAAUtD,qBACViP,EAAY3L,EAAQrD,eAAekG,eAAeqH,GACxD,IAAKyB,EAAW,OAEhB,MAAM2B,EAAmD,iBAAnC9C,iBAAiBrU,SAASuU,KAC1C5N,EAAWwQ,EAAgBhD,EAAwBD,EAEnDnJ,EAAc0D,OAAOlK,oBACtBhJ,OAAQpE,IAAOsT,qBAAqBtT,IACpCga,IAAK/L,IACF,MAAMqG,ENhWhB,SAAuCrG,GACzC,MAAO,IACAA,EACH+E,YAAa/E,EAAW+E,YAAYU,QAAQ,KAAM,SAASA,QAAQ,KAAM,QAAQA,QAAQ,KAAM,QAAQA,QAAQ,KAAM,UAE7H,CM2VkCuM,CAA6BhS,GAC/C,IAAK+R,EACD,MAAO,IAAK1L,EAAW4L,gBAAiBjM,gBAE5C,MAAMkM,EAAMjD,iBAAiBS,0BAA0B1P,GACvD,MAAO,IACAqG,EACH8L,YAAanM,iBAAmBD,cAAc,MAAQE,gBAAgBjG,IACtEoS,YAAapS,EAAW4F,WAAaM,kBAAkBlG,GACvDqS,kBAAmBH,GAAOnM,cAAc,KACxCkM,gBAAiBjM,eACjBsM,aAAcvM,cAAc,MAAQA,cAAc,KAClD6L,kBAAmBM,GAAKnN,aAAe,GACvCwN,aAAcL,GAAKlI,QAAU,MAIzCoG,EAAUH,UAAYxL,EAAQnD,eAAeC,EAAU,CACnDoE,cACA6M,mBTvc+B,KSycvC,CAEQ,gCAAanD,GACjB,MAAMpB,QAAiBb,uBAAuBK,OAC9C,GAAKQ,EAEL,IAAK,MAAOlJ,EAAa4M,KAAW9Z,OAAOmV,QAAQiB,EAASS,SACnDO,iBAAiBO,eAAenT,IAAI0I,IACrCkK,iBAAiBO,eAAerc,IAAI4R,EAAa,CAC7CA,cACAiF,OAAQ2H,EAAO3H,QAI/B,CAEQ,4BAAayF,GACjB,IAAKR,iBAAiBG,eAAgB,OAEtC,MAAMqD,QAAiBrF,uBAAuBK,QAAWL,uBAAuBoB,QAC1EE,EAAqD,CAAA,EAC3D,IAAK,MAAO9Y,EAAK8c,KAAQzD,iBAAiBO,eAAexC,UACrD0B,EAAQ9Y,GAAO,CAAEoU,OAAQ0I,EAAI1I,QAGjCoD,uBAAuBY,KAAK,IAAKyE,EAAS/D,WAC9C,CAEQ,yBAAO2C,CAAmBrH,GAC9BrH,OAAOwE,MACH,CACIU,MAAO,gBACPgB,QAAS,gQACTrE,GAAI,oBACJJ,KAAM,QACN0E,YAAY,EACZC,YAAY,EACZC,cAAe,GACfC,cAAe,GACfC,WAAW,EACXT,QAAS,CACL,CAAE2D,MAAO,WAAYC,UAAW,cAAeC,WAAW,GAC1D,CAAEF,MAAO,SAAUC,UAAW,cAAepK,KAAM,8BAG3D,QAGJZ,SAASmL,cAAc,+BAA+BjD,iBAAiB,QAAS,KAC5E,MAAMnD,EAAQ/E,SAASiG,eAAe,qBAChCqL,EAAUvM,GAAO0G,OAAOxG,QAAU,GACxC,IAAKqM,EAAS,OACd,MAAMC,EAAWzM,uBAAuBwM,GACxC1D,iBAAiBG,gBAAgB7L,IAAIqP,EAAU5I,IAEvD,CAEQ,cAAO6I,GACX,OAAOnJ,MAAMmC,KACT1K,qBAAqBC,eAAeuL,iBAAiB,IAAIgC,oBAEjE,CAEQ,eAAOmE,CAAShH,GACpB,MAAMiH,EAAQ5R,qBAAqBC,eAAeoL,cAC9C,IAAImC,iBAEHoE,GACLjH,EAAK/N,QAAS6B,GAAQmT,EAAM7C,YAAYtQ,GAC5C,CAEQ,aAAOmR,CAAOF,EAAoBC,GACtC,MAAMhF,EAAOmD,iBAAiB4D,UAC9B/G,EAAK3I,KAAK,CAACpR,EAAG6M,KACV,MAAMoU,EAAS/D,iBAAiBgE,aAAalhB,EAAG8e,GAC1CqC,EAASjE,iBAAiBgE,aAAarU,EAAGiS,GAChD,OAAImC,GAAUE,EACHpC,EAAYkC,EAAOG,cAAcD,GAAUA,EAAOC,cAAcH,GAEpE,IAEX/D,iBAAiB6D,SAAShH,EAC9B,CAEQ,mBAAOmH,CAAarT,EAA0BiR,GAClD,OAAQA,GACJ,IAAK,QACD,OAAOjR,EAAI4M,cAAc,2BAA2B+D,QAAQ,OAAO6C,aAAa9M,OACpF,IAAK,OACD,OAAO1G,EAAI4M,cAAc,oBAAoB4G,aAAa9M,OAC9D,IAAK,OACD,OAAO1G,EAAI4M,cAAc,oBAAoB4G,aAAa9M,OAC9D,IAAK,WACD,OAAO1G,EAAI4M,cAAc,oBAAoB4G,aAAa9M,OAEtE,EC5hBE,MAAO+M,qBAAqBC,YAM9BvO,YAMAiF,OAEAuJ,YAA6B,KAC7BC,aAA8B,KAC9BC,aAA8B,KAC9BC,eAAgC,KAExBC,cAA+B,KACnC,MAAMC,EAAS3f,KAAK4f,YAAYrH,cAAc,oBAC1CoH,IACAA,EAAO/D,MAAMiE,MAAQ,qBACrBF,EAAO/D,MAAMkE,gBAAkB,qBAI/BC,YAA6B,KACjC,MAAMJ,EAAS3f,KAAK4f,YAAYrH,cAAc,oBAC1CoH,IACAA,EAAO/D,MAAMiE,MAAQ,qBACrBF,EAAO/D,MAAMkE,gBAAkB,qBAI/BE,cAA+B,KACnC,MAAML,EAAS3f,KAAK4f,YAAYrH,cAAc,oBAC1CoH,IACAA,EAAO/D,MAAMiE,MAAQ,kBACrBF,EAAO/D,MAAMkE,gBAAkB,uBAIvC,WAAAlgB,GACIqgB,QACA,MAAMC,EAASlgB,KAAKmgB,aAAa,CAAEjF,KAAM,SACnCU,EAAQxO,SAAS0J,cAAc,SACrC8E,EAAMI,UC/DC,u0CDgEP,MAAM1O,EAAWF,SAAS0J,cAAc,YACxCxJ,EAAS0O,60LACTkE,EAAOjE,YAAYL,GAEnBsE,EAAOjE,YAAY3O,EAASsH,QAAQwL,WAAU,IAC9CpgB,KAAK8Q,YAAc,GACnB9Q,KAAK+V,OAAS,IAClB,CAEA,6BAAWsK,GACP,MAAO,CAAC,cAAe,SAAU,cAAe,eAAgB,eAAgB,iBACpF,CAEA,wBAAAC,CAAyB/Q,EAAcgR,EAAmBC,GACtD,GAAKxgB,KAAKygB,YAAV,CACA,OAAQlR,GACJ,IAAK,cACDvP,KAAK8Q,YAAc0P,GAAY,GAC/B,MACJ,IAAK,SACDxgB,KAAK+V,OAASyK,EACd,MACJ,IAAK,cACDxgB,KAAKsf,YAAckB,EACnB,MACJ,IAAK,eACDxgB,KAAKuf,aAAeiB,EACpB,MACJ,IAAK,eACDxgB,KAAKwf,aAAegB,GAAY,OAChC,MACJ,IAAK,iBACDxgB,KAAKyf,eAAiBe,EAG9BxgB,KAAK0gB,gBArBkB,CAsB3B,CAEA,oBAAAC,GACI3V,OAAOgO,oBAAoB,uBAAwBhZ,KAAK0f,eACxD1U,OAAOgO,oBAAoB,qBAAsBhZ,KAAK+f,aACtD/U,OAAOgO,oBAAoB,qBAAsBhZ,KAAKggB,cAC1D,CAKA,iBAAAY,GAII5gB,KAAKsf,YAActf,KAAKwc,aAAa,eACrCxc,KAAKuf,aAAevf,KAAKwc,aAAa,gBACtCxc,KAAKwf,aAAexf,KAAKwc,aAAa,iBAAmB,OACzDxc,KAAKyf,eAAiBzf,KAAKwc,aAAa,kBACxCxc,KAAK0gB,iBAIL1gB,KAAK+V,OAAS/V,KAAKwc,aAAa,UAChCxc,KAAK8Q,YAAc9Q,KAAKwc,aAAa,gBAAkB,GACvD,MAAMzQ,EAAaqJ,OAAOvV,cAC1BG,KAAK6gB,UAAU9U,GACf/L,KAAK8gB,WAAW/U,GAChB/L,KAAK+gB,WAAWhV,GAChB/L,KAAKghB,aAAajV,GAClBf,OAAOsK,iBAAiB,uBAAwBtV,KAAK0f,eACrD1U,OAAOsK,iBAAiB,qBAAsBtV,KAAK+f,aACnD/U,OAAOsK,iBAAiB,qBAAsBtV,KAAKggB,eACnDhF,iBAAiBK,eAAe,CAAEvK,YAAa9Q,KAAK8Q,YAAaiF,OAAQ/V,KAAK+V,QAAU,MAC5F,CAEQ,cAAA2K,GACqB,SAArB1gB,KAAKsf,aACLtf,KAAK4f,YAAYrH,cAAc,YAAY0I,eAAe3D,UAAU9b,OAAO,mBAErD,SAAtBxB,KAAKuf,cACLvf,KAAK4f,YAAYrH,cAAc,UAAU0I,eAAe3D,UAAU9b,OAAO,mBAEnD,SAAtBxB,KAAKwf,cACLxf,KAAK4f,YAAYrH,cAAc,UAAU0I,eAAe3D,UAAU9b,OAAO,mBAEjD,SAAxBxB,KAAKyf,gBACLzf,KAAK4f,YAAYrH,cAAc,YAAY0I,eAAe3D,UAAU9b,OAAO,kBAEnF,CAEQ,SAAAqf,CAAU9U,GACd/L,KAAK4f,YAAYrH,cAAc,YAAYjD,iBAAiB,QAAU5X,IAClEA,EAAE6e,iBACGvc,KAAK8Q,YAGN/E,EAAWuD,IAAItP,KAAK8Q,YAAa9Q,KAAK+V,QAFtC/V,KAAKkhB,aAKjB,CACQ,UAAAJ,CAAW/U,GACf/L,KAAK4f,YAAYrH,cAAc,UAAUjD,iBAAiB,QAAU5X,IAChEA,EAAE6e,iBACFxQ,EAAWsK,KAAMrW,KAAK8Q,YAA0C9Q,KAAK8Q,YAAjCjG,IAE5C,CACQ,UAAAkW,CAAWhV,GACf/L,KAAK4f,YAAYrH,cAAc,UAAUjD,iBAAiB,QAAU5X,IAChEA,EAAE6e,iBACFxQ,EAAWwK,KAAMvW,KAAK8Q,YAA0C9Q,KAAK8Q,YAAjCjG,IAE5C,CAEQ,YAAAmW,CAAajV,GACjB/L,KAAK4f,YAAYrH,cAAc,YAAYjD,iBAAiB,QAAU5X,IAClEA,EAAE6e,iBACFxQ,EAAWvK,OAAQxB,KAAK8Q,YAA0C9Q,KAAK8Q,YAAjCjG,IAE9C,CAEQ,SAAAqW,GACJ,MAYMC,EAAcnW,OAAO0D,OAAOwE,MAC9B,CACIU,MAAO,+BACPgB,QAfS,+jBAgBTrE,GAAI,cACJsE,YAAY,EACZC,YAAY,EACZN,QAAS,CACL,CACI2D,MAAO,SACPnK,KAAM,mBAEV,CACImK,MAAO,WACPnK,KAAM,sBAGd+G,cAAe,GACfC,cAAe,GACf7E,KAAM,QACN8E,WAAW,GAEf,CAACmM,EAAKxL,KACGwL,IACDpW,OAAO0D,OAAO2S,aACV,sBACA,CACIxL,OAAQ,CAACyL,EAAWC,KAChB,MAAMC,aPjLlC,MACMC,EADcnQ,4BAA4BzG,GACnBiN,IAAKha,GAAMA,EAAEgT,YAAYU,QAAQ,YAAa,IAAIA,QAAQ,OAAQ,KAC/F,MAAO,IAAI,IAAIkQ,IAAID,GACvB,CO8KgDE,GACXzf,OAAQ8N,GAAMA,EAAEuB,cAAcjD,SAASgT,EAAE/P,gBACzCuG,IAAKhH,KAAmBA,iBAC7ByQ,EAAGC,IAEPI,WAAW,EACXC,WAAY,cACZC,SAAU,WACV5c,KAAM,gBAEV,QAGJ8F,OAAOoC,SAASmL,cAAc,sBAAsBjD,iBAAiB,QAAS,KAC1E,MAAMuD,MAAEA,GAAU7N,OAAOoC,SAASmL,cAAc,uBAChD,IAAKM,EAMD,YALAnK,OAAOC,MAAM,CACTiF,MAAO,OACPhF,QAAS,+BACT1J,KAAM,WAId,MAAM4L,EAAc,GAAG+H,EAAMkJ,mBAC7BZ,EAAY3f,SACO4T,OAAOvV,cACfyP,IAAIwB,EAAa9Q,KAAK+V,UAGrC/K,OAAOoC,SAASmL,cAAc,wBAAwBjD,iBAAiB,QAAS,KAC5E6L,EAAY3f,aAKhC,EAGCwgB,eAAe9gB,IAAI,sBACpB8gB,eAAeC,OAAO,oBAAqB7C,oBEhQlC8C,mBACD,qBAAOC,GACO/U,SAASsL,iBAAiB,gBAClC5O,QAASsY,IACfA,EAAM9E,UAAU9b,OAAO,aACvB,MAAM6gB,EAAgBD,EAAM7J,cAAc,iBACtC8J,GACAA,EAAc/E,UAAUhO,IAAI,oBAGxC,CAEA,2BAAOgT,CAAqBC,GACxB,IAAKA,GAA4B,IAAlBA,EAAOnjB,OAClB,MAAM,IAAIa,MAAM,wEAEpBD,KAAKmiB,iBAELI,EAAOzY,QAAQ,EAAGD,QAAO2Y,mBACrB,GAAI3Y,EAAO,CACP,MAAMuY,EAAQvY,EAAMyS,QAAQ,gBAC5B,GAAI8F,EAAO,CACPA,EAAM9E,UAAUhO,IAAI,aACpB,MAAM+S,EAAgBD,EAAM7J,cAAc,iBACtC8J,IACAA,EAAc/E,UAAU9b,OAAO,mBAC/B6gB,EAAclD,YAAcqD,GAGhC,MAAMC,kBAAoB,KACtBL,EAAM9E,UAAU9b,OAAO,aACnB6gB,IACAA,EAAc/E,UAAUhO,IAAI,mBAC5B+S,EAAclD,YAAc,KAIpCiD,EAAM9M,iBAAiB,QAASmN,kBAAmB,CAAEC,MAAM,IAC3DN,EAAM9M,iBAAiB,UAAWmN,kBAAmB,CAAEC,MAAM,GACjE,CACJ,IAEJ,MAAMC,EAAgBJ,EACjBrgB,OAAO,EAAGsgB,kBAAmBA,GAAgBA,EAAanQ,QAC1DyF,IAAI,EAAG0K,kBAAmBA,EAAahR,QAAQ,KAAM,QAAQA,QAAQ,KAAM,SAEhF,GAA6B,IAAzBmR,EAAcvjB,OACd,MAAM,IAAIa,MAAM,wEAEpB,MAAM2iB,EAAmBD,EAAc1K,KAAK,QAC5C,MAAM,IAAIhY,MAAM,gDAAgD2iB,UACpE,ECxCG,MAAMC,EAAqB,CAC9BC,eAAgB,GAChBC,cAAe,GACfC,cAAe,GACfC,YAAa,GACbC,oBAAqB,ICblBvf,eAAewf,mBAClB,MAAMC,cAAgB,KAClBpjB,KAAKqjB,mBACLrjB,KAAKsjB,uBAKT,IAAK,MAAMC,KAAMV,EAASC,eACtB,IACI,MAAMxiB,EAASijB,IACXjjB,aAAkBF,eACZE,CAEd,CAAE,MAAO5C,GAEL,YADA0lB,eAEJ,CAGJ,MAAMI,EAAsBpW,SAASiG,eAAe,gBAC9CoQ,EAAeD,GAAqB3K,OAAS7Y,KAAK0jB,iBAGxD,SADsB1jB,KAAK2jB,iBAAiB,qBAAsB,CAAC1X,iBAAiBU,sBAAuB8W,IAC3G,CAOA,IAAK,MAAMF,KAAMV,EAASE,cACtB,IACI,MAAMziB,EAASijB,IACXjjB,aAAkBF,eACZE,CAEd,CAAE,MAAO5C,GAEL,YADA0lB,eAEJ,CAEJpjB,KAAK4jB,uBACL5jB,KAAK6jB,aAAY,GAAO,EAhBxB,MAFIT,eAmBR,CC7CA,MAAMU,EAAY,CACdX,wBA+BSY,oBACDxkB,sBAAuB,EACvBA,uBAAwB,EACxBA,uBAAuE,CAAA,EAmB/E,iBAAaykB,CAAKC,EAAU,KACxB,GAAIjkB,KAAKP,cAAe,OACxB,GAAIO,KAAKkkB,eACL,MAAM,IAAIjkB,MAAM,qDAGpBD,KAAKkkB,gBAAiB,EACtB,MAAMC,EAAY9iB,KAAKC,MAEvB,MAAQ0J,OAAOoZ,aAAa,CACxB,GAAI/iB,KAAKC,MAAQ6iB,EAAYF,EAEzB,MADAjkB,KAAKkkB,gBAAiB,EAChB,IAAIjkB,MAAM,mFAEd,IAAIG,QAAS6F,GAAYoe,WAAWpe,EAAS,KACvD,CAEAjG,KAAKkkB,gBAAiB,EACtBlkB,KAAKP,eAAgB,CACzB,CAWA,YAAO6kB,CAAM1T,GACT,IAAK5Q,KAAKP,cACN,MAAM,IAAIQ,MAAM,+DAEpB,IAAK+K,OAAOoZ,YAAa,OAEzB,MAAMb,EAAKO,EAAUlT,GACrB,IAAK2S,EACD,MAAM,IAAItjB,MAAM,mCAAmC2Q,8CAElD5Q,KAAKukB,gBAAgB3T,KACtB5Q,KAAKukB,gBAAgB3T,GAAQ5F,OAAOoZ,YAAYxT,IAEpD5F,OAAOoZ,YAAYxT,GAAQ2S,EAAGvV,KAAKhD,OAAOoZ,YAC9C,CAQA,gBAAOI,CAAUC,GACb,IAAKzkB,KAAKP,cACN,MAAM,IAAIQ,MAAM,+DAEpBwkB,EAAM3a,QAAS8G,GAAS5Q,KAAKskB,MAAM1T,GACvC,CAMA,eAAO8T,GACH,IAAK1kB,KAAKP,cACN,MAAM,IAAIQ,MAAM,+DAEhB+K,OAAOoZ,aACPxgB,OAAO+gB,KAAKb,GAAWha,QAAS8G,IAC5B5Q,KAAKskB,MAAM1T,IAGvB,CAeA,cAAOgU,GACE5Z,OAAOoZ,cAEZxgB,OAAOmV,QAAQ/Y,KAAKukB,iBAAiBza,QAAQ,EAAE8G,EAAMiU,MACjD,MAAMC,EAAIlU,OACS5G,IAAf6a,EACE7Z,OAAOoZ,YAAoBU,GAAKD,SAE1B7Z,OAAOoZ,YAAoBU,KAI3C9kB,KAAKukB,gBAAkB,CAAA,EACvBvkB,KAAKP,eAAgB,EACrBO,KAAKkkB,gBAAiB,EACtBrB,EAASC,eAAe1jB,OAAS,EACjCyjB,EAASE,cAAc3jB,OAAS,EAChCyjB,EAASG,cAAc5jB,OAAS,EAChCyjB,EAASI,YAAY7jB,OAAS,EAC9ByjB,EAASK,oBAAoB9jB,OAAS,EAC1C,CAQA,eAAO2lB,CAAmCpjB,GACtC,OAAOkhB,EAASlhB,EACpB,CAoBA,wBAAOqjB,CAAkBzB,GACrBV,EAASC,eAAe1b,KAAKmc,EACjC,CAmBA,uBAAO0B,CAAiB1B,GACpBV,EAASE,cAAc3b,KAAKmc,EAChC,CAgBA,uBAAO2B,CAAiB3B,GACpBV,EAASG,cAAc5b,KAAKmc,EAChC,CAgBA,qBAAO4B,CAAe5B,GAClBV,EAASI,YAAY7b,KAAKmc,EAC9B,CAgBA,6BAAO6B,CAAuB7B,GAC1BV,EAASK,oBAAoB9b,KAAKmc,EACtC,EC9QE,SAAU8B,aAAaC,GACzB,OAAOA,EAAI9T,QAAQ,YAAa,CAAC+T,EAAGC,IAAmBA,EAAOzD,cAClE,CAOM,SAAU0D,aAAaH,GACzB,OAAOA,EAAI9T,QAAQ,SAAWgU,GAAW,IAAIA,EAAOjU,gBACxD,OCJamU,kBACT,IAAAlM,CAAQmM,GACJ,MAAMC,EAAS,GAAGD,KACZrlB,EAAkC,CAAA,EAcxC,OAbe8M,SAASsL,iBACpB,gBAAgBkN,sBAA2BA,wBAA6BA,OAErE9b,QAAS6G,IACZ,MAAMkV,EAAUlV,EAAGpB,KACnB,IAAKsW,GAAWA,EAAQvX,SAAS,OAAQ,OACzC,MAAMwX,EAAWT,aAAaQ,EAAQE,MAAMH,EAAOxmB,SAC/CuR,aAAcqV,kBAAgC,aAAZrV,EAAGzL,KACrC5E,EAAOwlB,GAAYnV,EAAGiI,QAEtBtY,EAAOwlB,GAAYnV,EAAGkI,QAGvBvY,CACX,CAEA,SAAA2lB,CAAaC,GACT,MAAMrO,EAAOzK,SAASsL,iBAClB,oBAAoBwN,2EAElB5lB,EAAc,GAiBpB,OAhBAuX,EAAK/N,QAAS6B,IACV,MAAMwa,EAAmC,CAAA,EAC1Bxa,EAAI+M,iBACf,2BAEG5O,QAAS6G,IACZ,IAAKA,EAAGpB,KAAM,OACd,MAAM6W,EAAWzV,EAAGpB,KAAKjB,SAAS,OAASqC,EAAGpB,KAAK+C,UAAU,EAAG3B,EAAGpB,KAAK8W,YAAY,QAAU1V,EAAGpB,KAC7FoB,aAAcqV,kBAAgC,aAAZrV,EAAGzL,KACrCihB,EAAQC,GAAYzV,EAAGiI,QAEvBuN,EAAQC,GAAYzV,EAAGkI,QAG/BvY,EAAO8G,KAAK+e,KAET7lB,CACX,CAEA,IAAAyZ,CAAQ4L,EAAiBjkB,GACrB,MAAMkkB,EAAS,GAAGD,KAClB/hB,OAAOmV,QAAQrX,GAAiCoI,QAAQ,EAAEgc,EAAUjN,MAChE,MAAMgN,EAAU,GAAGD,IAASH,aAAaK,KACnCnV,EAAKvD,SAASmL,cAChB,UAAUsN,OAETlV,IACDA,aAAcqV,kBAAgC,aAAZrV,EAAGzL,KACrCyL,EAAGiI,QAAU0N,QAAQzN,GAErBlI,EAAGkI,MAAQ3O,OAAO2O,GAAS,MAGvC,CAEA,SAAA0N,CAAaL,EAAmBrO,GAE5BzK,SAASsL,iBACL,oBAAoBwN,gBACtBpc,QAAS6B,IACoC,SAAtCA,EAAoBiQ,MAAMC,SAC3BlQ,EAAInK,WAIZqW,EAAK/N,QAASqc,IACV,MAAMK,EAAQC,YAAYP,GAAW,GACrCtiB,OAAOmV,QAAQoN,GAAoCrc,QAAQ,EAAEnI,EAAKkX,MAC9D,MAAMlI,EAAKvD,SAASmL,cAChB,UAAU5W,OAAS6kB,OAElB7V,IACDA,aAAcqV,kBAAgC,aAAZrV,EAAGzL,KACrCyL,EAAGiI,QAAU0N,QAAQzN,GAErBlI,EAAGkI,MAAQ3O,OAAO2O,GAAS,QAI3C,QCxES6N,mBAEQC,MAAQ,IAAIrgB,IACZsgB,OAAS,IAAItgB,IAE9B,IAAAkT,CAAQmM,GACJ,MAAMC,EAAS,GAAGD,KACZrlB,EAAkC,CAAA,EACxC,IAAK,MAAOulB,EAAShN,KAAU7Y,KAAK2mB,MAAM5N,UACtC,GAAI8M,EAAQxU,WAAWuU,GAAS,CAE5BtlB,EADiB+kB,aAAaQ,EAAQE,MAAMH,EAAOxmB,UAChCyZ,CACvB,CAEJ,OAAOvY,CACX,CAEA,SAAA2lB,CAAaC,GACT,OAAQlmB,KAAK4mB,OAAO1lB,IAAIglB,IAAc,EAC1C,CAEA,IAAAnM,CAAQ4L,EAAiBjkB,GACrB,MAAMkkB,EAAS,GAAGD,KAClB/hB,OAAOmV,QAAQrX,GAAiCoI,QAAQ,EAAEgc,EAAUjN,MAChE7Y,KAAK2mB,MAAMznB,IAAI,GAAG0mB,IAASH,aAAaK,KAAajN,IAE7D,CAEA,SAAA0N,CAAaL,EAAmBrO,GAC5B7X,KAAK4mB,OAAO1nB,IAAIgnB,EAAW,IAAIrO,GACnC,CAMA,KAAAgP,GACI7mB,KAAK2mB,MAAM5kB,QACX/B,KAAK4mB,OAAO7kB,OAChB,EClCE,SAAU+kB,WAAcC,GAC1B,MAAMzmB,EAAqB,CAAA,EAC3B,IAAK,MAAM0mB,KAAYpjB,OAAO+gB,KAAKoC,GAA0B,CACzD,MAAMlB,EAAUkB,EAASC,GACzB,IAAKnB,EAAS,SACd,MAAMlV,EAAKvD,SAASmL,cAChB,UAAUsN,OAETlV,IACLrQ,EAAO0mB,GACHrW,aAAcqV,kBAAgC,aAAZrV,EAAGzL,KAAsByL,EAAGiI,QAAUjI,EAAGkI,MAEnF,CACA,OAAOvY,CACX,CCjBM,SAAU2mB,qBAEdC,GAIE,OAAOA,CACX,CCWM,SAAUC,uBACZC,EACAC,GAEA,MAAMtO,EAAUnV,OAAO0jB,OAAOF,GAASllB,OAClCxE,GACqB,OAAlBA,EAAE6pB,aACc,IAAhB7pB,EAAE8pB,WACiB,OAAnB9pB,EAAE+pB,cAGV1O,EAAQ7J,KAAK,CAACpR,EAAG6M,KACb,MAAM+c,EAAY5pB,EAAE2pB,aAA2B9c,EAAE8c,aACjD,OAAiB,IAAbC,EAAuBA,GACnB5pB,EAAE6pB,cAAgB,IAAIzI,cAAcvU,EAAEgd,cAAgB,MAGlE,MAAMC,EAAa,IAAIlG,IACjBphB,EAAmB,GAEzB,IAAK,MAAMunB,KAAS9O,EAAS,CACzB,MAAM+O,EAAST,EAAW9N,KAAMzb,GAAMA,EAAE8O,WAAaib,EAAME,eACvDD,GAAQE,QAAUJ,EAAWxf,IAAI0f,EAAOE,SACxCJ,EAAWtY,IAAIwY,EAAOE,OACtB1nB,EAAO8G,KAAK0gB,EAAOE,OAE3B,CAEA,OAAO1nB,CACX,UAWgB2nB,oBACZC,EACAC,EACAd,GAEA,MAAMS,EAAST,EAAW9N,KAAMzb,GAAMA,EAAE8O,WAAasb,GACrD,OAAKJ,GAAQE,MACN,CACHA,MAAOF,EAAOE,MACdrO,OAA+B,WAAvBwO,EAAkC,UAAY,WAH/B,IAK/B,OCvEaC,cAEYC,SACAC,gBACAlB,QAHrB,WAAAxnB,CACqByoB,EACAC,EACAlB,GAFApnB,KAAAqoB,SAAAA,EACAroB,KAAAsoB,gBAAAA,EACAtoB,KAAAonB,QAAAA,CAClB,CAOH,SAAAmB,CAAUC,GACN,OAAOxoB,KAAKsoB,gBAAgB/O,KAAMnX,GAAMA,EAAEomB,WAAaA,IAAWD,YAAa,CACnF,CAOA,UAAAE,CAAWD,GACP,OAAOxoB,KAAKsoB,gBAAgB/O,KAAMnX,GAAMA,EAAEomB,WAAaA,IAAWC,aAAc,CACpF,CAOA,QAAAC,CAASF,GACL,OAAOxoB,KAAKsoB,gBAAgB/O,KAAMnX,GAAMA,EAAEomB,WAAaA,IAAWE,WAAY,CAClF,CASA,WAAAC,GACI,OAAO3oB,KAAKqoB,SAASzb,QACzB,CAMA,gBAAAgc,GACI,MAA8B,WAAvB5oB,KAAKqoB,SAASQ,MAA2D,YAAtC7oB,KAAKonB,QAAQ0B,cAAcnP,MACzE,CAKA,WAAAoP,GACI,MAA8B,YAAvB/oB,KAAKqoB,SAASQ,IACzB,CAOA,oBAAAG,GACI,MAAMC,EAA2EjpB,KAAKonB,QAAQ8B,gBAAgBpR,IACzGkQ,IAAK,CAAQA,QAAOrO,OAAQ,UAG3B6E,EAAUxe,KAAKonB,QAAQ0B,aAK7B,OAJItK,IAAYxe,KAAKonB,QAAQ8B,gBAAgB5a,SAASkQ,EAAQwJ,QAC1DiB,EAAO7hB,KAAK,CAAE4gB,MAAOxJ,EAAQwJ,MAAOrO,OAAQ6E,EAAQ7E,SAGjDsP,CACX,CAKA,UAAAE,GACI,OAAOnpB,KAAKsoB,eAChB,CAKA,iBAAAc,GACI,MAAO,IAAIppB,KAAKsoB,iBAAiBpmB,OAAQE,GAAMA,EAAEmmB,WAAWrZ,KAAK,CAACpR,EAAG6M,IAAM7M,EAAEurB,MAAQ1e,EAAE0e,MAC3F,CAMA,oBAAAC,GACI,OAAOtpB,KAAKopB,oBAAoBlnB,OAAQE,GAAMA,EAAEmnB,iBACpD,WCpGYC,sBACZtC,EACAta,EACAwa,GAEA,MAAMiB,EAAWnB,EAAOG,WAAW9N,KAAMzb,GAAMA,EAAE8O,WAAaA,GAC9D,IAAKyb,EACD,MAAM,IAAIpoB,MAAM,yBAAyB2M,iDAG7C,MAAM0b,EAAoCpB,EAAOuC,QAAQ3R,IAAK4R,IAC1D,MAAMnB,EAAYF,EAASoB,SAASE,QAAQrb,SAASob,EAAIlB,YAAa,EAChEC,EAAaJ,EAASoB,SAASG,SAAStb,SAASob,EAAIlB,YAAa,EAClEE,EAAWL,EAASoB,SAASI,SAAWH,EAAIlB,SAElD,MAAO,IACAkB,EACHnB,YACAE,aACAC,cAKFoB,EAAYxB,EAAgBvY,KAAM3N,GAAMA,EAAEsmB,UAChD,IAAKoB,EAAW,CACZ,MAAMC,EAAezB,EAAgB/O,KAAMnX,GAAMA,EAAEmnB,kBAAoBnnB,EAAEmmB,WACrEwB,IACAA,EAAarB,UAAW,EAEhC,CAEA,OAAO,IAAIN,cAAcC,EAAUC,EAAiBlB,EACxD,CC1BM,SAAU4C,eACZC,EACAC,GAEA,IAAK,MAAO3a,EAAMoX,KAAU/iB,OAAOmV,QAAQmR,GACvCD,EAAOtD,MAAMpX,EAAMoX,GAEvB,OAAO,IAAIwD,MAAMD,EAAU,CACvBhpB,IAAK,CAACkpB,EAASC,IAAiBJ,EAAOtD,MAAM0D,IAErD","x_google_ignoreList":[0]}
|