From 6012ba701d4b6ac92464373bef7d96582fb53de1 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Sun, 19 Apr 2026 08:52:40 +0300 Subject: [PATCH] fixed relation and file custom change event trigger --- .../{index-DhtJzO0I.js => index-OxsdchXY.js} | 4 +- ui/dist/index.html | 2 +- ui/package.json | 3 +- ui/src/fields/file/input.js | 240 +++++++++--------- ui/src/fields/relation/input.js | 158 ++++++------ 5 files changed, 204 insertions(+), 203 deletions(-) rename ui/dist/assets/{index-DhtJzO0I.js => index-OxsdchXY.js} (99%) diff --git a/ui/dist/assets/index-DhtJzO0I.js b/ui/dist/assets/index-OxsdchXY.js similarity index 99% rename from ui/dist/assets/index-DhtJzO0I.js rename to ui/dist/assets/index-OxsdchXY.js index c2864fea..f2522c8f 100644 --- a/ui/dist/assets/index-DhtJzO0I.js +++ b/ui/dist/assets/index-OxsdchXY.js @@ -47,8 +47,8 @@ The field cannot be presentable if hidden.`),n})})))},()=>{if(i.showHidden)retur This field is disabled if "Only domains" is set.`)})),t.input({type:`text`,id:n+`.exceptDomains`,disabled:()=>!app.utils.isEmpty(e.field.onlyDomains),name:()=>`fields.${e.fieldIndex}.exceptDomains`,value:()=>app.utils.joinNonEmpty(e.field.exceptDomains),onchange:n=>e.field.exceptDomains=app.utils.splitNonEmpty(n.target.value,`,`)})),t.div({className:`field-help`},`Use comma as separator.`)),t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.onlyDomains`},t.span({className:`txt`},`Only domains`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`List of domains that are ONLY allowed. This field is disabled if "Except domains" is set.`)})),t.input({type:`text`,id:n+`.onlyDomains`,disabled:()=>!app.utils.isEmpty(e.field.exceptDomains),name:()=>`fields.${e.fieldIndex}.onlyDomains`,value:()=>app.utils.joinNonEmpty(e.field.onlyDomains),onchange:n=>e.field.onlyDomains=app.utils.splitNonEmpty(n.target.value,`,`)})),t.div({className:`field-help`},`Use comma as separator.`)),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string`)})))]})}function J(e){return t.div({className:`record-field-view field-type-email`},()=>{let n=e.record[e.field.name]||``;return n?e.short?t.span({className:`txt txt-ellipsis`,textContent:app.utils.truncate(n)}):n:t.span({className:`missing-value`})})}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.email={icon:`ri-mail-line`,label:`Email`,settings:ln,input:cn,view:J,filterModifiers:e=>[`lower`],dummyData:(e,n=!1)=>`test_${app.utils.randomString(3,`123567890`)}@example.com`};function un(e){let n=`url_`+app.utils.randomString();return t.div({className:`record-field-input field-type-url`},t.div({className:`field`},t.label({htmlFor:n},t.i({className:app.fieldTypes.url.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),t.input({type:`url`,id:n,spellcheck:!1,name:()=>e.field.name,required:()=>e.field.required,value:()=>e.record[e.field.name]||``,oninput:n=>e.record[e.field.name]=n.target.value})),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function Y(e){let n=`f_`+app.utils.randomString();return app.components.fieldSettings(e,{content:()=>t.div({className:`grid sm`},t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.exceptDomains`},t.span({className:`txt`},`Except domains`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`List of domains that are NOT allowed. This field is disabled if "Only domains" is set.`)})),t.input({type:`text`,id:n+`.exceptDomains`,disabled:()=>!app.utils.isEmpty(e.field.onlyDomains),name:()=>`fields.${e.fieldIndex}.exceptDomains`,value:()=>app.utils.joinNonEmpty(e.field.exceptDomains),onchange:n=>e.field.exceptDomains=app.utils.splitNonEmpty(n.target.value,`,`)})),t.div({className:`field-help`},`Use comma as separator.`)),t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.onlyDomains`},t.span({className:`txt`},`Only domains`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`List of domains that are ONLY allowed. -This field is disabled if "Except domains" is set.`)})),t.input({type:`text`,id:n+`.onlyDomains`,disabled:()=>!app.utils.isEmpty(e.field.exceptDomains),name:()=>`fields.${e.fieldIndex}.onlyDomains`,value:()=>app.utils.joinNonEmpty(e.field.onlyDomains),onchange:n=>e.field.onlyDomains=app.utils.splitNonEmpty(n.target.value,`,`)})),t.div({className:`field-help`},`Use comma as separator.`)),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string`)})))]})}function dn(e){return t.div({className:`record-field-view field-type-url`},()=>{let n=e.record[e.field.name]||``;return n?t.a({href:()=>n,className:`txt txt-ellipsis`,rel:`noopener noreferrer`,target:`_blank`,textContent:app.utils.truncate(n),ariaDescription:app.attrs.tooltip(`Open in new tab`),onclick:e=>{e.stopPropagation()}}):t.span({className:`missing-value`})})}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.url={icon:`ri-link`,label:`URL`,settings:Y,input:un,view:dn,dummyData:(e,n=!1)=>`https://example.com`};function fn(e){let n=`date_`+app.utils.randomString();return t.div({className:`record-field-input field-type-date`},t.div({className:`field`},t.label({htmlFor:n},t.i({className:app.fieldTypes.date.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),t.input({id:n,step:1,type:`datetime-local`,name:()=>e.field.name,required:()=>e.field.required,value:()=>app.utils.toDatetimeLocalInputValue(e.record[e.field.name]),onchange:n=>{e.record[e.field.name]=app.utils.toRFC3339Datetime(n.target.value)}})),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function pn(e){let n=`f_`+app.utils.randomString();return app.components.fieldSettings(e,{content:()=>t.div({className:`grid sm`},t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.min`},t.span({className:`txt`},`Min date (Local)`)),t.input({type:`datetime-local`,id:n+`.min`,step:1,name:()=>`fields.${e.fieldIndex}.min`,value:()=>app.utils.toDatetimeLocalInputValue(e.field.min),onchange:n=>{e.field.min=app.utils.toRFC3339Datetime(n.target.value)}}))),t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.max`},t.span({className:`txt`},`Max date (Local)`)),t.input({type:`datetime-local`,id:n+`.max`,step:1,name:()=>`fields.${e.fieldIndex}.max`,value:()=>app.utils.toDatetimeLocalInputValue(e.field.max),onchange:n=>{e.field.max=app.utils.toRFC3339Datetime(n.target.value)}}))),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string`)})))]})}function mn(e){return t.div({className:`record-field-view field-type-date`},app.components.formattedDate({value:()=>e.record[e.field.name],short:()=>e.short}))}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.date={icon:`ri-calendar-line`,label:`Datetime`,settings:pn,input:fn,view:mn,dummyData:(e,n=!1)=>new Date().toISOString().replaceAll(`T`,` `)};function hn(e){delete e.clone[e.field.name]}function gn(e){let n=[{label:`Create`,value:1},{label:`Update`,value:2},{label:`Create/Update`,value:3}];function r(e){return e.onCreate&&e.onUpdate?3:e.onUpdate?2:1}function i(n){switch(n){case 1:e.field.onCreate=!0,e.field.onUpdate=!1;break;case 2:e.field.onCreate=!1,e.field.onUpdate=!0;break;case 3:e.field.onCreate=!0,e.field.onUpdate=!0;break}}let a=store({isDropdownOpen:!1});return app.components.fieldSettings(e,{header:t.div({className:`field header-select autodate-select`,ariaDescription:app.attrs.tooltip(`Auto set on`,`left`),onmount:()=>{i(r(e.field))}},app.components.select({required:!0,options:n,disabled:()=>e.originalCollection?.system,value:()=>r(e.field),onchange:e=>i(e?.[0]?.value),ondropdowntoggle:e=>{a.isDropdownOpen=e.newState==`open`}}))})}function _n(e){return t.div({className:`record-field-view field-type-autodate`},app.components.formattedDate({value:()=>e.record[e.field.name],short:()=>e.short}))}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.autodate={icon:`ri-calendar-check-line`,label:`Autodate`,settings:gn,view:_n,onrecordduplicate:hn,dummyData:(e,n=!1)=>{if(!n)return new Date().toISOString().replaceAll(`T`,` `)}};var vn=`@@filesToDelete`;function X(e){let n=app.utils.toArray(e.payload[e.field.name]),r=app.utils.toArray(e.record[vn]?.[e.field.name]);for(let e of r){let r=n.indexOf(e);r>=0&&n.splice(r,1)}e.payload[e.field.name]=n}function yn(e){let n=`file_`+app.utils.randomString();function r(n){return typeof n==`string`?!!e.record[vn]?.[e.field.name]?.includes(n):!1}function i(n){if(typeof n==`string`){e.record[vn]=e.record[`@@filesToDelete`]||{},e.record[vn][e.field.name]=e.record[`@@filesToDelete`][e.field.name]||[],app.utils.pushUnique(e.record[vn][e.field.name],n),c();return}let r=app.utils.toArray(e.record[e.field.name]),i=r.indexOf(n);i>=0&&(r.splice(i,1),e.record[e.field.name]=r,c())}function a(n){typeof n==`string`&&(app.utils.removeByValue(e.record[vn]?.[e.field.name],n),c())}function o(){return e.record[`@@filesToDelete`]?.[e.field.name]?.length||0}function s(){return app.utils.toArray(e.record[e.field.name]).length-o()}function c(){f?.dispatchEvent(new CustomEvent(`change`,{detail:{data:e},bubbles:!0}))}let l=store({get maxReached(){let n=e.field.maxSelect||1;return s()>=n}});function u(n){let r=app.utils.toArray(e.record[e.field.name]);for(let e of n){if(l.maxReached){console.warn(`can't add more files - max allowed files reached`);break}r.push(e)}e.record[e.field.name]=r,c()}let d=t.input({type:`file`,hidden:!0,name:()=>e.field.name,multiple:()=>e.field.maxSelect>1,accept:()=>e.field.mimeTypes?.join(`,`)||void 0,onchange:e=>{u(e.target.files),e.target.value=null}}),f=t.div({className:`record-field-input field-type-file`,ondragover:e=>{e.preventDefault()},ondrop:e=>{let n=e.dataTransfer?.files||[];n.length&&(e.preventDefault(),!l.maxReached&&u(n))}},t.div({className:()=>`field ${e.field.required?`required`:``}`},t.label({htmlFor:n},t.i({className:app.fieldTypes.file.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),d,t.div({className:`field-content`},app.components.sortable({className:`list`,data:()=>{let n=app.utils.toArray(e.record[e.field.name]),r=!1;for(let e=n.length-1;e>=0;e--)typeof n[e]==`string`||n[e]instanceof Blob||(r=!0,n.splice(e,1));return r&&(e.record[e.field.name]=n),n},onchange:n=>{e.record[e.field.name]=n,c()},dataItem:(n,o)=>t.div({rid:n,className:()=>`list-item highlight ${r(n)?`deleted`:``}`},t.div({className:`content gap-10`},()=>typeof n==`string`?[app.components.recordFileThumb({record:e.record,filename:n}),t.button({type:`button`,ariaDescription:app.attrs.tooltip(`Open in new tab`),onclick:async()=>{let r=await app.getFileToken(e.record.collectionId),i=app.pb.files.getURL(e.record,n,{token:r});window.open(i,`_blank`,`noreferrer,noopener`)}},t.span({className:`txt link-primary`},n))]:[app.components.uploadedFileThumb({file:n}),t.span({className:`label success`},`New`),t.span({className:`txt`},n.name)]),t.div({className:`actions`},t.button({type:`button`,className:`btn sm secondary transparent circle`,ariaLabel:app.attrs.tooltip(`Remove file`),hidden:()=>r(n),onclick:()=>i(n)},t.i({className:`ri-close-line`,ariaHidden:!0})),t.button({type:`button`,className:`btn sm warning transparent`,hidden:()=>!r(n),onclick:()=>a(n)},t.span({className:`txt`},`Restore`))))}),t.hr({className:`m-t-5 m-b-0`,hidden:()=>app.utils.toArray(e.record[e.field.name]).length>0}),t.button({type:`button`,className:`btn sm secondary block`,title:()=>l.maxReached?`Max allowed files reached`:void 0,disabled:()=>l.maxReached,onclick:e=>{l.maxReached||d.click(),document.activeElement?.blur()}},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0}),t.span({className:`txt`},`Upload or drop new file`)))),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)});return f}function bn(e){delete e.clone[e.field.name]}function xn(e){let n=`f_`+app.utils.randomString();return app.components.fieldSettings(e,{header:[t.div({className:`field header-select single-multiple-select`},app.components.select({required:!0,options:[{label:`Single`,value:!1},{label:`Multiple`,value:!0}],value:()=>e.field.maxSelect>1,onchange:n=>{n?.[0]?.value?(!e.field.maxSelect||e.field.maxSelect<2)&&(e.field.maxSelect=10):e.field.maxSelect=1}}))],content:()=>t.div({className:`grid sm`},t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.mimeTypes`},t.span({className:`txt`},`Allowed mime types`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Allow files ONLY with the listed mime types. - Leave empty for no restriction.`)})),app.components.select({max:99,placeholder:`No restriction`,options:app.utils.mimeTypes.map(e=>({value:e.mimeType,label:()=>t.div({className:`inline-flex gap-10`},t.span({className:`txt`},e.ext||`-`),t.small({className:`txt-hint`},e.mimeType))})),name:()=>`fields.${e.fieldIndex}.mimeTypes`,value:()=>app.utils.toArray(e.field.mimeTypes),onchange:n=>e.field.mimeTypes=n.map(e=>e.value)})),t.div({className:`field-help`},t.button({type:`button`,className:`link-hint gap-0`,"html-popovertarget":n+`mimeTypesDropdown`},t.span({className:`txt`},`Choose presets`),t.i({className:`ri-arrow-drop-down-fill`,ariaHidden:!0})),t.div({id:n+`mimeTypesDropdown`,className:`dropdown sm nowrap left p-10`,popover:`auto`},t.button({type:`button`,className:`dropdown-item`,role:`menuitem`,onclick:n=>{e.field.mimeTypes=[`image/jpeg`,`image/png`,`image/svg+xml`,`image/gif`,`image/webp`],n.target.closest(`.dropdown`).hidePopover()},textContent:`Images (jpg, png, svg, gif, webp)`}),t.button({type:`button`,className:`dropdown-item`,role:`menuitem`,onclick:n=>{e.field.mimeTypes=[`application/pdf`,`application/msword`,`application/vnd.openxmlformats-officedocument.wordprocessingml.document`,`application/vnd.ms-excel`,`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`],n.target.closest(`.dropdown`).hidePopover()},textContent:`Documents (pdf, doc/docx, xls/xlsx)`}),t.button({type:`button`,className:`dropdown-item`,role:`menuitem`,onclick:n=>{e.field.mimeTypes=[`video/mp4`,`video/mpeg`,`video/x-msvideo`,`video/quicktime`,`video/3gpp`],n.target.closest(`.dropdown`).hidePopover()},textContent:`Videos (mp4, mpeg, avi, mov, 3gp)`}),t.button({type:`button`,className:`dropdown-item`,role:`menuitem`,onclick:n=>{e.field.mimeTypes=[`application/zip`,`application/x-7z-compressed`,`application/x-rar-compressed`],n.target.closest(`.dropdown`).hidePopover()},textContent:`Archives (zip, 7zip, rar)`})))),t.div({className:()=>e.field.maxSelect>1?`col-sm-6`:`col-sm-9`},t.div({className:`field`},t.label({htmlFor:n+`.thumbs`},t.span({className:`txt`},`Thumb sizes`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`List of additional thumb sizes for image files, along with the default thumb size of 100x100. The thumbs are generated lazily on first access.`)})),t.input({type:`text`,id:n+`.thumbs`,placeholder:`e.g. 50x50, 480x720`,name:()=>`fields.${e.fieldIndex}.thumbs`,value:()=>app.utils.joinNonEmpty(e.field.thumbs),onchange:n=>e.field.thumbs=app.utils.splitNonEmpty(n.target.value,`,`)})),t.div({className:`field-help`},t.span({className:`txt m-r-5`},`Use comma as separator.`),t.button({type:`button`,className:`link-hint gap-0`,"html-popovertarget":n+`thumbFormatsDropdown`},t.span({className:`txt`},`Supported formats`),t.i({className:`ri-arrow-drop-down-fill`,ariaHidden:!0})),t.div({id:n+`thumbFormatsDropdown`,className:`dropdown sm nowrap left p-10`,popover:`auto`},t.ul({className:`m-0 p-l-sm`},t.li(null,t.strong(null,`WxH`),t.span(null,` (e.g. 100x50) - crop to WxH viewbox (from center)`)),t.li(null,t.strong(null,`WxHt`),t.span(null,` (e.g. 100x50t) - crop to WxH viewbox (from top)`)),t.li(null,t.strong(null,`WxHb`),t.span(null,` (e.g. 100x50b) - crop to WxH viewbox (from bottom)`)),t.li(null,t.strong(null,`WxHf`),t.span(null,` (e.g. 100x50f) - fit inside a WxH viewbox (without cropping)`)),t.li(null,t.strong(null,`0xH`),t.span(null,` (e.g. 0x50) - resize to H height preserving the aspect ratio`)),t.li(null,t.strong(null,`Wx0`),t.span(null,` (e.g. 100x0) - resize to W width preserving the aspect ratio`)))))),t.div({className:`col-sm-3`},t.div({className:`field`},t.label({htmlFor:n+`.maxSize`},`Max size`),t.input({type:`number`,id:n+`.maxSize`,step:1,min:0,max:2**53-1,placeholder:`~5MB default`,name:()=>`fields.${e.fieldIndex}.maxSize`,value:()=>e.field.maxSize||``,oninput:n=>e.field.maxSize=parseInt(n.target.value,10)})),t.div({className:`field-help`},`In bytes.`)),()=>{if(e.field.maxSelect>1)return t.div({className:`col-sm-3`},t.div({className:`field`},t.label({htmlFor:n+`.maxSelect`},`Max select`),t.input({type:`number`,id:n+`.maxSelect`,placeholder:`Default to single`,step:1,min:2,required:!0,max:2**53-1,name:()=>`fields.${e.fieldIndex}.maxSelect`,value:()=>e.field.maxSelect||``,onchange:e=>{let n=parseInt(e.target.value,10);n>1?props.field.maxSelect=n:props.field.maxSelect=1}})))},t.div({className:`col-sm-12`},t.div({className:`field m-t-5 m-b-5`},t.input({className:`switch`,type:`checkbox`,id:n+`.protected`,name:()=>`fields.${e.fieldIndex}.protected`,checked:()=>!!e.field.protected,onchange:n=>e.field.protected=n.target.checked}),t.label({htmlFor:n+`.protected`},t.span({className:`txt`},`Protected`),t.small({className:`txt-hint`},`Files will require View API rule permissions and file token (`,t.a({href:`https://pocketbase.io/docs/files-handling#protected-files`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Learn more`}),`).`)))),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string`)})))]})}function Sn(e){return t.div({className:`record-field-view field-type-file`},()=>{let n=app.utils.toArray(e.record[e.field.name]);if(!n.length)return t.span({className:`missing-value`});let r=[],i=e.short?5:100;for(let a=0;a=i){r.push(t.span({className:`thumb sm`},`+`,n.length-i));break}r.push(app.components.recordFileThumb({record:e.record,filename:n[a]}))}return r})}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.file={icon:`ri-image-line`,label:`File`,settings:xn,input:yn,view:Sn,summaryPriority:-1,onrecordsave:X,onrecordduplicate:bn,filterModifiers:e=>e.maxSelect>1?[`each`,`length`]:[],dummyData:(e,n=!1)=>n?e.maxSelect>1?[Cn(`test1.txt`),Cn(`test2.txt`)]:Cn(`test1.txt`):e.maxSelect>1?[`test1_`+app.utils.randomString(10)+`.txt`,`test2_`+app.utils.randomString(10)+`.txt`]:`test_`+app.utils.randomString(10)+`.txt`};function Cn(e){return{toString(){return`new File([...], '${e}')`},toJSON(){return`[[new File([...], '${e}')]]`}}}function wn(e){let n=`rel_`+app.utils.randomString();function r(){l?.dispatchEvent(new CustomEvent(`change`,{detail:{data:e},bubbles:!0}))}let i=store({selected:[],isLoading:!0,get maxReached(){let n=e.field.maxSelect||1;return app.utils.toArray(e.record[e.field.name]).length>=n}});async function a(){i.isLoading=!0;let n=app.utils.toArray(e.record[e.field.name]);if(!n.length){i.selected=[],i.isLoading=!1;return}try{let r=app.store.collections.find(n=>n.id==e.field.collectionId),a=[],o=r?.fields?.filter(e=>!e.hidden&&e.presentable&&e.type==`relation`)||[];for(let e of o)a.push(e.name);let s=await app.pb.collection(e.field.collectionId).getFullList({requestKey:null,filter:n.map(e=>app.pb.filter(`id={:id}`,{id:e})).join(`||`),expand:a.join(`,`)||void 0}),c=[];for(let e of n){let n=s.find(n=>n.id==e);n&&c.push(n)}i.selected=c,i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}function o(n){let r=app.utils.toArray(e.record[e.field.name]),a=r.indexOf(n);a>=0&&(r.splice(a,1),s(r));let o=i.selected.findIndex(e=>e.id==n);i.selected.splice(o,1)}function s(n=[]){e.record[e.field.name]=e.field.maxSelect>1?n:n?.[0]||``}let c=[watch(()=>e.record[e.field.name],()=>a())],l=t.div({className:`record-field-input field-type-relation`,onunmount:()=>{c.forEach(e=>e?.unwatch())}},t.div({className:()=>`field ${e.field.required?`required`:``}`},t.label({htmlFor:n},t.i({className:app.fieldTypes.relation.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),t.output({className:`field-content`,name:()=>e.field.name},t.div({hidden:()=>!i.isLoading,className:`list`},()=>app.utils.toArray(e.record[e.field.name]).map(()=>t.div({className:`list-item`},t.span({className:`skeleton-loader`})))),app.components.sortable({className:`list`,hidden:()=>i.isLoading,data:()=>i.selected,onchange:e=>{i.selected=e,s(e.map(e=>e.id)),r()},dataItem:(e,n)=>t.div({rid:e,className:`list-item highlight`},t.div({className:`content`},()=>app.components.recordSummary(e)),t.div({className:`actions`},t.button({className:`btn sm secondary transparent circle`,ariaLabel:app.attrs.tooltip(`Remove`),onclick:()=>o(e.id)},t.i({className:`ri-close-line`,ariaHidden:!0}))))}),t.hr({hidden:()=>!app.utils.isEmpty(e.record[e.field.name]),className:`m-t-5 m-b-0`}),t.button({type:`button`,className:`btn sm secondary block`,disabled:()=>i.isLoading,onclick:n=>{app.modals.openRecordsPicker({collection:e.field.collectionId,selectedIds:app.utils.toArray(e.record[e.field.name]),maxSelect:e.field.maxSelect,onselect:e=>{i.selected=e,s(e.map(e=>e.id))}})}},t.i({className:`ri-magic-line`,ariaHidden:!0}),t.span({className:`txt`},`Open records picker`)))),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)});return l}function Tn(e){let n=`f_`+app.utils.randomString(),r=[{label:`False`,value:!1},{label:`True`,value:!0}],i=[{label:`Single`,value:!1},{label:`Multiple`,value:!0}],a=[watch(()=>e.field.maxSelect,n=>{n||=1,n<=1&&(e.field.minSelect=0)})];return app.components.fieldSettings(e,{header:[t.div({className:`field header-select collections-select`,onunmount:()=>{a.forEach(e=>e?.unwatch())}},app.components.select({required:!0,className:`inline-error`,placeholder:`Select collection*`,name:()=>`fields.${e.fieldIndex}.collectionId`,disabled:()=>!!e.originalField?.id,options:()=>app.utils.sortedCollections(app.store.collections.filter(e=>e.type!=`view`)).map(e=>({value:e.id,label:e.name})),value:()=>e.field.collectionId,onchange:n=>{e.field.collectionId=n?.[0]?.value||``},after:()=>[t.hr({className:`m-t-5 m-b-5`}),t.button({type:`button`,className:`btn sm outline`,onclick:()=>{app.modals.openCollectionUpsert({},{onsave:n=>{e.field.collectionId=n.id}})}},t.i({className:`ri-add-line`,ariaHidden:!0}),t.span({className:`txt`},`New collection`))]})),t.div({className:`field header-select single-multiple-select`},app.components.select({required:!0,options:i,value:()=>e.field.maxSelect>1,onchange:n=>{n?.[0]?.value?e.field.maxSelect<<0<2&&(e.field.maxSelect=10):e.field.maxSelect=1}}))],content:()=>t.div({className:`grid sm`},t.div({className:`col-sm-6`,hidden:()=>e.field.maxSelect<<0<2},t.div({className:`field`},t.label({htmlFor:n+`.minSelect`},`Min select`),t.input({type:`number`,id:n+`.minSelect`,step:1,min:0,max:2**53-1,placeholder:`No min limit`,name:()=>`fields.${e.fieldIndex}.minSelect`,value:()=>e.field.minSelect||``,onchange:n=>e.field.minSelect=parseInt(n.target.value,10)}))),t.div({className:`col-sm-6`,hidden:()=>e.field.maxSelect<<0<2},t.div({className:`field`},t.label({htmlFor:n+`.maxSelect`},`Max select`),t.input({type:`number`,id:n+`.maxSelect`,step:1,min:()=>e.field.minSelect||2,max:2**53-1,placeholder:`Default to single`,name:()=>`fields.${e.fieldIndex}.maxSelect`,value:()=>e.field.maxSelect||``,onchange:n=>{let r=parseInt(n.target.value,10);r>1?e.field.maxSelect=r:e.field.maxSelect=1}}))),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.cascadeDelete`},`Cascade delete`),app.components.select({required:!0,id:n+`.cascadeDelete`,name:()=>`fields.${e.fieldIndex}.cascadeDelete`,options:r,value:()=>e.field.cascadeDelete||!1,onchange:n=>{e.field.cascadeDelete=!!n?.[0].value}}))),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string`)})))]})}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.relation={icon:`ri-mind-map`,label:`Relation`,settings:Tn,input:wn,view:Ht,filterModifiers:e=>e.maxSelect>1?[`each`,`length`]:[],dummyData:(e,n=!1)=>e.maxSelect>1?[`RECORD_ID1`,`RECORD_ID2`]:`RECORD_ID`};function En(e){let n=`select_`+app.utils.randomString();return t.div({className:`record-field-input field-type-select`},t.div({className:`field`},t.label({htmlFor:n},t.i({className:app.fieldTypes.select.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),app.components.select({id:n,max:()=>e.field.maxSelect||1,required:()=>e.field.required,options:()=>e.field.values.map(e=>({value:e})),value:()=>app.utils.toArray(e.record[e.field.name]),onchange:n=>{if(e.field.maxSelect<=1){e.record[e.field.name]=n?.[0]?.value||``;return}e.record[e.field.name]=n.map(e=>e.value)}})),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function Dn(e){let n=`f_`+app.utils.randomString(),r=[{label:`Single`,value:!1},{label:`Multiple`,value:!0}],i=t.div({popover:`manual`,className:`dropdown field-select-choices-dropdown`},t.div({className:`field-help m-t-0`,style:`font-size: 0.9em`},`New-line separated choices:`),t.div({className:`field`},t.textarea({className:`autoexpand`,required:!0,value:()=>app.utils.toArray(e.field.values,!1).join(` +This field is disabled if "Except domains" is set.`)})),t.input({type:`text`,id:n+`.onlyDomains`,disabled:()=>!app.utils.isEmpty(e.field.exceptDomains),name:()=>`fields.${e.fieldIndex}.onlyDomains`,value:()=>app.utils.joinNonEmpty(e.field.onlyDomains),onchange:n=>e.field.onlyDomains=app.utils.splitNonEmpty(n.target.value,`,`)})),t.div({className:`field-help`},`Use comma as separator.`)),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string`)})))]})}function dn(e){return t.div({className:`record-field-view field-type-url`},()=>{let n=e.record[e.field.name]||``;return n?t.a({href:()=>n,className:`txt txt-ellipsis`,rel:`noopener noreferrer`,target:`_blank`,textContent:app.utils.truncate(n),ariaDescription:app.attrs.tooltip(`Open in new tab`),onclick:e=>{e.stopPropagation()}}):t.span({className:`missing-value`})})}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.url={icon:`ri-link`,label:`URL`,settings:Y,input:un,view:dn,dummyData:(e,n=!1)=>`https://example.com`};function fn(e){let n=`date_`+app.utils.randomString();return t.div({className:`record-field-input field-type-date`},t.div({className:`field`},t.label({htmlFor:n},t.i({className:app.fieldTypes.date.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),t.input({id:n,step:1,type:`datetime-local`,name:()=>e.field.name,required:()=>e.field.required,value:()=>app.utils.toDatetimeLocalInputValue(e.record[e.field.name]),onchange:n=>{e.record[e.field.name]=app.utils.toRFC3339Datetime(n.target.value)}})),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function pn(e){let n=`f_`+app.utils.randomString();return app.components.fieldSettings(e,{content:()=>t.div({className:`grid sm`},t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.min`},t.span({className:`txt`},`Min date (Local)`)),t.input({type:`datetime-local`,id:n+`.min`,step:1,name:()=>`fields.${e.fieldIndex}.min`,value:()=>app.utils.toDatetimeLocalInputValue(e.field.min),onchange:n=>{e.field.min=app.utils.toRFC3339Datetime(n.target.value)}}))),t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.max`},t.span({className:`txt`},`Max date (Local)`)),t.input({type:`datetime-local`,id:n+`.max`,step:1,name:()=>`fields.${e.fieldIndex}.max`,value:()=>app.utils.toDatetimeLocalInputValue(e.field.max),onchange:n=>{e.field.max=app.utils.toRFC3339Datetime(n.target.value)}}))),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string`)})))]})}function mn(e){return t.div({className:`record-field-view field-type-date`},app.components.formattedDate({value:()=>e.record[e.field.name],short:()=>e.short}))}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.date={icon:`ri-calendar-line`,label:`Datetime`,settings:pn,input:fn,view:mn,dummyData:(e,n=!1)=>new Date().toISOString().replaceAll(`T`,` `)};function hn(e){delete e.clone[e.field.name]}function gn(e){let n=[{label:`Create`,value:1},{label:`Update`,value:2},{label:`Create/Update`,value:3}];function r(e){return e.onCreate&&e.onUpdate?3:e.onUpdate?2:1}function i(n){switch(n){case 1:e.field.onCreate=!0,e.field.onUpdate=!1;break;case 2:e.field.onCreate=!1,e.field.onUpdate=!0;break;case 3:e.field.onCreate=!0,e.field.onUpdate=!0;break}}let a=store({isDropdownOpen:!1});return app.components.fieldSettings(e,{header:t.div({className:`field header-select autodate-select`,ariaDescription:app.attrs.tooltip(`Auto set on`,`left`),onmount:()=>{i(r(e.field))}},app.components.select({required:!0,options:n,disabled:()=>e.originalCollection?.system,value:()=>r(e.field),onchange:e=>i(e?.[0]?.value),ondropdowntoggle:e=>{a.isDropdownOpen=e.newState==`open`}}))})}function _n(e){return t.div({className:`record-field-view field-type-autodate`},app.components.formattedDate({value:()=>e.record[e.field.name],short:()=>e.short}))}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.autodate={icon:`ri-calendar-check-line`,label:`Autodate`,settings:gn,view:_n,onrecordduplicate:hn,dummyData:(e,n=!1)=>{if(!n)return new Date().toISOString().replaceAll(`T`,` `)}};var vn=`@@filesToDelete`;function X(e){let n=app.utils.toArray(e.payload[e.field.name]),r=app.utils.toArray(e.record[vn]?.[e.field.name]);for(let e of r){let r=n.indexOf(e);r>=0&&n.splice(r,1)}e.payload[e.field.name]=n}function yn(e){let n=`file_`+app.utils.randomString();function r(n){return typeof n==`string`?!!e.record[vn]?.[e.field.name]?.includes(n):!1}function i(n){if(typeof n==`string`){e.record[vn]=e.record[`@@filesToDelete`]||{},e.record[vn][e.field.name]=e.record[`@@filesToDelete`][e.field.name]||[],app.utils.pushUnique(e.record[vn][e.field.name],n),c();return}let r=app.utils.toArray(e.record[e.field.name]),i=r.indexOf(n);i>=0&&(r.splice(i,1),e.record[e.field.name]=r,c())}function a(n){typeof n==`string`&&(app.utils.removeByValue(e.record[vn]?.[e.field.name],n),c())}function o(){return e.record[`@@filesToDelete`]?.[e.field.name]?.length||0}function s(){return app.utils.toArray(e.record[e.field.name]).length-o()}function c(){f?.dispatchEvent(new CustomEvent(`change`,{detail:{data:e},bubbles:!0}))}let l=store({get maxReached(){let n=e.field.maxSelect||1;return s()>=n}});function u(n){let r=app.utils.toArray(e.record[e.field.name]);for(let e of n){if(l.maxReached){console.warn(`can't add more files - max allowed files reached`);break}r.push(e)}e.record[e.field.name]=r,c()}let d=t.input({type:`file`,hidden:!0,multiple:()=>e.field.maxSelect>1,accept:()=>e.field.mimeTypes?.join(`,`)||void 0,onchange:e=>{u(e.target.files),e.target.value=null}}),f=t.output({className:`field-content`,name:()=>e.field.name},app.components.sortable({className:`list`,data:()=>{let n=app.utils.toArray(e.record[e.field.name]),r=!1;for(let e=n.length-1;e>=0;e--)typeof n[e]==`string`||n[e]instanceof Blob||(r=!0,n.splice(e,1));return r&&(e.record[e.field.name]=n),n},onchange:n=>{e.record[e.field.name]=n,c()},dataItem:(n,o)=>t.div({rid:n,className:()=>`list-item highlight ${r(n)?`deleted`:``}`},t.div({className:`content gap-10`},()=>typeof n==`string`?[app.components.recordFileThumb({record:e.record,filename:n}),t.button({type:`button`,ariaDescription:app.attrs.tooltip(`Open in new tab`),onclick:async()=>{let r=await app.getFileToken(e.record.collectionId),i=app.pb.files.getURL(e.record,n,{token:r});window.open(i,`_blank`,`noreferrer,noopener`)}},t.span({className:`txt link-primary`},n))]:[app.components.uploadedFileThumb({file:n}),t.span({className:`label success`},`New`),t.span({className:`txt`},n.name)]),t.div({className:`actions`},t.button({type:`button`,className:`btn sm secondary transparent circle`,ariaLabel:app.attrs.tooltip(`Remove file`),hidden:()=>r(n),onclick:()=>i(n)},t.i({className:`ri-close-line`,ariaHidden:!0})),t.button({type:`button`,className:`btn sm warning transparent`,hidden:()=>!r(n),onclick:()=>a(n)},t.span({className:`txt`},`Restore`))))}),t.hr({className:`m-t-5 m-b-0`,hidden:()=>app.utils.toArray(e.record[e.field.name]).length>0}),t.button({type:`button`,className:`btn sm secondary block`,title:()=>l.maxReached?`Max allowed files reached`:void 0,disabled:()=>l.maxReached,onclick:e=>{l.maxReached||d?.click(),document.activeElement?.blur()}},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0}),t.span({className:`txt`},`Upload or drop new file`)));return t.div({className:`record-field-input field-type-file`,ondragover:e=>{e.preventDefault()},ondrop:e=>{let n=e.dataTransfer?.files||[];n.length&&(e.preventDefault(),!l.maxReached&&u(n))}},t.div({className:()=>`field ${e.field.required?`required`:``}`},t.label({htmlFor:n},t.i({className:app.fieldTypes.file.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),d,f),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function bn(e){delete e.clone[e.field.name]}function xn(e){let n=`f_`+app.utils.randomString();return app.components.fieldSettings(e,{header:[t.div({className:`field header-select single-multiple-select`},app.components.select({required:!0,options:[{label:`Single`,value:!1},{label:`Multiple`,value:!0}],value:()=>e.field.maxSelect>1,onchange:n=>{n?.[0]?.value?(!e.field.maxSelect||e.field.maxSelect<2)&&(e.field.maxSelect=10):e.field.maxSelect=1}}))],content:()=>t.div({className:`grid sm`},t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.mimeTypes`},t.span({className:`txt`},`Allowed mime types`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Allow files ONLY with the listed mime types. + Leave empty for no restriction.`)})),app.components.select({max:99,placeholder:`No restriction`,options:app.utils.mimeTypes.map(e=>({value:e.mimeType,label:()=>t.div({className:`inline-flex gap-10`},t.span({className:`txt`},e.ext||`-`),t.small({className:`txt-hint`},e.mimeType))})),name:()=>`fields.${e.fieldIndex}.mimeTypes`,value:()=>app.utils.toArray(e.field.mimeTypes),onchange:n=>e.field.mimeTypes=n.map(e=>e.value)})),t.div({className:`field-help`},t.button({type:`button`,className:`link-hint gap-0`,"html-popovertarget":n+`mimeTypesDropdown`},t.span({className:`txt`},`Choose presets`),t.i({className:`ri-arrow-drop-down-fill`,ariaHidden:!0})),t.div({id:n+`mimeTypesDropdown`,className:`dropdown sm nowrap left p-10`,popover:`auto`},t.button({type:`button`,className:`dropdown-item`,role:`menuitem`,onclick:n=>{e.field.mimeTypes=[`image/jpeg`,`image/png`,`image/svg+xml`,`image/gif`,`image/webp`],n.target.closest(`.dropdown`).hidePopover()},textContent:`Images (jpg, png, svg, gif, webp)`}),t.button({type:`button`,className:`dropdown-item`,role:`menuitem`,onclick:n=>{e.field.mimeTypes=[`application/pdf`,`application/msword`,`application/vnd.openxmlformats-officedocument.wordprocessingml.document`,`application/vnd.ms-excel`,`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`],n.target.closest(`.dropdown`).hidePopover()},textContent:`Documents (pdf, doc/docx, xls/xlsx)`}),t.button({type:`button`,className:`dropdown-item`,role:`menuitem`,onclick:n=>{e.field.mimeTypes=[`video/mp4`,`video/mpeg`,`video/x-msvideo`,`video/quicktime`,`video/3gpp`],n.target.closest(`.dropdown`).hidePopover()},textContent:`Videos (mp4, mpeg, avi, mov, 3gp)`}),t.button({type:`button`,className:`dropdown-item`,role:`menuitem`,onclick:n=>{e.field.mimeTypes=[`application/zip`,`application/x-7z-compressed`,`application/x-rar-compressed`],n.target.closest(`.dropdown`).hidePopover()},textContent:`Archives (zip, 7zip, rar)`})))),t.div({className:()=>e.field.maxSelect>1?`col-sm-6`:`col-sm-9`},t.div({className:`field`},t.label({htmlFor:n+`.thumbs`},t.span({className:`txt`},`Thumb sizes`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`List of additional thumb sizes for image files, along with the default thumb size of 100x100. The thumbs are generated lazily on first access.`)})),t.input({type:`text`,id:n+`.thumbs`,placeholder:`e.g. 50x50, 480x720`,name:()=>`fields.${e.fieldIndex}.thumbs`,value:()=>app.utils.joinNonEmpty(e.field.thumbs),onchange:n=>e.field.thumbs=app.utils.splitNonEmpty(n.target.value,`,`)})),t.div({className:`field-help`},t.span({className:`txt m-r-5`},`Use comma as separator.`),t.button({type:`button`,className:`link-hint gap-0`,"html-popovertarget":n+`thumbFormatsDropdown`},t.span({className:`txt`},`Supported formats`),t.i({className:`ri-arrow-drop-down-fill`,ariaHidden:!0})),t.div({id:n+`thumbFormatsDropdown`,className:`dropdown sm nowrap left p-10`,popover:`auto`},t.ul({className:`m-0 p-l-sm`},t.li(null,t.strong(null,`WxH`),t.span(null,` (e.g. 100x50) - crop to WxH viewbox (from center)`)),t.li(null,t.strong(null,`WxHt`),t.span(null,` (e.g. 100x50t) - crop to WxH viewbox (from top)`)),t.li(null,t.strong(null,`WxHb`),t.span(null,` (e.g. 100x50b) - crop to WxH viewbox (from bottom)`)),t.li(null,t.strong(null,`WxHf`),t.span(null,` (e.g. 100x50f) - fit inside a WxH viewbox (without cropping)`)),t.li(null,t.strong(null,`0xH`),t.span(null,` (e.g. 0x50) - resize to H height preserving the aspect ratio`)),t.li(null,t.strong(null,`Wx0`),t.span(null,` (e.g. 100x0) - resize to W width preserving the aspect ratio`)))))),t.div({className:`col-sm-3`},t.div({className:`field`},t.label({htmlFor:n+`.maxSize`},`Max size`),t.input({type:`number`,id:n+`.maxSize`,step:1,min:0,max:2**53-1,placeholder:`~5MB default`,name:()=>`fields.${e.fieldIndex}.maxSize`,value:()=>e.field.maxSize||``,oninput:n=>e.field.maxSize=parseInt(n.target.value,10)})),t.div({className:`field-help`},`In bytes.`)),()=>{if(e.field.maxSelect>1)return t.div({className:`col-sm-3`},t.div({className:`field`},t.label({htmlFor:n+`.maxSelect`},`Max select`),t.input({type:`number`,id:n+`.maxSelect`,placeholder:`Default to single`,step:1,min:2,required:!0,max:2**53-1,name:()=>`fields.${e.fieldIndex}.maxSelect`,value:()=>e.field.maxSelect||``,onchange:e=>{let n=parseInt(e.target.value,10);n>1?props.field.maxSelect=n:props.field.maxSelect=1}})))},t.div({className:`col-sm-12`},t.div({className:`field m-t-5 m-b-5`},t.input({className:`switch`,type:`checkbox`,id:n+`.protected`,name:()=>`fields.${e.fieldIndex}.protected`,checked:()=>!!e.field.protected,onchange:n=>e.field.protected=n.target.checked}),t.label({htmlFor:n+`.protected`},t.span({className:`txt`},`Protected`),t.small({className:`txt-hint`},`Files will require View API rule permissions and file token (`,t.a({href:`https://pocketbase.io/docs/files-handling#protected-files`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Learn more`}),`).`)))),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string`)})))]})}function Sn(e){return t.div({className:`record-field-view field-type-file`},()=>{let n=app.utils.toArray(e.record[e.field.name]);if(!n.length)return t.span({className:`missing-value`});let r=[],i=e.short?5:100;for(let a=0;a=i){r.push(t.span({className:`thumb sm`},`+`,n.length-i));break}r.push(app.components.recordFileThumb({record:e.record,filename:n[a]}))}return r})}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.file={icon:`ri-image-line`,label:`File`,settings:xn,input:yn,view:Sn,summaryPriority:-1,onrecordsave:X,onrecordduplicate:bn,filterModifiers:e=>e.maxSelect>1?[`each`,`length`]:[],dummyData:(e,n=!1)=>n?e.maxSelect>1?[Cn(`test1.txt`),Cn(`test2.txt`)]:Cn(`test1.txt`):e.maxSelect>1?[`test1_`+app.utils.randomString(10)+`.txt`,`test2_`+app.utils.randomString(10)+`.txt`]:`test_`+app.utils.randomString(10)+`.txt`};function Cn(e){return{toString(){return`new File([...], '${e}')`},toJSON(){return`[[new File([...], '${e}')]]`}}}function wn(e){let n=`rel_`+app.utils.randomString();function r(){l?.dispatchEvent(new CustomEvent(`change`,{detail:{data:e},bubbles:!0}))}let i=store({selected:[],isLoading:!0,get maxReached(){let n=e.field.maxSelect||1;return app.utils.toArray(e.record[e.field.name]).length>=n}});async function a(){i.isLoading=!0;let n=app.utils.toArray(e.record[e.field.name]);if(!n.length){i.selected=[],i.isLoading=!1;return}try{let r=app.store.collections.find(n=>n.id==e.field.collectionId),a=[],o=r?.fields?.filter(e=>!e.hidden&&e.presentable&&e.type==`relation`)||[];for(let e of o)a.push(e.name);let s=await app.pb.collection(e.field.collectionId).getFullList({requestKey:null,filter:n.map(e=>app.pb.filter(`id={:id}`,{id:e})).join(`||`),expand:a.join(`,`)||void 0}),c=[];for(let e of n){let n=s.find(n=>n.id==e);n&&c.push(n)}i.selected=c,i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}function o(n){let r=app.utils.toArray(e.record[e.field.name]),a=r.indexOf(n);a>=0&&(r.splice(a,1),s(r));let o=i.selected.findIndex(e=>e.id==n);i.selected.splice(o,1)}function s(n=[]){e.record[e.field.name]=e.field.maxSelect>1?n:n?.[0]||``,r()}let c=[watch(()=>e.record[e.field.name],()=>a())],l=t.output({className:`field-content`,name:()=>e.field.name},t.div({hidden:()=>!i.isLoading,className:`list`},()=>app.utils.toArray(e.record[e.field.name]).map(()=>t.div({className:`list-item`},t.span({className:`skeleton-loader`})))),app.components.sortable({className:`list`,hidden:()=>i.isLoading,data:()=>i.selected,onchange:e=>{i.selected=e,s(e.map(e=>e.id))},dataItem:(e,n)=>t.div({rid:e,className:`list-item highlight`},t.div({className:`content`},()=>app.components.recordSummary(e)),t.div({className:`actions`},t.button({className:`btn sm secondary transparent circle`,ariaLabel:app.attrs.tooltip(`Remove`),onclick:()=>o(e.id)},t.i({className:`ri-close-line`,ariaHidden:!0}))))}),t.hr({hidden:()=>!app.utils.isEmpty(e.record[e.field.name]),className:`m-t-5 m-b-0`}),t.button({type:`button`,className:`btn sm secondary block`,disabled:()=>i.isLoading,onclick:n=>{app.modals.openRecordsPicker({collection:e.field.collectionId,selectedIds:app.utils.toArray(e.record[e.field.name]),maxSelect:e.field.maxSelect,onselect:e=>{i.selected=e,s(e.map(e=>e.id))}})}},t.i({className:`ri-magic-line`,ariaHidden:!0}),t.span({className:`txt`},`Open records picker`)));return t.div({className:`record-field-input field-type-relation`,onunmount:()=>{c.forEach(e=>e?.unwatch())}},t.div({className:()=>`field ${e.field.required?`required`:``}`},t.label({htmlFor:n},t.i({className:app.fieldTypes.relation.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),l),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function Tn(e){let n=`f_`+app.utils.randomString(),r=[{label:`False`,value:!1},{label:`True`,value:!0}],i=[{label:`Single`,value:!1},{label:`Multiple`,value:!0}],a=[watch(()=>e.field.maxSelect,n=>{n||=1,n<=1&&(e.field.minSelect=0)})];return app.components.fieldSettings(e,{header:[t.div({className:`field header-select collections-select`,onunmount:()=>{a.forEach(e=>e?.unwatch())}},app.components.select({required:!0,className:`inline-error`,placeholder:`Select collection*`,name:()=>`fields.${e.fieldIndex}.collectionId`,disabled:()=>!!e.originalField?.id,options:()=>app.utils.sortedCollections(app.store.collections.filter(e=>e.type!=`view`)).map(e=>({value:e.id,label:e.name})),value:()=>e.field.collectionId,onchange:n=>{e.field.collectionId=n?.[0]?.value||``},after:()=>[t.hr({className:`m-t-5 m-b-5`}),t.button({type:`button`,className:`btn sm outline`,onclick:()=>{app.modals.openCollectionUpsert({},{onsave:n=>{e.field.collectionId=n.id}})}},t.i({className:`ri-add-line`,ariaHidden:!0}),t.span({className:`txt`},`New collection`))]})),t.div({className:`field header-select single-multiple-select`},app.components.select({required:!0,options:i,value:()=>e.field.maxSelect>1,onchange:n=>{n?.[0]?.value?e.field.maxSelect<<0<2&&(e.field.maxSelect=10):e.field.maxSelect=1}}))],content:()=>t.div({className:`grid sm`},t.div({className:`col-sm-6`,hidden:()=>e.field.maxSelect<<0<2},t.div({className:`field`},t.label({htmlFor:n+`.minSelect`},`Min select`),t.input({type:`number`,id:n+`.minSelect`,step:1,min:0,max:2**53-1,placeholder:`No min limit`,name:()=>`fields.${e.fieldIndex}.minSelect`,value:()=>e.field.minSelect||``,onchange:n=>e.field.minSelect=parseInt(n.target.value,10)}))),t.div({className:`col-sm-6`,hidden:()=>e.field.maxSelect<<0<2},t.div({className:`field`},t.label({htmlFor:n+`.maxSelect`},`Max select`),t.input({type:`number`,id:n+`.maxSelect`,step:1,min:()=>e.field.minSelect||2,max:2**53-1,placeholder:`Default to single`,name:()=>`fields.${e.fieldIndex}.maxSelect`,value:()=>e.field.maxSelect||``,onchange:n=>{let r=parseInt(n.target.value,10);r>1?e.field.maxSelect=r:e.field.maxSelect=1}}))),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.cascadeDelete`},`Cascade delete`),app.components.select({required:!0,id:n+`.cascadeDelete`,name:()=>`fields.${e.fieldIndex}.cascadeDelete`,options:r,value:()=>e.field.cascadeDelete||!1,onchange:n=>{e.field.cascadeDelete=!!n?.[0].value}}))),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string`)})))]})}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.relation={icon:`ri-mind-map`,label:`Relation`,settings:Tn,input:wn,view:Ht,filterModifiers:e=>e.maxSelect>1?[`each`,`length`]:[],dummyData:(e,n=!1)=>e.maxSelect>1?[`RECORD_ID1`,`RECORD_ID2`]:`RECORD_ID`};function En(e){let n=`select_`+app.utils.randomString();return t.div({className:`record-field-input field-type-select`},t.div({className:`field`},t.label({htmlFor:n},t.i({className:app.fieldTypes.select.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),app.components.select({id:n,max:()=>e.field.maxSelect||1,required:()=>e.field.required,options:()=>e.field.values.map(e=>({value:e})),value:()=>app.utils.toArray(e.record[e.field.name]),onchange:n=>{if(e.field.maxSelect<=1){e.record[e.field.name]=n?.[0]?.value||``;return}e.record[e.field.name]=n.map(e=>e.value)}})),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function Dn(e){let n=`f_`+app.utils.randomString(),r=[{label:`Single`,value:!1},{label:`Multiple`,value:!0}],i=t.div({popover:`manual`,className:`dropdown field-select-choices-dropdown`},t.div({className:`field-help m-t-0`,style:`font-size: 0.9em`},`New-line separated choices:`),t.div({className:`field`},t.textarea({className:`autoexpand`,required:!0,value:()=>app.utils.toArray(e.field.values,!1).join(` `),oninput:n=>{let r=n.target.value.trimStart().replaceAll(` `,` diff --git a/ui/dist/index.html b/ui/dist/index.html index 1e078ff4..16d70bf6 100644 --- a/ui/dist/index.html +++ b/ui/dist/index.html @@ -13,7 +13,7 @@ - + diff --git a/ui/package.json b/ui/package.json index 3442c238..0f847167 100644 --- a/ui/package.json +++ b/ui/package.json @@ -4,8 +4,7 @@ "type": "module", "scripts": { "dev": "vite", - "build": "vite build", - "format": "dprint fmt" + "build": "dprint fmt && vite build" }, "dependencies": { "leaflet": "^1.9.4", diff --git a/ui/src/fields/file/input.js b/ui/src/fields/file/input.js index 301bab39..d3964a57 100644 --- a/ui/src/fields/file/input.js +++ b/ui/src/fields/file/input.js @@ -57,7 +57,7 @@ export function input(props) { // trigger custom change event for clearing field errors function triggerChangeEvent() { - fieldEl?.dispatchEvent( + fieldContentEl?.dispatchEvent( new CustomEvent("change", { detail: { data: props }, bubbles: true, @@ -92,7 +92,6 @@ export function input(props) { const fileInput = t.input({ type: "file", hidden: true, - name: () => props.field.name, multiple: () => props.field.maxSelect > 1, accept: () => props.field.mimeTypes?.join(",") || undefined, onchange: (e) => { @@ -101,7 +100,125 @@ export function input(props) { }, }); - const fieldEl = t.div( + const fieldContentEl = t.output( + { + className: "field-content", + name: () => props.field.name, + }, + // @todo enable ordering new files before/inbetween existing + app.components.sortable({ + className: "list", + data: () => { + const vals = app.utils.toArray(props.record[props.field.name]); + + let hadInvalid = false; + // filter empty or invalid values (e.g. from old serialized draft) + for (let i = vals.length - 1; i >= 0; i--) { + if (typeof vals[i] == "string" || vals[i] instanceof Blob) { + continue; // valid + } + + hadInvalid = true; + vals.splice(i, 1); + } + + // update record model to prevent conflict with required and other validators + if (hadInvalid) { + props.record[props.field.name] = vals; + } + + return vals; + }, + onchange: (sortedList) => { + props.record[props.field.name] = sortedList; + triggerChangeEvent(); + }, + dataItem: (nameOrFile, i) => { + return t.div( + { + rid: nameOrFile, + className: () => `list-item highlight ${isDeleted(nameOrFile) ? "deleted" : ""}`, + }, + t.div({ className: "content gap-10" }, () => { + if (typeof nameOrFile == "string") { + return [ + app.components.recordFileThumb({ + record: props.record, + filename: nameOrFile, + }), + t.button( + { + type: "button", + ariaDescription: app.attrs.tooltip("Open in new tab"), + onclick: async () => { + const token = await app.getFileToken(props.record.collectionId); + const url = app.pb.files.getURL(props.record, nameOrFile, { + token, + }); + window.open(url, "_blank", "noreferrer,noopener"); + }, + }, + t.span({ className: "txt link-primary" }, nameOrFile), + ), + ]; + } + + return [ + app.components.uploadedFileThumb({ + file: nameOrFile, + }), + t.span({ className: "label success" }, "New"), + t.span({ className: "txt" }, nameOrFile.name), + ]; + }), + t.div( + { className: "actions" }, + t.button( + { + type: "button", + className: "btn sm secondary transparent circle", + ariaLabel: app.attrs.tooltip("Remove file"), + hidden: () => isDeleted(nameOrFile), + onclick: () => toDelete(nameOrFile), + }, + t.i({ className: "ri-close-line", ariaHidden: true }), + ), + t.button( + { + type: "button", + className: "btn sm warning transparent", + hidden: () => !isDeleted(nameOrFile), + onclick: () => restoreDeleted(nameOrFile), + }, + t.span({ className: "txt" }, "Restore"), + ), + ), + ); + }, + }), + t.hr({ + className: "m-t-5 m-b-0", + hidden: () => app.utils.toArray(props.record[props.field.name]).length > 0, + }), + t.button( + { + type: "button", + className: "btn sm secondary block", + title: () => local.maxReached ? "Max allowed files reached" : undefined, + disabled: () => local.maxReached, + onclick: (e) => { + if (!local.maxReached) { + fileInput?.click(); + } + document.activeElement?.blur(); + }, + }, + t.i({ className: "ri-upload-cloud-line", ariaHidden: true }), + t.span({ className: "txt" }, "Upload or drop new file"), + ), + ); + + return t.div( { className: "record-field-input field-type-file", ondragover: (e) => { @@ -130,120 +247,7 @@ export function input(props) { t.span({ className: "txt" }, () => props.field.name), ), fileInput, - t.div( - { className: "field-content" }, - // @todo enable ordering new files before/inbetween existing - app.components.sortable({ - className: "list", - data: () => { - const vals = app.utils.toArray(props.record[props.field.name]); - - let hadInvalid = false; - // filter empty or invalid values (e.g. from old serialized draft) - for (let i = vals.length - 1; i >= 0; i--) { - if (typeof vals[i] == "string" || vals[i] instanceof Blob) { - continue; // valid - } - - hadInvalid = true; - vals.splice(i, 1); - } - - // update record model to prevent conflict with required and other validators - if (hadInvalid) { - props.record[props.field.name] = vals; - } - - return vals; - }, - onchange: (sortedList) => { - props.record[props.field.name] = sortedList; - triggerChangeEvent(); - }, - dataItem: (nameOrFile, i) => { - return t.div( - { - rid: nameOrFile, - className: () => `list-item highlight ${isDeleted(nameOrFile) ? "deleted" : ""}`, - }, - t.div({ className: "content gap-10" }, () => { - if (typeof nameOrFile == "string") { - return [ - app.components.recordFileThumb({ - record: props.record, - filename: nameOrFile, - }), - t.button( - { - type: "button", - ariaDescription: app.attrs.tooltip("Open in new tab"), - onclick: async () => { - const token = await app.getFileToken(props.record.collectionId); - const url = app.pb.files.getURL(props.record, nameOrFile, { - token, - }); - window.open(url, "_blank", "noreferrer,noopener"); - }, - }, - t.span({ className: "txt link-primary" }, nameOrFile), - ), - ]; - } - - return [ - app.components.uploadedFileThumb({ - file: nameOrFile, - }), - t.span({ className: "label success" }, "New"), - t.span({ className: "txt" }, nameOrFile.name), - ]; - }), - t.div( - { className: "actions" }, - t.button( - { - type: "button", - className: "btn sm secondary transparent circle", - ariaLabel: app.attrs.tooltip("Remove file"), - hidden: () => isDeleted(nameOrFile), - onclick: () => toDelete(nameOrFile), - }, - t.i({ className: "ri-close-line", ariaHidden: true }), - ), - t.button( - { - type: "button", - className: "btn sm warning transparent", - hidden: () => !isDeleted(nameOrFile), - onclick: () => restoreDeleted(nameOrFile), - }, - t.span({ className: "txt" }, "Restore"), - ), - ), - ); - }, - }), - t.hr({ - className: "m-t-5 m-b-0", - hidden: () => app.utils.toArray(props.record[props.field.name]).length > 0, - }), - t.button( - { - type: "button", - className: "btn sm secondary block", - title: () => local.maxReached ? "Max allowed files reached" : undefined, - disabled: () => local.maxReached, - onclick: (e) => { - if (!local.maxReached) { - fileInput.click(); - } - document.activeElement?.blur(); - }, - }, - t.i({ className: "ri-upload-cloud-line", ariaHidden: true }), - t.span({ className: "txt" }, "Upload or drop new file"), - ), - ), + fieldContentEl, ), () => { if (props.field.help) { @@ -251,6 +255,4 @@ export function input(props) { } }, ); - - return fieldEl; } diff --git a/ui/src/fields/relation/input.js b/ui/src/fields/relation/input.js index f859b2f8..437ddd81 100644 --- a/ui/src/fields/relation/input.js +++ b/ui/src/fields/relation/input.js @@ -9,7 +9,7 @@ export function input(props) { // trigger custom change event for clearing field errors function triggerChangeEvent() { - fieldEl?.dispatchEvent( + fieldContentEl?.dispatchEvent( new CustomEvent("change", { detail: { data: props }, bubbles: true, @@ -87,6 +87,7 @@ export function input(props) { function updateRecordValue(ids = []) { props.record[props.field.name] = props.field.maxSelect > 1 ? ids : ids?.[0] || ""; + triggerChangeEvent(); } const watchers = [ @@ -96,7 +97,82 @@ export function input(props) { ), ]; - const fieldEl = t.div( + const fieldContentEl = t.output( + { + className: "field-content", + name: () => props.field.name, + }, + // loader + t.div( + { + hidden: () => !local.isLoading, + className: "list", + }, + () => { + const ids = app.utils.toArray(props.record[props.field.name]); + return ids.map(() => { + return t.div({ className: "list-item" }, t.span({ className: "skeleton-loader" })); + }); + }, + ), + // list + app.components.sortable({ + className: "list", + hidden: () => local.isLoading, + data: () => local.selected, + onchange: (sortedList) => { + local.selected = sortedList; + updateRecordValue(sortedList.map((r) => r.id)); + }, + dataItem: (record, relIndex) => { + return t.div( + { + rid: record, + className: "list-item highlight", + }, + t.div({ className: "content" }, () => app.components.recordSummary(record)), + t.div( + { className: "actions" }, + t.button( + { + className: "btn sm secondary transparent circle", + ariaLabel: app.attrs.tooltip("Remove"), + onclick: () => remove(record.id), + }, + t.i({ className: "ri-close-line", ariaHidden: true }), + ), + ), + ); + }, + }), + // picker btn + t.hr({ + hidden: () => !app.utils.isEmpty(props.record[props.field.name]), + className: "m-t-5 m-b-0", + }), + t.button( + { + type: "button", + className: "btn sm secondary block", + disabled: () => local.isLoading, + onclick: (e) => { + app.modals.openRecordsPicker({ + collection: props.field.collectionId, + selectedIds: app.utils.toArray(props.record[props.field.name]), + maxSelect: props.field.maxSelect, + onselect: (records) => { + local.selected = records; + updateRecordValue(records.map((r) => r.id)); + }, + }); + }, + }, + t.i({ className: "ri-magic-line", ariaHidden: true }), + t.span({ className: "txt" }, "Open records picker"), + ), + ); + + return t.div( { className: "record-field-input field-type-relation", onunmount: () => { @@ -110,81 +186,7 @@ export function input(props) { t.i({ className: app.fieldTypes.relation.icon, ariaHidden: true }), t.span({ className: "txt" }, () => props.field.name), ), - t.output( - { - className: "field-content", - name: () => props.field.name, - }, - // loader - t.div( - { - hidden: () => !local.isLoading, - className: "list", - }, - () => { - const ids = app.utils.toArray(props.record[props.field.name]); - return ids.map(() => { - return t.div({ className: "list-item" }, t.span({ className: "skeleton-loader" })); - }); - }, - ), - // list - app.components.sortable({ - className: "list", - hidden: () => local.isLoading, - data: () => local.selected, - onchange: (sortedList) => { - local.selected = sortedList; - updateRecordValue(sortedList.map((r) => r.id)); - triggerChangeEvent(); - }, - dataItem: (record, relIndex) => { - return t.div( - { - rid: record, - className: "list-item highlight", - }, - t.div({ className: "content" }, () => app.components.recordSummary(record)), - t.div( - { className: "actions" }, - t.button( - { - className: "btn sm secondary transparent circle", - ariaLabel: app.attrs.tooltip("Remove"), - onclick: () => remove(record.id), - }, - t.i({ className: "ri-close-line", ariaHidden: true }), - ), - ), - ); - }, - }), - // picker btn - t.hr({ - hidden: () => !app.utils.isEmpty(props.record[props.field.name]), - className: "m-t-5 m-b-0", - }), - t.button( - { - type: "button", - className: "btn sm secondary block", - disabled: () => local.isLoading, - onclick: (e) => { - app.modals.openRecordsPicker({ - collection: props.field.collectionId, - selectedIds: app.utils.toArray(props.record[props.field.name]), - maxSelect: props.field.maxSelect, - onselect: (records) => { - local.selected = records; - updateRecordValue(records.map((r) => r.id)); - }, - }); - }, - }, - t.i({ className: "ri-magic-line", ariaHidden: true }), - t.span({ className: "txt" }, "Open records picker"), - ), - ), + fieldContentEl, ), () => { if (props.field.help) { @@ -192,6 +194,4 @@ export function input(props) { } }, ); - - return fieldEl; }