domma-cms 0.44.0 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +53 -53
- package/README.md +27 -27
- package/admin/css/admin.css +1 -1
- package/admin/dist/domma/domma-tools.css +3 -3
- package/admin/dist/domma/domma-tools.min.js +3 -3
- package/admin/index.html +2 -2
- package/admin/js/app.js +1 -1
- package/admin/js/lib/card-builder.js +2 -2
- package/admin/js/lib/crud-tutorial.js +1 -1
- package/admin/js/lib/effect-defs.js +1 -1
- package/admin/js/lib/effects-builder.js +1 -1
- package/admin/js/lib/image-editor.js +1 -1
- package/admin/js/lib/markdown-toolbar.js +2 -2
- package/admin/js/lib/project-context.js +1 -1
- package/admin/js/lib/project-quick-create.js +1 -1
- package/admin/js/lib/scribe-composer.js +1 -1
- package/admin/js/lib/server-restart.js +1 -1
- package/admin/js/lib/shortcode-context-menu.js +2 -2
- package/admin/js/lib/simple-editor.js +1 -1
- package/admin/js/lib/themes.js +1 -1
- package/admin/js/lib/timeline-builder.js +1 -1
- package/admin/js/templates/action-editor.html +8 -8
- package/admin/js/templates/api-endpoint-editor.html +7 -7
- package/admin/js/templates/api-endpoints.html +1 -1
- package/admin/js/templates/api-reference.html +1 -1
- package/admin/js/templates/block-editor.html +6 -6
- package/admin/js/templates/collection-editor.html +1 -1
- package/admin/js/templates/component-editor.html +2 -2
- package/admin/js/templates/dashboard/cache.html +3 -3
- package/admin/js/templates/dashboard/journeys.html +3 -3
- package/admin/js/templates/dashboard/kpi-strip.html +3 -3
- package/admin/js/templates/dashboard/top-pages.html +1 -1
- package/admin/js/templates/dashboard/traffic-chart.html +1 -1
- package/admin/js/templates/docs/api-actions.html +1 -1
- package/admin/js/templates/docs/api-collections.html +4 -4
- package/admin/js/templates/docs/api-pages.html +2 -2
- package/admin/js/templates/docs/api-plugins.html +1 -1
- package/admin/js/templates/docs/api-settings.html +2 -2
- package/admin/js/templates/docs/api-users.html +1 -1
- package/admin/js/templates/docs/components-howto.html +4 -4
- package/admin/js/templates/docs/components-reference.html +21 -21
- package/admin/js/templates/docs/components-rules.html +14 -14
- package/admin/js/templates/docs/components-walkthrough.html +13 -13
- package/admin/js/templates/docs/tutorial-crud.html +49 -49
- package/admin/js/templates/docs/tutorial-forms.html +4 -4
- package/admin/js/templates/docs/tutorial-plugin.html +10 -10
- package/admin/js/templates/docs/usage-actions.html +6 -6
- package/admin/js/templates/docs/usage-cta-shortcode.html +9 -9
- package/admin/js/templates/docs/usage-dconfig.html +4 -4
- package/admin/js/templates/docs/usage-navigation.html +1 -1
- package/admin/js/templates/docs/usage-pages.html +1 -1
- package/admin/js/templates/docs/usage-shortcodes.html +24 -24
- package/admin/js/templates/docs/usage-users-roles.html +3 -3
- package/admin/js/templates/docs/usage-views.html +4 -4
- package/admin/js/templates/documentation.html +1 -1
- package/admin/js/templates/effects.html +752 -752
- package/admin/js/templates/form-editor.html +5 -5
- package/admin/js/templates/forms.html +17 -17
- package/admin/js/templates/login.html +5 -5
- package/admin/js/templates/menu-editor.html +10 -10
- package/admin/js/templates/my-profile.html +17 -17
- package/admin/js/templates/navigation.html +11 -11
- package/admin/js/templates/notifications.html +1 -1
- package/admin/js/templates/page-editor.html +4 -4
- package/admin/js/templates/pro-docs.html +14 -14
- package/admin/js/templates/role-editor.html +70 -70
- package/admin/js/templates/roles.html +10 -10
- package/admin/js/templates/settings.html +10 -10
- package/admin/js/templates/tutorials.html +3 -3
- package/admin/js/templates/view-editor.html +15 -15
- package/admin/js/views/action-editor.js +1 -1
- package/admin/js/views/actions-list.js +1 -1
- package/admin/js/views/api-endpoint-editor.js +2 -2
- package/admin/js/views/api-endpoints.js +2 -2
- package/admin/js/views/api-tokens.js +3 -3
- package/admin/js/views/blocks.js +2 -2
- package/admin/js/views/collection-editor.js +1 -1
- package/admin/js/views/collection-entries.js +1 -1
- package/admin/js/views/collections.js +1 -1
- package/admin/js/views/component-editor.js +1 -1
- package/admin/js/views/components.js +4 -4
- package/admin/js/views/dashboard/widgets/cache.js +1 -1
- package/admin/js/views/dashboard/widgets/journeys.js +1 -1
- package/admin/js/views/dashboard/widgets/kpi-strip.js +1 -1
- package/admin/js/views/form-editor.js +7 -7
- package/admin/js/views/form-submissions.js +1 -1
- package/admin/js/views/forms.js +1 -1
- package/admin/js/views/layouts.js +1 -1
- package/admin/js/views/login.js +2 -2
- package/admin/js/views/menu-editor.js +3 -3
- package/admin/js/views/menu-locations.js +1 -1
- package/admin/js/views/menus.js +3 -3
- package/admin/js/views/navigation.js +8 -8
- package/admin/js/views/page-editor.js +40 -40
- package/admin/js/views/pages.js +3 -3
- package/admin/js/views/plugin-code.js +2 -2
- package/admin/js/views/plugins.js +1 -1
- package/admin/js/views/project-settings.js +1 -1
- package/admin/js/views/projects.js +1 -1
- package/admin/js/views/roles.js +1 -1
- package/admin/js/views/user-editor.js +1 -1
- package/admin/js/views/users.js +3 -3
- package/admin/js/views/view-editor.js +1 -1
- package/admin/js/views/view-preview.js +1 -1
- package/admin/js/views/views-list.js +1 -1
- package/bin/cli.js +8 -8
- package/bin/lib/config-merge.js +44 -44
- package/bin/update.js +16 -16
- package/config/plugins.json +1 -1
- package/package.json +2 -2
- package/plugins/_template/admin/views/index.js +1 -1
- package/plugins/_template/config.js +1 -1
- package/plugins/_template/plugin.js +1 -1
- package/plugins/analytics/admin/templates/analytics.html +3 -3
- package/plugins/analytics/admin/views/analytics.js +1 -1
- package/plugins/analytics/config.js +1 -1
- package/plugins/analytics/plugin.js +4 -4
- package/plugins/analytics/plugin.json +1 -1
- package/plugins/analytics/public/inject-body.html +2 -2
- package/plugins/analytics/public/inject-head.html +1 -1
- package/plugins/blog/admin/templates/blog.html +4 -4
- package/plugins/blog/admin/views/blog.js +3 -3
- package/plugins/blog/admin/views/categories.js +2 -2
- package/plugins/blog/admin/views/comments.js +4 -4
- package/plugins/blog/admin/views/post-editor.js +1 -1
- package/plugins/blog/plugin.js +2 -2
- package/plugins/blog/plugin.json +4 -4
- package/plugins/contacts/admin/views/contacts.js +8 -8
- package/plugins/contacts/plugin.js +4 -4
- package/plugins/contacts/plugin.json +1 -1
- package/plugins/invoice/admin/templates/editor.html +6 -6
- package/plugins/invoice/admin/templates/index.html +4 -4
- package/plugins/invoice/admin/views/editor.js +3 -3
- package/plugins/invoice/admin/views/index.js +4 -4
- package/plugins/invoice/admin/views/issuers.js +1 -1
- package/plugins/invoice/admin/views/party-view.js +3 -3
- package/plugins/invoice/admin/views/receivers.js +1 -1
- package/plugins/invoice/config.js +1 -1
- package/plugins/invoice/plugin.js +1 -1
- package/plugins/invoice/plugin.json +4 -4
- package/plugins/notes/admin/views/notes.js +4 -4
- package/plugins/notes/plugin.js +1 -1
- package/plugins/notes/plugin.json +1 -1
- package/plugins/site-search/admin/templates/site-search.html +3 -3
- package/plugins/site-search/admin/views/site-search.js +1 -1
- package/plugins/site-search/config.js +1 -1
- package/plugins/site-search/plugin.js +4 -4
- package/plugins/site-search/plugin.json +1 -1
- package/plugins/surveys/admin/templates/results.html +1 -1
- package/plugins/surveys/admin/templates/survey-editor.html +4 -4
- package/plugins/surveys/admin/views/audience.js +6 -6
- package/plugins/surveys/admin/views/results.js +3 -3
- package/plugins/surveys/admin/views/survey-editor.js +1 -1
- package/plugins/surveys/admin/views/surveys.js +2 -2
- package/plugins/surveys/plugin.js +1 -1
- package/plugins/surveys/plugin.json +4 -4
- package/plugins/theme-switcher/admin/views/theme-switcher.js +1 -1
- package/plugins/theme-switcher/plugin.json +3 -3
- package/plugins/theme-switcher/public/inject-body.html +28 -28
- package/plugins/theme-switcher/public/inject-head.html +1 -1
- package/plugins/todo/plugin.js +1 -1
- package/public/css/forms.css +1 -1
- package/public/js/collection-browser.js +1 -1
- package/public/js/collection-context.js +1 -1
- package/public/js/form-logic-engine.js +1 -1
- package/public/js/forms.js +2 -1
- package/public/js/site.js +1 -1
- package/scripts/build.js +14 -14
- package/scripts/create-plugin.js +2 -2
- package/scripts/fresh.js +2 -2
- package/scripts/gen-instance-secret.js +1 -1
- package/scripts/pro.js +12 -12
- package/scripts/reset.js +2 -2
- package/scripts/setup.js +15 -15
- package/scripts/users.js +5 -5
- package/scripts/verify-assets.mjs +6 -6
- package/server/config.js +1 -1
- package/server/middleware/auth.js +253 -253
- package/server/middleware/managerAuth.js +3 -3
- package/server/routes/api/actions.js +4 -4
- package/server/routes/api/api-endpoints.js +7 -7
- package/server/routes/api/api-tokens.js +5 -5
- package/server/routes/api/auth.js +309 -309
- package/server/routes/api/blocks.js +3 -3
- package/server/routes/api/collections.js +18 -18
- package/server/routes/api/dashboard.js +5 -5
- package/server/routes/api/effects.js +2 -2
- package/server/routes/api/endpoints-public.js +5 -5
- package/server/routes/api/forms.js +47 -47
- package/server/routes/api/menu-locations.js +3 -3
- package/server/routes/api/menus.js +7 -7
- package/server/routes/api/navigation.js +42 -42
- package/server/routes/api/notifications.js +2 -2
- package/server/routes/api/pages.js +14 -2
- package/server/routes/api/plugin-marketplace.js +3 -3
- package/server/routes/api/plugins.js +6 -6
- package/server/routes/api/projects.js +9 -9
- package/server/routes/api/scaffold.js +7 -7
- package/server/routes/api/settings.js +6 -6
- package/server/routes/api/sidebar.js +1 -1
- package/server/routes/api/users.js +5 -5
- package/server/routes/api/versions.js +1 -1
- package/server/routes/api/views.js +1 -1
- package/server/routes/docs-public.js +3 -3
- package/server/routes/public.js +14 -14
- package/server/server.js +34 -16
- package/server/services/actions.js +19 -19
- package/server/services/adapters/FileAdapter.js +2 -2
- package/server/services/adapters/MongoAdapter.js +5 -5
- package/server/services/apiEndpoints.js +15 -15
- package/server/services/apiTokens.js +7 -7
- package/server/services/blocks.js +13 -13
- package/server/services/cache/drivers/MemoryDriver.js +3 -3
- package/server/services/cache/drivers/NoneDriver.js +1 -1
- package/server/services/cache/index.js +5 -5
- package/server/services/collections.js +14 -14
- package/server/services/components.js +9 -9
- package/server/services/connectionManager.js +4 -4
- package/server/services/content.js +25 -2
- package/server/services/docs.js +14 -14
- package/server/services/email.js +167 -167
- package/server/services/filterEngine.js +6 -6
- package/server/services/forms.js +18 -10
- package/server/services/health.js +1 -1
- package/server/services/hooks.js +7 -7
- package/server/services/images.js +4 -4
- package/server/services/managerClient.js +1 -1
- package/server/services/markdown.js +79 -79
- package/server/services/menuRender.js +5 -5
- package/server/services/menus-migration.js +3 -3
- package/server/services/menus.js +31 -31
- package/server/services/permissionRegistry.js +1 -1
- package/server/services/pluginFiles.js +5 -5
- package/server/services/pluginInstaller.js +17 -17
- package/server/services/pluginScaffold.js +1 -1
- package/server/services/plugins.js +17 -17
- package/server/services/presetCollections.js +2 -2
- package/server/services/projects.js +35 -26
- package/server/services/recipes/contact-list.json +1 -1
- package/server/services/recipes/onboarding.json +8 -8
- package/server/services/references.js +8 -8
- package/server/services/renderer.js +9 -9
- package/server/services/roles.js +9 -9
- package/server/services/rowAccess.js +10 -10
- package/server/services/scaffolder.js +30 -30
- package/server/services/sidebar-migration.js +10 -10
- package/server/services/sitemap.js +1 -1
- package/server/services/userProfiles.js +199 -199
- package/server/services/userRoles.js +7 -7
- package/server/services/users.js +302 -302
- package/server/services/versions.js +3 -3
- package/server/services/viewPipeline.js +6 -6
- package/server/services/views.js +11 -11
- package/server/templates/page.html +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
import{api as h}from"../api.js";import{keepTableIconsAlive as _}from"../lib/table-icons.js";function O(e){return String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}let y=null,g=null,u=[],H=1,L=[],k={},b=[];const te=50,P={eq:"=",ne:"\u2260",contains:"contains",gt:">",lt:"<"};function U(e,r){const a=e.data?.[r.field],o=String(a??"");switch(r.op){case"eq":return o===String(r.value);case"ne":return o!==String(r.value);case"contains":return o.toLowerCase().includes(String(r.value).toLowerCase());case"gt":case"lt":{const c=parseFloat(o),t=parseFloat(r.value);if(!Number.isNaN(c)&&!Number.isNaN(t))return r.op==="gt"?c>t:c<t;const n=Date.parse(o),i=Date.parse(r.value);return!Number.isNaN(n)&&!Number.isNaN(i)?r.op==="gt"?n>i:n<i:r.op==="gt"?o>String(r.value):o<String(r.value)}default:return!0}}function x(e){const r=(e.find("#entry-search").get(0)?.value||"").toLowerCase().trim();let a=u;for(const o of b)a=a.filter(c=>U(c,o));r&&(a=a.filter(o=>Object.values(o.data||{}).some(c=>String(c).toLowerCase().includes(r)))),W(e),B(a,e)}function W(e){const r=e.find("#entry-filter-chips").get(0);if(!r)return;if(r.replaceChildren(),!b.length){r.style.display="none";return}r.style.display="flex",b.forEach((o,c)=>{const t=document.createElement("span");t.className="badge badge-secondary",t.style.cssText="display:inline-flex;align-items:center;gap:.35rem;font-size:.78rem;";const n=String(o.value);t.textContent=`${o.label} ${P[o.op]||o.op} \u201C${n.length>24?n.slice(0,24)+"\u2026":n}\u201D`;const i=document.createElement("button");i.type="button",i.textContent="\xD7",i.title="Remove filter",i.style.cssText="background:none;border:none;cursor:pointer;color:inherit;font-size:.9rem;line-height:1;padding:0;",i.addEventListener("click",()=>{b.splice(c,1),x(e)}),t.appendChild(i),r.appendChild(t)});const a=document.createElement("button");a.type="button",a.className="btn btn-ghost btn-sm",a.textContent="Clear all",a.addEventListener("click",()=>{b=[],x(e)}),r.appendChild(a)}let v=null;const J="position:fixed;z-index:10000;min-width:200px;max-height:60vh;overflow-y:auto;background:var(--dm-surface,#1c1c30);border:1px solid var(--dm-border,#2a2a40);border-radius:6px;box-shadow:var(--dm-shadow-lg);padding:.3rem;font-size:.83rem;color:var(--dm-text,#e5e5e5);",G="display:flex;align-items:center;gap:.5rem;width:100%;text-align:left;background:none;border:none;color:inherit;font:inherit;padding:.35rem .6rem;border-radius:4px;cursor:pointer;";function C(){v&&(v.remove(),v=null,document.removeEventListener("mousedown",A,!0),document.removeEventListener("keydown",j,!0),window.removeEventListener("scroll",z,!0))}const A=e=>{v&&!v.contains(e.target)&&C()},j=e=>{e.key==="Escape"&&C()},z=e=>{v&&!v.contains(e.target)&&C()};function N(e,r){const a=document.createElement("button");return a.type="button",a.style.cssText=G,a.textContent=e,a.addEventListener("mouseenter",()=>{a.style.background="var(--dm-surface-2,rgba(255,255,255,.06))"}),a.addEventListener("mouseleave",()=>{a.style.background="none"}),a.addEventListener("click",r),a}function V(e){const r=document.createElement("div");return r.style.cssText="padding:.3rem .6rem;font-size:.72rem;text-transform:uppercase;letter-spacing:.04em;color:var(--dm-text-muted,#9a9aac);",r.textContent=e,r}function K(e,r,a,o,c){C();const t=document.createElement("div");t.style.cssText=J,v=t;const n=a.label||a.name,i=String(o).length>28?String(o).slice(0,28)+"\u2026":String(o),l=(m,f)=>{b.push({field:a.name,label:n,op:m,value:f}),x(c),C()};t.appendChild(V(n)),o!==""&&(t.appendChild(N(`Filter: = \u201C${i}\u201D`,()=>l("eq",o))),t.appendChild(N(`Filter: \u2260 \u201C${i}\u201D`,()=>l("ne",o))),["number","date","time"].includes(a.type)&&(t.appendChild(N(`Filter: > \u201C${i}\u201D`,()=>l("gt",o))),t.appendChild(N(`Filter: < \u201C${i}\u201D`,()=>l("lt",o)))));const d=document.createElement("div");d.style.cssText="padding:.35rem .6rem;";const s=document.createElement("input");if(s.type="text",s.placeholder=`${n} contains\u2026`,s.className="form-input",s.style.cssText="width:100%;font-size:.8rem;padding:.3rem .5rem;",s.addEventListener("mousedown",m=>m.stopPropagation()),s.addEventListener("keydown",m=>{m.key==="Enter"&&s.value.trim()&&l("contains",s.value.trim())}),d.appendChild(s),t.appendChild(d),b.length){const m=document.createElement("div");m.style.cssText="border-top:1px solid var(--dm-border,#2a2a40);margin:.25rem 0;",t.appendChild(m),t.appendChild(N(`Clear all filters (${b.length})`,()=>{b=[],x(c),C()}))}document.body.appendChild(t);const p=t.getBoundingClientRect();t.style.left=Math.min(e,window.innerWidth-p.width-8)+"px",t.style.top=Math.min(r,window.innerHeight-p.height-8)+"px",document.addEventListener("mousedown",A,!0),document.addEventListener("keydown",j,!0),window.addEventListener("scroll",z,!0),setTimeout(()=>s.focus(),0)}export const collectionEntriesView={templateUrl:"/admin/js/templates/collection-entries.html",async onMount(e){u=[],H=1,g=null,L=[],k={},b=[],C();const a=window.location.hash.match(/\/collections\/([^/?#]+)\/entries/);if(y=a?a[1]:null,!y){E.toast("No collection selected.",{type:"error"});return}const o=E.loader(e.get(0),{type:"dots"});try{if(g=await h.collections.get(y),!g){o.destroy(),E.toast("Collection not found.",{type:"error"}),R.navigate("/collections");return}const t=e.find("#entries-title").get(0);t&&(t.textContent=g.title+" \u2014 Entries");const n=e.find("#edit-schema-btn").get(0);n&&n.setAttribute("href",`#/collections/edit/${y}`);const i=e.find("#form-btn").get(0);i&&(new Set(["roles","user-profiles"]).has(y)?i.style.display="none":i.setAttribute("href",`#/forms/edit/${y}`))}catch{o.destroy(),E.toast("Failed to load collection schema.",{type:"error"});return}try{L=await h.actions.forCollection(y)}catch{L=[]}try{await M(e)}finally{o.destroy()}await I(e);const c=e.find("#entry-search").get(0);c&&c.addEventListener("input",()=>x(e)),e.get(0).addEventListener("contextmenu",t=>{const n=t.target.closest("#entries-table tbody td");if(!n)return;const l=(g?.fields||[]).slice(0,5)[n.cellIndex];if(!l)return;t.preventDefault();const d=n.querySelector("span[title]")?.title??n.textContent.trim();K(t.clientX,t.clientY,l,d,e)}),e.find("#add-entry-btn").off("click").on("click",()=>{q(null,e)}),e.find("#export-btn").off("click").on("click",()=>{const t=E.slideover({title:"Export Entries",size:"sm",position:"right"}),n=document.createElement("div");n.style.cssText="padding:1.25rem;display:flex;flex-direction:column;gap:1rem;",["json","csv"].forEach(i=>{const l=document.createElement("button");l.className="btn btn-ghost",l.style.cssText="justify-content:flex-start;gap:.5rem;",l.textContent=i==="json"?"Export as JSON":"Export as CSV",l.addEventListener("click",()=>{fetch(`/api/collections/${y}/export?format=${i}`,{headers:{Authorization:`Bearer ${S.get("auth_token")||""}`}}).then(d=>d.blob()).then(d=>{const s=document.createElement("a");s.href=URL.createObjectURL(d),s.download=`${y}-entries.${i}`,document.body.appendChild(s),s.click(),document.body.removeChild(s),URL.revokeObjectURL(s.href),t.close()}).catch(()=>E.toast("Export failed.",{type:"error"}))}),n.appendChild(l)}),t.setContent(n),t.open()}),e.find("#import-btn").off("click").on("click",()=>{Q(e)}),e.find("#clear-all-btn").off("click").on("click",async()=>{if(await E.confirm("Delete ALL entries? This cannot be undone."))try{await h.collections.clearEntries(y),u=[],E.toast("All entries cleared.",{type:"success"}),x(e)}catch{E.toast("Failed to clear entries.",{type:"error"})}}),e.off("click",".js-run-action").on("click",".js-run-action",async function(t){t.stopPropagation();const n=this,{actionSlug:i,entryId:l,confirmMessage:d}=n.dataset;if(!(d&&!await E.confirm(d))){n.disabled=!0;try{const s=await h.actions.execute(i,l);if(s.success)E.toast(`Action completed (${s.stepsCompleted} step${s.stepsCompleted!==1?"s":""}).`,{type:"success"}),await M(e);else{const p=s.results?.find(m=>!m.success);E.toast(p?.error||"Action failed.",{type:"error"})}}catch(s){E.toast(s.message||"Action failed.",{type:"error"})}finally{n.disabled=!1}}}),e.off("click",".js-edit-entry").on("click",".js-edit-entry",function(t){t.stopPropagation();const n=u.find(i=>i.id===this.dataset.id);n&&q(n,e)}),e.off("click",".js-delete-entry").on("click",".js-delete-entry",async function(t){t.stopPropagation();const n=this.dataset.id;if(await E.confirm("Delete this entry?"))try{await h.collections.deleteEntry(y,n),u=u.filter(l=>l.id!==n),E.toast("Entry deleted.",{type:"success"}),x(e)}catch{E.toast("Failed to delete entry.",{type:"error"})}}),e.off("click","#entries-table tbody tr").on("click","#entries-table tbody tr",function(t){if(t.target.closest(".js-run-action, .js-edit-entry, .js-delete-entry"))return;const n=this.querySelector(".js-edit-entry")?.dataset.id,i=u.find(l=>l.id===n);i&&Z(i)}),Domma.icons.scan(),_(e.get(0))}};async function I(e){const r=L.filter(o=>o.access?.rowLevel);if(r.length===0)return;const a=u.map(o=>o.id);a.length!==0&&(await Promise.all(r.map(async o=>{try{const{allowed:c}=await h.actions.checkAccess(o.slug,a);k[o.slug]=new Set(c)}catch{k[o.slug]=null}})),x(e))}async function M(e){try{const r=await h.collections.listEntries(y,{limit:500});u=r.entries||r||[]}catch{u=[],E.toast("Could not load entries.",{type:"error"})}x(e),await I(e)}function B(e,r){const a=r.find("#entry-count").get(0);a&&(a.textContent=e.length===u.length?`${u.length} entr${u.length!==1?"ies":"y"}`:`Showing ${e.length} of ${u.length}`);const c=[...(g?.fields||[]).slice(0,5).map(n=>({key:`data.${n.name}`,title:n.label||n.name,render:(i,l)=>{const d=l.data?.[n.name]??"",s=String(d),p=document.createElement("span");return p.title=s,p.textContent=s.length>60?s.slice(0,60)+"\u2026":s,p.outerHTML}})),{key:"meta",title:"Created",render:n=>D(n?.createdAt).format("DD MMM YYYY HH:mm")},{key:"id",title:"",render:n=>{const i=document.createElement("div");i.style.cssText="display:flex;gap:.3rem;justify-content:flex-end;flex-wrap:wrap;",L.forEach(s=>{if(k[s.slug]!==void 0&&k[s.slug]!==null&&!k[s.slug].has(n))return;const p=document.createElement("button");p.className="btn btn-sm btn-ghost js-run-action",p.dataset.actionSlug=s.slug,p.dataset.entryId=n,p.dataset.confirmMessage=s.trigger?.confirmMessage||"",p.title=s.title||s.slug;const m=document.createElement("span");m.setAttribute("data-icon",O(s.trigger?.icon||"zap")),m.setAttribute("data-icon-size","14"),p.appendChild(m),p.appendChild(document.createTextNode(" "+(s.trigger?.label||s.title))),i.appendChild(p)});const l=document.createElement("button");l.className="btn btn-sm btn-ghost js-edit-entry",l.dataset.id=n,l.setAttribute("data-tooltip","Edit"),l.innerHTML='<span data-icon="edit" data-icon-size="14"></span>';const d=document.createElement("button");return d.className="btn btn-sm btn-ghost js-delete-entry",d.dataset.id=n,d.setAttribute("data-tooltip","Delete"),d.innerHTML='<span data-icon="trash" data-icon-size="14"></span>',i.appendChild(l),i.appendChild(d),i.outerHTML}}];T.create("#entries-table",{data:e,columns:c,emptyMessage:'No entries yet. Click "Add Entry" to get started.'});const t=document.querySelector("#entries-table");t&&(t.querySelectorAll("tbody tr").forEach(n=>{n.style.cursor="pointer"}),Domma.icons.scan(t),t.querySelectorAll("[data-tooltip]").forEach(n=>{E.tooltip(n,{content:n.getAttribute("data-tooltip"),position:"top"})}))}function X(e,r){const a={};return e.forEach(o=>{const c={};o.fullWidth?c.span=r:o.span>1&&(c.span=o.span),o.placeholder&&(c.placeholder=o.placeholder),o.helper&&(c.hint=o.helper);const t=o.type==="checkbox"?"boolean":o.type==="date"?"string":o.type;a[o.name]={type:t,label:o.label,required:o.required,options:o.options,...Object.keys(c).length?{formConfig:c}:{}}}),a}function q(e,r){const a=!!e,o=E.slideover({title:a?"Edit Entry":"Add Entry",size:"md",position:"right"}),c=document.createElement("div");c.style.cssText="padding:.25rem 0 .5rem;";const t=g?.fields||[],n=g?.columns||2,i=g?.layout||"stacked",l=document.createElement("div");F.create(X(t,n),e?.data||{},{layout:i,columns:n,showSubmitButton:!1}).renderTo(l),(t||[]).forEach(m=>{if(m.type!=="date"||!m.name)return;const f=l.querySelector(`[name="${m.name}"]`);f&&f.type!=="date"&&(f.type="date")}),c.appendChild(l);const d=document.createElement("div");d.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:.5rem;";const s=document.createElement("button");s.className="btn btn-ghost",s.textContent="Cancel";const p=document.createElement("button");p.className="btn btn-primary",p.textContent=a?"Save Changes":"Add Entry",d.appendChild(s),d.appendChild(p),c.appendChild(d),o.element.appendChild(c),o.open(),s.addEventListener("click",()=>o.close()),p.addEventListener("click",async()=>{const m={};t.forEach(f=>{const w=l.querySelector(`[name="${f.name}"]`);w&&(m[f.name]=f.type==="checkbox"?w.checked:w.value)}),p.disabled=!0;try{if(a){const f=await h.collections.updateEntry(y,e.id,m),w=u.findIndex(Y=>Y.id===e.id);w!==-1&&(u[w]=f),E.toast("Entry updated.",{type:"success"})}else{const f=await h.collections.createEntry(y,m);u.unshift(f),E.toast("Entry added.",{type:"success"})}o.close(),r?x(r):B(u,{find:()=>({get:()=>null})})}catch(f){E.toast(f.message||"Failed to save entry.",{type:"error"}),p.disabled=!1}})}function Z(e){const r=document.createElement("div"),a=g?.fields||[],o=document.createElement("div");o.style.cssText="display:flex;flex-direction:column;gap:.75rem;margin-bottom:1.25rem;",a.forEach(n=>{const i=e.data?.[n.name];if(i==null||i==="")return;const l=document.createElement("div");l.style.cssText="border-bottom:1px solid var(--dm-border,#333);padding-bottom:.6rem;";const d=document.createElement("strong");d.textContent=n.label||n.name,d.style.cssText="display:block;font-size:.8rem;color:var(--dm-text-muted,#888);margin-bottom:.2rem;";const s=document.createElement("p");s.textContent=String(i),s.style.cssText="margin:0;word-break:break-word;",l.appendChild(d),l.appendChild(s),o.appendChild(l)});const c=document.createElement("div");if(c.style.cssText="font-size:.8rem;color:var(--dm-text-muted,#888);display:flex;flex-direction:column;gap:.3rem;border-top:1px solid var(--dm-border,#333);padding-top:.75rem;",e.meta?.createdAt){const n=document.createElement("span");n.textContent=`Created: ${D(e.meta.createdAt).format("DD MMM YYYY HH:mm")}`,c.appendChild(n)}if(e.meta?.source){const n=document.createElement("span");n.textContent=`Source: ${e.meta.source}`,c.appendChild(n)}r.appendChild(o),r.appendChild(c);const t=E.slideover({title:"Entry Details",size:"md",position:"right"});t.element.appendChild(r),t.open()}function Q(e){const r=E.slideover({title:"Import Entries",size:"md",position:"right"}),a=document.createElement("div");a.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const o=document.createElement("p");o.textContent='Paste a JSON array of entries. Each item should have a "data" object with field values.',o.style.cssText="font-size:.875rem;color:var(--dm-text-muted,#888);margin:0;",a.appendChild(o);const c=document.createElement("textarea");c.className="form-input",c.rows=10,c.placeholder='[{"data": {"name": "Example"}}, ...]',a.appendChild(c);const t=document.createElement("p");t.style.cssText="font-size:.875rem;margin:0;display:none;",a.appendChild(t);const n=document.createElement("div");n.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;";const i=document.createElement("button");i.className="btn btn-ghost",i.textContent="Cancel";const l=document.createElement("button");l.className="btn btn-primary",l.textContent="Import",n.appendChild(i),n.appendChild(l),a.appendChild(n),r.element.appendChild(a),r.open(),i.addEventListener("click",()=>r.close()),l.addEventListener("click",async()=>{let d;try{if(d=JSON.parse(c.value),!Array.isArray(d))throw new Error("Must be a JSON array")}catch(s){t.style.display="",t.style.color="var(--dm-danger,#f87171)",t.textContent=`Invalid JSON: ${s.message}`;return}l.disabled=!0;try{const s=await h.collections.import(y,d);t.style.display="",t.style.color="var(--dm-success,#4ade80)",t.textContent=`Imported ${s.imported} entries. Skipped: ${s.skipped}.`,await M(e||{find:()=>({get:()=>null,off:()=>({on:()=>{}})})}),setTimeout(()=>r.close(),1500)}catch(s){t.style.display="",t.style.color="var(--dm-danger,#f87171)",t.textContent=s.message||"Import failed."}finally{l.disabled=!1}})}
|
|
1
|
+
import{api as h}from"../api.js";import{keepTableIconsAlive as _}from"../lib/table-icons.js";function O(e){return String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}let y=null,g=null,u=[],H=1,L=[],k={},b=[];const te=50,P={eq:"=",ne:"\u2260",contains:"contains",gt:">",lt:"<"};function U(e,r){const a=e.data?.[r.field],o=String(a??"");switch(r.op){case"eq":return o===String(r.value);case"ne":return o!==String(r.value);case"contains":return o.toLowerCase().includes(String(r.value).toLowerCase());case"gt":case"lt":{const c=parseFloat(o),t=parseFloat(r.value);if(!Number.isNaN(c)&&!Number.isNaN(t))return r.op==="gt"?c>t:c<t;const n=Date.parse(o),i=Date.parse(r.value);return!Number.isNaN(n)&&!Number.isNaN(i)?r.op==="gt"?n>i:n<i:r.op==="gt"?o>String(r.value):o<String(r.value)}default:return!0}}function x(e){const r=(e.find("#entry-search").get(0)?.value||"").toLowerCase().trim();let a=u;for(const o of b)a=a.filter(c=>U(c,o));r&&(a=a.filter(o=>Object.values(o.data||{}).some(c=>String(c).toLowerCase().includes(r)))),W(e),B(a,e)}function W(e){const r=e.find("#entry-filter-chips").get(0);if(!r)return;if(r.replaceChildren(),!b.length){r.style.display="none";return}r.style.display="flex",b.forEach((o,c)=>{const t=document.createElement("span");t.className="badge badge-secondary",t.style.cssText="display:inline-flex;align-items:center;gap:.35rem;font-size:.78rem;";const n=String(o.value);t.textContent=`${o.label} ${P[o.op]||o.op} \u201C${n.length>24?n.slice(0,24)+"\u2026":n}\u201D`;const i=document.createElement("button");i.type="button",i.textContent="\xD7",i.title="Remove filter",i.style.cssText="background:none;border:none;cursor:pointer;color:inherit;font-size:.9rem;line-height:1;padding:0;",i.addEventListener("click",()=>{b.splice(c,1),x(e)}),t.appendChild(i),r.appendChild(t)});const a=document.createElement("button");a.type="button",a.className="btn btn-ghost btn-sm",a.textContent="Clear all",a.addEventListener("click",()=>{b=[],x(e)}),r.appendChild(a)}let v=null;const J="position:fixed;z-index:10000;min-width:200px;max-height:60vh;overflow-y:auto;background:var(--dm-surface,#1c1c30);border:1px solid var(--dm-border,#2a2a40);border-radius:6px;box-shadow:var(--dm-shadow-lg);padding:.3rem;font-size:.83rem;color:var(--dm-text,#e5e5e5);",G="display:flex;align-items:center;gap:.5rem;width:100%;text-align:left;background:none;border:none;color:inherit;font:inherit;padding:.35rem .6rem;border-radius:4px;cursor:pointer;";function C(){v&&(v.remove(),v=null,document.removeEventListener("mousedown",A,!0),document.removeEventListener("keydown",j,!0),window.removeEventListener("scroll",z,!0))}const A=e=>{v&&!v.contains(e.target)&&C()},j=e=>{e.key==="Escape"&&C()},z=e=>{v&&!v.contains(e.target)&&C()};function N(e,r){const a=document.createElement("button");return a.type="button",a.style.cssText=G,a.textContent=e,a.addEventListener("mouseenter",()=>{a.style.background="var(--dm-surface-2,rgba(255,255,255,.06))"}),a.addEventListener("mouseleave",()=>{a.style.background="none"}),a.addEventListener("click",r),a}function V(e){const r=document.createElement("div");return r.style.cssText="padding:.3rem .6rem;font-size:.72rem;text-transform:uppercase;letter-spacing:.04em;color:var(--dm-text-muted,#9a9aac);",r.textContent=e,r}function K(e,r,a,o,c){C();const t=document.createElement("div");t.style.cssText=J,v=t;const n=a.label||a.name,i=String(o).length>28?String(o).slice(0,28)+"\u2026":String(o),l=(m,f)=>{b.push({field:a.name,label:n,op:m,value:f}),x(c),C()};t.appendChild(V(n)),o!==""&&(t.appendChild(N(`Filter: = \u201C${i}\u201D`,()=>l("eq",o))),t.appendChild(N(`Filter: \u2260 \u201C${i}\u201D`,()=>l("ne",o))),["number","date","time"].includes(a.type)&&(t.appendChild(N(`Filter: > \u201C${i}\u201D`,()=>l("gt",o))),t.appendChild(N(`Filter: < \u201C${i}\u201D`,()=>l("lt",o)))));const d=document.createElement("div");d.style.cssText="padding:.35rem .6rem;";const s=document.createElement("input");if(s.type="text",s.placeholder=`${n} contains\u2026`,s.className="form-input",s.style.cssText="width:100%;font-size:.8rem;padding:.3rem .5rem;",s.addEventListener("mousedown",m=>m.stopPropagation()),s.addEventListener("keydown",m=>{m.key==="Enter"&&s.value.trim()&&l("contains",s.value.trim())}),d.appendChild(s),t.appendChild(d),b.length){const m=document.createElement("div");m.style.cssText="border-top:1px solid var(--dm-border,#2a2a40);margin:.25rem 0;",t.appendChild(m),t.appendChild(N(`Clear all filters (${b.length})`,()=>{b=[],x(c),C()}))}document.body.appendChild(t);const p=t.getBoundingClientRect();t.style.left=Math.min(e,window.innerWidth-p.width-8)+"px",t.style.top=Math.min(r,window.innerHeight-p.height-8)+"px",document.addEventListener("mousedown",A,!0),document.addEventListener("keydown",j,!0),window.addEventListener("scroll",z,!0),setTimeout(()=>s.focus(),0)}export const collectionEntriesView={templateUrl:"/admin/js/templates/collection-entries.html",async onMount(e){u=[],H=1,g=null,L=[],k={},b=[],C();const a=window.location.hash.match(/\/collections\/([^/?#]+)\/entries/);if(y=a?a[1]:null,!y){E.toast("No collection selected.",{type:"error"});return}const o=E.loader(e.get(0),{type:"dots"});try{if(g=await h.collections.get(y),!g){o.destroy(),E.toast("Collection not found.",{type:"error"}),R.navigate("/collections");return}const t=e.find("#entries-title").get(0);t&&(t.textContent=g.title+" - Entries");const n=e.find("#edit-schema-btn").get(0);n&&n.setAttribute("href",`#/collections/edit/${y}`);const i=e.find("#form-btn").get(0);i&&(new Set(["roles","user-profiles"]).has(y)?i.style.display="none":i.setAttribute("href",`#/forms/edit/${y}`))}catch{o.destroy(),E.toast("Failed to load collection schema.",{type:"error"});return}try{L=await h.actions.forCollection(y)}catch{L=[]}try{await M(e)}finally{o.destroy()}await I(e);const c=e.find("#entry-search").get(0);c&&c.addEventListener("input",()=>x(e)),e.get(0).addEventListener("contextmenu",t=>{const n=t.target.closest("#entries-table tbody td");if(!n)return;const l=(g?.fields||[]).slice(0,5)[n.cellIndex];if(!l)return;t.preventDefault();const d=n.querySelector("span[title]")?.title??n.textContent.trim();K(t.clientX,t.clientY,l,d,e)}),e.find("#add-entry-btn").off("click").on("click",()=>{q(null,e)}),e.find("#export-btn").off("click").on("click",()=>{const t=E.slideover({title:"Export Entries",size:"sm",position:"right"}),n=document.createElement("div");n.style.cssText="padding:1.25rem;display:flex;flex-direction:column;gap:1rem;",["json","csv"].forEach(i=>{const l=document.createElement("button");l.className="btn btn-ghost",l.style.cssText="justify-content:flex-start;gap:.5rem;",l.textContent=i==="json"?"Export as JSON":"Export as CSV",l.addEventListener("click",()=>{fetch(`/api/collections/${y}/export?format=${i}`,{headers:{Authorization:`Bearer ${S.get("auth_token")||""}`}}).then(d=>d.blob()).then(d=>{const s=document.createElement("a");s.href=URL.createObjectURL(d),s.download=`${y}-entries.${i}`,document.body.appendChild(s),s.click(),document.body.removeChild(s),URL.revokeObjectURL(s.href),t.close()}).catch(()=>E.toast("Export failed.",{type:"error"}))}),n.appendChild(l)}),t.setContent(n),t.open()}),e.find("#import-btn").off("click").on("click",()=>{Q(e)}),e.find("#clear-all-btn").off("click").on("click",async()=>{if(await E.confirm("Delete ALL entries? This cannot be undone."))try{await h.collections.clearEntries(y),u=[],E.toast("All entries cleared.",{type:"success"}),x(e)}catch{E.toast("Failed to clear entries.",{type:"error"})}}),e.off("click",".js-run-action").on("click",".js-run-action",async function(t){t.stopPropagation();const n=this,{actionSlug:i,entryId:l,confirmMessage:d}=n.dataset;if(!(d&&!await E.confirm(d))){n.disabled=!0;try{const s=await h.actions.execute(i,l);if(s.success)E.toast(`Action completed (${s.stepsCompleted} step${s.stepsCompleted!==1?"s":""}).`,{type:"success"}),await M(e);else{const p=s.results?.find(m=>!m.success);E.toast(p?.error||"Action failed.",{type:"error"})}}catch(s){E.toast(s.message||"Action failed.",{type:"error"})}finally{n.disabled=!1}}}),e.off("click",".js-edit-entry").on("click",".js-edit-entry",function(t){t.stopPropagation();const n=u.find(i=>i.id===this.dataset.id);n&&q(n,e)}),e.off("click",".js-delete-entry").on("click",".js-delete-entry",async function(t){t.stopPropagation();const n=this.dataset.id;if(await E.confirm("Delete this entry?"))try{await h.collections.deleteEntry(y,n),u=u.filter(l=>l.id!==n),E.toast("Entry deleted.",{type:"success"}),x(e)}catch{E.toast("Failed to delete entry.",{type:"error"})}}),e.off("click","#entries-table tbody tr").on("click","#entries-table tbody tr",function(t){if(t.target.closest(".js-run-action, .js-edit-entry, .js-delete-entry"))return;const n=this.querySelector(".js-edit-entry")?.dataset.id,i=u.find(l=>l.id===n);i&&Z(i)}),Domma.icons.scan(),_(e.get(0))}};async function I(e){const r=L.filter(o=>o.access?.rowLevel);if(r.length===0)return;const a=u.map(o=>o.id);a.length!==0&&(await Promise.all(r.map(async o=>{try{const{allowed:c}=await h.actions.checkAccess(o.slug,a);k[o.slug]=new Set(c)}catch{k[o.slug]=null}})),x(e))}async function M(e){try{const r=await h.collections.listEntries(y,{limit:500});u=r.entries||r||[]}catch{u=[],E.toast("Could not load entries.",{type:"error"})}x(e),await I(e)}function B(e,r){const a=r.find("#entry-count").get(0);a&&(a.textContent=e.length===u.length?`${u.length} entr${u.length!==1?"ies":"y"}`:`Showing ${e.length} of ${u.length}`);const c=[...(g?.fields||[]).slice(0,5).map(n=>({key:`data.${n.name}`,title:n.label||n.name,render:(i,l)=>{const d=l.data?.[n.name]??"",s=String(d),p=document.createElement("span");return p.title=s,p.textContent=s.length>60?s.slice(0,60)+"\u2026":s,p.outerHTML}})),{key:"meta",title:"Created",render:n=>D(n?.createdAt).format("DD MMM YYYY HH:mm")},{key:"id",title:"",render:n=>{const i=document.createElement("div");i.style.cssText="display:flex;gap:.3rem;justify-content:flex-end;flex-wrap:wrap;",L.forEach(s=>{if(k[s.slug]!==void 0&&k[s.slug]!==null&&!k[s.slug].has(n))return;const p=document.createElement("button");p.className="btn btn-sm btn-ghost js-run-action",p.dataset.actionSlug=s.slug,p.dataset.entryId=n,p.dataset.confirmMessage=s.trigger?.confirmMessage||"",p.title=s.title||s.slug;const m=document.createElement("span");m.setAttribute("data-icon",O(s.trigger?.icon||"zap")),m.setAttribute("data-icon-size","14"),p.appendChild(m),p.appendChild(document.createTextNode(" "+(s.trigger?.label||s.title))),i.appendChild(p)});const l=document.createElement("button");l.className="btn btn-sm btn-ghost js-edit-entry",l.dataset.id=n,l.setAttribute("data-tooltip","Edit"),l.innerHTML='<span data-icon="edit" data-icon-size="14"></span>';const d=document.createElement("button");return d.className="btn btn-sm btn-ghost js-delete-entry",d.dataset.id=n,d.setAttribute("data-tooltip","Delete"),d.innerHTML='<span data-icon="trash" data-icon-size="14"></span>',i.appendChild(l),i.appendChild(d),i.outerHTML}}];T.create("#entries-table",{pageSize:25,data:e,columns:c,emptyMessage:'No entries yet. Click "Add Entry" to get started.'});const t=document.querySelector("#entries-table");t&&(t.querySelectorAll("tbody tr").forEach(n=>{n.style.cursor="pointer"}),Domma.icons.scan(t),t.querySelectorAll("[data-tooltip]").forEach(n=>{E.tooltip(n,{content:n.getAttribute("data-tooltip"),position:"top"})}))}function X(e,r){const a={};return e.forEach(o=>{const c={};o.fullWidth?c.span=r:o.span>1&&(c.span=o.span),o.placeholder&&(c.placeholder=o.placeholder),o.helper&&(c.hint=o.helper);const t=o.type==="checkbox"?"boolean":o.type==="date"?"string":o.type;a[o.name]={type:t,label:o.label,required:o.required,options:o.options,...Object.keys(c).length?{formConfig:c}:{}}}),a}function q(e,r){const a=!!e,o=E.slideover({title:a?"Edit Entry":"Add Entry",size:"md",position:"right"}),c=document.createElement("div");c.style.cssText="padding:.25rem 0 .5rem;";const t=g?.fields||[],n=g?.columns||2,i=g?.layout||"stacked",l=document.createElement("div");F.create(X(t,n),e?.data||{},{layout:i,columns:n,showSubmitButton:!1}).renderTo(l),(t||[]).forEach(m=>{if(m.type!=="date"||!m.name)return;const f=l.querySelector(`[name="${m.name}"]`);f&&f.type!=="date"&&(f.type="date")}),c.appendChild(l);const d=document.createElement("div");d.style.cssText="display:flex;justify-content:flex-end;gap:1rem;margin-top:.5rem;";const s=document.createElement("button");s.className="btn btn-ghost",s.textContent="Cancel";const p=document.createElement("button");p.className="btn btn-primary",p.textContent=a?"Save Changes":"Add Entry",d.appendChild(s),d.appendChild(p),c.appendChild(d),o.element.appendChild(c),o.open(),s.addEventListener("click",()=>o.close()),p.addEventListener("click",async()=>{const m={};t.forEach(f=>{const w=l.querySelector(`[name="${f.name}"]`);w&&(m[f.name]=f.type==="checkbox"?w.checked:w.value)}),p.disabled=!0;try{if(a){const f=await h.collections.updateEntry(y,e.id,m),w=u.findIndex(Y=>Y.id===e.id);w!==-1&&(u[w]=f),E.toast("Entry updated.",{type:"success"})}else{const f=await h.collections.createEntry(y,m);u.unshift(f),E.toast("Entry added.",{type:"success"})}o.close(),r?x(r):B(u,{find:()=>({get:()=>null})})}catch(f){E.toast(f.message||"Failed to save entry.",{type:"error"}),p.disabled=!1}})}function Z(e){const r=document.createElement("div"),a=g?.fields||[],o=document.createElement("div");o.style.cssText="display:flex;flex-direction:column;gap:.75rem;margin-bottom:1.25rem;",a.forEach(n=>{const i=e.data?.[n.name];if(i==null||i==="")return;const l=document.createElement("div");l.style.cssText="border-bottom:1px solid var(--dm-border,#333);padding-bottom:.6rem;";const d=document.createElement("strong");d.textContent=n.label||n.name,d.style.cssText="display:block;font-size:.8rem;color:var(--dm-text-muted,#888);margin-bottom:.2rem;";const s=document.createElement("p");s.textContent=String(i),s.style.cssText="margin:0;word-break:break-word;",l.appendChild(d),l.appendChild(s),o.appendChild(l)});const c=document.createElement("div");if(c.style.cssText="font-size:.8rem;color:var(--dm-text-muted,#888);display:flex;flex-direction:column;gap:.3rem;border-top:1px solid var(--dm-border,#333);padding-top:.75rem;",e.meta?.createdAt){const n=document.createElement("span");n.textContent=`Created: ${D(e.meta.createdAt).format("DD MMM YYYY HH:mm")}`,c.appendChild(n)}if(e.meta?.source){const n=document.createElement("span");n.textContent=`Source: ${e.meta.source}`,c.appendChild(n)}r.appendChild(o),r.appendChild(c);const t=E.slideover({title:"Entry Details",size:"md",position:"right"});t.element.appendChild(r),t.open()}function Q(e){const r=E.slideover({title:"Import Entries",size:"md",position:"right"}),a=document.createElement("div");a.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const o=document.createElement("p");o.textContent='Paste a JSON array of entries. Each item should have a "data" object with field values.',o.style.cssText="font-size:.875rem;color:var(--dm-text-muted,#888);margin:0;",a.appendChild(o);const c=document.createElement("textarea");c.className="form-input",c.rows=10,c.placeholder='[{"data": {"name": "Example"}}, ...]',a.appendChild(c);const t=document.createElement("p");t.style.cssText="font-size:.875rem;margin:0;display:none;",a.appendChild(t);const n=document.createElement("div");n.style.cssText="display:flex;justify-content:flex-end;gap:1rem;";const i=document.createElement("button");i.className="btn btn-ghost",i.textContent="Cancel";const l=document.createElement("button");l.className="btn btn-primary",l.textContent="Import",n.appendChild(i),n.appendChild(l),a.appendChild(n),r.element.appendChild(a),r.open(),i.addEventListener("click",()=>r.close()),l.addEventListener("click",async()=>{let d;try{if(d=JSON.parse(c.value),!Array.isArray(d))throw new Error("Must be a JSON array")}catch(s){t.style.display="",t.style.color="var(--dm-danger,#f87171)",t.textContent=`Invalid JSON: ${s.message}`;return}l.disabled=!0;try{const s=await h.collections.import(y,d);t.style.display="",t.style.color="var(--dm-success,#4ade80)",t.textContent=`Imported ${s.imported} entries. Skipped: ${s.skipped}.`,await M(e||{find:()=>({get:()=>null,off:()=>({on:()=>{}})})}),setTimeout(()=>r.close(),1500)}catch(s){t.style.display="",t.style.color="var(--dm-danger,#f87171)",t.textContent=s.message||"Import failed."}finally{l.disabled=!1}})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{api as y}from"../api.js";import{filterByProject as
|
|
1
|
+
import{api as y}from"../api.js";import{filterByProject as B,getProjectFromHash as M,renderProjectFilterNotice as A}from"../lib/project-context.js";import{keepTableIconsAlive as H}from"../lib/table-icons.js";function h(e){return String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}let d={};export const collectionsView={templateUrl:"/admin/js/templates/collections.html",async onMount(e){const l=E.loader(e.get(0),{type:"dots"});E.tabs(e.find("#collections-tabs").get(0));const p=e.find("#collections-tabs").get(0)?.querySelector(".tab-list");if(p){const t=e.find("#collections-header-actions").get(0);Array.from(p.querySelectorAll(".tab-item")).forEach((n,c)=>{n.addEventListener("click",()=>{t&&(t.style.display=c===0?"":"none")})})}await Promise.all([j(e),q(e)]),l.destroy(),H(e.get(0)),e.off("click",".js-delete-collection").on("click",".js-delete-collection",async function(){const t=this.dataset.slug,n=this.dataset.plugin,c=n?`This collection is managed by the <strong>${n}</strong> plugin. Deleting it may cause the plugin to malfunction. Continue?`:`Delete collection "${t}" and all its data? This cannot be undone.`;if(await E.confirm(c))try{await y.collections.delete(t),E.toast("Collection deleted.",{type:"success"}),await j(e)}catch{E.toast("Failed to delete collection.",{type:"error"})}}),e.find("#create-collection-btn").off("click").on("click",()=>{const t=E.slideover({title:"New Collection",size:"sm",position:"right"}),n=document.createElement("div");n.style.cssText="padding:.25rem 0 .5rem;";const c=document.createElement("div");F.create({title:{type:"string",label:"Collection Title",placeholder:"e.g. Products, Blog Posts\u2026",required:!0}},{},{showSubmitButton:!1}).renderTo(c),n.appendChild(c);const a=document.createElement("div");a.style.cssText="display:flex;justify-content:flex-end;gap:1rem;margin-top:.75rem;";const o=document.createElement("button");o.className="btn btn-ghost",o.textContent="Cancel";const r=document.createElement("button");r.className="btn btn-primary",r.textContent="Create",a.appendChild(o),a.appendChild(r),n.appendChild(a),t.element.appendChild(n),t.open();const s=c.querySelector('input[name="title"]');setTimeout(()=>s?.focus(),50);async function i(){const m=s?.value.trim();if(m)try{const u=await y.collections.create({title:m});t.close(),R.navigate(`/collections/edit/${u.slug}`)}catch(u){E.toast(u.message||"Failed to create collection.",{type:"error"})}}o.addEventListener("click",()=>t.close()),r.addEventListener("click",i),s?.addEventListener("keydown",m=>{m.key==="Enter"&&i()})}),e.find("#connections-raw-toggle").on("change",function(){if(this.checked)d=x(e),v(e),e.find("#connections-form-view").hide(),e.find("#connections-raw-view").show();else{const t=e.find("#connections-raw-json").get(0)?.value||"{}";try{d=JSON.parse(t),C(e),e.find("#connections-form-view").show(),e.find("#connections-raw-view").hide()}catch{E.toast("Invalid JSON - fix before switching to form view.",{type:"warning"}),this.checked=!0}}}),e.find("#add-connection-btn").on("click",()=>{d=x(e);let t=Object.keys(d).length+1,n=`connection${t}`;for(;d[n];)t++,n=`connection${t}`;d[n]={type:"mongodb",uri:"",database:"",options:{}},C(e),v(e)}),e.find("#save-connections-btn").on("click",async()=>{const t=e.find("#connections-raw-toggle").get(0)?.checked;let n;if(t)try{n=JSON.parse(e.find("#connections-raw-json").get(0)?.value||"{}")}catch{E.toast("Invalid JSON - fix before saving.",{type:"warning"});return}else n=x(e);try{await y.collections.saveConnections(n),d=n,E.toast("Connections saved.",{type:"success"})}catch(c){E.toast(c.message||"Failed to save connections.",{type:"error"})}}),Domma.icons.scan()}};async function j(e){let l=[];try{l=await y.collections.list()}catch{E.toast("Could not load collections.",{type:"error"})}const p=M();if(p){const t=l.length;l=B(l,p),A(e,{total:t,shown:l.length,slug:p,allHref:"#/collections",noun:"collections"})}T.create("#collections-table",{pageSize:25,data:l,columns:[{key:"title",title:"Title",render:(t,n)=>{const c=document.createElement("span");c.style.cssText="display:flex;align-items:center;gap:.4rem;";const a=document.createElement("a");if(a.href=`#/collections/${h(n.slug)}/entries`,a.textContent=t,a.style.fontWeight="600",c.appendChild(a),n.storage?.adapter==="mongodb"){const o=document.createElement("span");o.className="badge badge-outline",o.textContent="MongoDB",o.title=`Connection: ${n.storage.connection||"default"}`,o.style.cssText="font-size:0.65rem;padding:1px 6px;color:var(--dm-success,#16a34a);border-color:var(--dm-success,#16a34a);flex-shrink:0;",c.appendChild(o)}if(n.bundled){const o=document.createElement("span");o.className="badge badge-outline",o.textContent="Bundled",o.title="Seeded on fresh installs",o.style.cssText="font-size:0.65rem;padding:1px 6px;color:var(--dm-info,#2563eb);border-color:var(--dm-info,#2563eb);flex-shrink:0;",c.appendChild(o)}if(n.plugin){const o=document.createElement("span");o.className="badge badge-outline",o.textContent=n.plugin,o.title=`Managed by the ${n.plugin} plugin`,o.style.cssText="font-size:0.65rem;padding:1px 6px;color:var(--dm-warning,#d97706);border-color:var(--dm-warning,#d97706);flex-shrink:0;",c.appendChild(o)}return c.outerHTML}},{key:"slug",title:"Slug",render:t=>{const n=document.createElement("code");return n.textContent=t,n.outerHTML}},{key:"fields",title:"Field Count",render:t=>String(t?.length??0)},{key:"entryCount",title:"Entry Count",render:t=>String(t??0)},{key:"slug",title:"Actions",render:(t,n)=>{const c=document.createElement("div");c.style.cssText="display:flex;gap:.4rem;justify-content:flex-end;flex-wrap:wrap;";const a=document.createElement("a");a.href=`#/collections/edit/${h(t)}`,a.className="btn btn-sm btn-ghost",a.setAttribute("data-tooltip","Edit schema"),a.innerHTML='<span data-icon="edit-3" data-icon-size="14"></span>';const o=document.createElement("a");if(o.href=`#/collections/${h(t)}/entries`,o.className="btn btn-sm btn-ghost",o.setAttribute("data-tooltip","Entries"),o.innerHTML='<span data-icon="database" data-icon-size="14"></span>',c.appendChild(a),c.appendChild(o),!new Set(["roles","user-profiles"]).has(t)){const i=document.createElement("a");i.href=`#/forms/edit/${h(t)}`,i.className="btn btn-sm btn-ghost",i.setAttribute("data-tooltip","Form"),i.innerHTML='<span data-icon="layout" data-icon-size="14"></span>',c.appendChild(i)}const s=document.createElement("button");return s.className="btn btn-sm btn-ghost js-delete-collection",s.dataset.slug=t,s.dataset.plugin=n.plugin||"",s.setAttribute("data-tooltip","Delete"),s.innerHTML='<span data-icon="trash" data-icon-size="14"></span>',c.appendChild(s),c.outerHTML}}],emptyMessage:'No collections yet. Click "New Collection" to get started.'}),Domma.icons.scan(),document.querySelectorAll("#collections-table [data-tooltip]").forEach(t=>{E.tooltip(t,{content:t.getAttribute("data-tooltip"),position:"top"})})}async function q(e){try{d=await y.collections.getConnections()}catch{d={}}C(e),v(e)}function C(e){const l=e.find("#connections-list").get(0),p=e.find("#connections-empty").get(0);if(!l)return;l.textContent="";const t=Object.keys(d);p&&(p.style.display=t.length?"none":""),t.forEach(n=>{const c=d[n],a=document.createElement("div");a.className="conn-card card mb-3",a.dataset.connKey=n;const o=document.createElement("div");o.className="card-header",o.style.cssText="display:flex;align-items:center;gap:.5rem;";const r=document.createElement("input");r.type="text",r.className="form-input conn-name",r.value=n,r.placeholder="Connection name",r.style.cssText="flex:1;";const s=document.createElement("button");s.type="button",s.className="btn btn-sm btn-ghost",s.title="Delete connection",s.innerHTML='<span data-icon="trash"></span>',s.addEventListener("click",()=>{d=x(e);const L=r.value.trim();L&&delete d[L],C(e),v(e)}),o.appendChild(r),o.appendChild(s);const i=document.createElement("div");i.className="card-body",i.style.cssText="display:grid;grid-template-columns:1fr 2fr 1fr;gap:.6rem;";const m=document.createElement("div"),u=document.createElement("label");u.className="form-label",u.textContent="Type";const f=document.createElement("input");f.type="text",f.className="form-input conn-type",f.value=c.type||"mongodb",f.disabled=!0,m.appendChild(u),m.appendChild(f);const w=document.createElement("div"),N=document.createElement("label");N.className="form-label",N.textContent="URI";const g=document.createElement("input");g.type="text",g.className="form-input conn-uri",g.value=c.uri||"",g.placeholder="mongodb://localhost:27017",w.appendChild(N),w.appendChild(g);const S=document.createElement("div"),k=document.createElement("label");k.className="form-label",k.textContent="Database";const b=document.createElement("input");b.type="text",b.className="form-input conn-database",b.value=c.database||"",b.placeholder="mydb",S.appendChild(k),S.appendChild(b),i.appendChild(m),i.appendChild(w),i.appendChild(S),a.appendChild(o),a.appendChild(i),l.appendChild(a)}),Domma.icons.scan(l)}function x(e){const l={},p=e.find("#connections-list").get(0)?.querySelectorAll(".conn-card")||[];for(const t of p){const n=t.querySelector(".conn-name")?.value.trim(),c=t.querySelector(".conn-uri")?.value.trim()||"",a=t.querySelector(".conn-database")?.value.trim()||"";n&&(l[n]={type:"mongodb",uri:c,database:a,options:{}})}return l}function v(e){const l=e.find("#connections-raw-json").get(0);l&&(l.value=JSON.stringify(d,null,2))}
|
|
@@ -25,4 +25,4 @@ ${e.style}
|
|
|
25
25
|
</style>`:""].filter(Boolean).join(`
|
|
26
26
|
`)+`
|
|
27
27
|
`}function w(e,n){const o=I(n);c.template?.setValue(o.template),c.props?.setValue(o.props),c.script?.setValue(o.script),c.style?.setValue(o.style)}function N(e){return M({template:c.template?.getValue()??"",props:c.props?.getValue()??"",script:c.script?.getValue()??"",style:c.style?.getValue()??""})}const O=["template","props","script","style"];function A(e){const n=()=>{b&&clearTimeout(b),b=setTimeout(()=>h(e),300)};for(const o of O){const t=e.find(`#component-src-${o}`).get(0);t&&(c[o]=S(t,{initialValue:"",onChange:n}))}}async function h(e){const n=(e.find("#component-name").val()||"").trim()||"preview",o=N(e);g(e,"compiling");let t;try{t=await u.components.compile(n,o)}catch(s){g(e,"error",s.message||"Compile request failed.");return}if(t.errors?.length){const s=t.errors.map(r=>`[${r.type}] ${r.message}`).join(`
|
|
28
|
-
`);g(e,"error",s),f=null;return}f=t.js,g(e,"ok"),P(e),B(e,{compiledJs:f,tagName:`dm-${n}`,props:l})}let y=null;function B(e,n){const o=e.find("#component-preview-iframe").get(0);if(!o)return;if(!o.dataset.dmMounted){o.dataset.dmMounted="true",C(e,{type:"mount",payload:n});return}y=n;const t=()=>{o.removeEventListener("load",t),y&&(C(e,{type:"mount",payload:y}),y=null)};o.addEventListener("load",t),o.src=o.src}function g(e,n,o=""){const t=e.find("#component-compile-indicator").get(0),s=e.find("#component-compile-status").get(0),r=e.find("#component-compile-errors").get(0),a=e.find("#save-component-btn").get(0);n==="compiling"?(t.style.background="var(--dm-text-muted)",s.textContent="Compiling\u2026",r.hidden=!0,a&&(a.disabled=!0)):n==="ok"?(t.style.background="var(--dm-success)",s.textContent="Compile OK",r.hidden=!0,a&&(a.disabled=!1)):(t.style.background="var(--dm-danger)",s.textContent="Compile failed
|
|
28
|
+
`);g(e,"error",s),f=null;return}f=t.js,g(e,"ok"),P(e),B(e,{compiledJs:f,tagName:`dm-${n}`,props:l})}let y=null;function B(e,n){const o=e.find("#component-preview-iframe").get(0);if(!o)return;if(!o.dataset.dmMounted){o.dataset.dmMounted="true",C(e,{type:"mount",payload:n});return}y=n;const t=()=>{o.removeEventListener("load",t),y&&(C(e,{type:"mount",payload:y}),y=null)};o.addEventListener("load",t),o.src=o.src}function g(e,n,o=""){const t=e.find("#component-compile-indicator").get(0),s=e.find("#component-compile-status").get(0),r=e.find("#component-compile-errors").get(0),a=e.find("#save-component-btn").get(0);n==="compiling"?(t.style.background="var(--dm-text-muted)",s.textContent="Compiling\u2026",r.hidden=!0,a&&(a.disabled=!0)):n==="ok"?(t.style.background="var(--dm-success)",s.textContent="Compile OK",r.hidden=!0,a&&(a.disabled=!1)):(t.style.background="var(--dm-danger)",s.textContent="Compile failed - see below",r.hidden=!1,r.textContent=o,a&&(a.disabled=!0))}function j(e){for(;e.firstChild;)e.removeChild(e.firstChild)}function k(e,n,o=!1){j(e);const t=document.createElement("p");if(t.className="text-muted",t.style.cssText="font-size:.8rem;margin:0;",o){t.appendChild(document.createTextNode("Invalid "));const s=document.createElement("code");s.textContent="<props>",t.appendChild(s),t.appendChild(document.createTextNode(" JSON - fix the tab above to see the props panel."))}else t.textContent=n;e.appendChild(t)}function P(e){const n=e.find("#component-preview-props-panel").get(0);if(!n)return;let o={};try{o=JSON.parse(c.props?.getValue()||"{}")}catch{k(n,"",!0);return}const t={};j(n);const s=Object.entries(o);if(s.length===0){k(n,"No props declared."),l={};return}for(const[r,a]of s){const i=document.createElement("div");i.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem;";const m=document.createElement("label");m.style.cssText="font-size:.75rem;color:var(--dm-text-muted,#aaa);min-width:120px;",m.textContent=a.label||r,i.appendChild(m);const d=F(a,r,()=>{l[r]=J(d,a),C(e,{type:"update",payload:{props:l}})}),x=r in l?l[r]:a.default!==void 0?a.default:_(a.type);U(d,a,x),t[r]=x,i.appendChild(d),n.appendChild(i)}l=t}function F(e,n,o){let t;return e.type==="number"?(t=document.createElement("input"),t.type="number",t.className="form-input form-input--sm"):e.type==="boolean"?(t=document.createElement("input"),t.type="checkbox",t.className="form-check"):e.type==="array"||e.type==="object"?(t=document.createElement("textarea"),t.rows=2,t.className="form-input form-input--sm",t.style.fontFamily="var(--dm-font-mono, monospace)"):(t=document.createElement("input"),t.type="text",t.className="form-input form-input--sm"),t.style.flex="1",t.dataset.propName=n,t.addEventListener("input",o),t.addEventListener("change",o),t}function J(e,n){if(n.type==="number")return e.value===""?null:Number(e.value);if(n.type==="boolean")return!!e.checked;if(n.type==="array"||n.type==="object")try{return JSON.parse(e.value||"null")}catch{return null}return e.value}function U(e,n,o){n.type==="boolean"?e.checked=!!o:n.type==="array"||n.type==="object"?e.value=JSON.stringify(o??null):e.value=o??""}function _(e){return e==="number"?0:e==="boolean"?!1:e==="array"?[]:e==="object"?{}:""}function C(e,n){const o=e.find("#component-preview-iframe").get(0);o?.contentWindow&&o.contentWindow.postMessage(n,"*")}function z(e){const n=e.find("#save-component-btn").get(0),o=e.find("#export-component-btn").get(0);n&&n.addEventListener("click",()=>q(e)),o&&o.addEventListener("click",async()=>{if(p)try{await u.components.exportBundle(p)}catch(t){E.toast(t.message||"Export failed.",{type:"error"})}})}async function q(e){const n=(e.find("#component-name").val()||"").trim();if(!n){E.toast("Component name is required.",{type:"warning"});return}if(!/^[a-z][a-z0-9-]*$/.test(n)){E.toast("Name must start with a letter and contain only lowercase letters, digits, and hyphens.",{type:"warning"});return}const o=N(e),t=!!e.find("#component-bundled").is(":checked"),s={...v||{}};delete s.bundled;const r=(e.find("#component-project").val()||"").trim();r?s.project=r:delete s.project;const a=e.find("#save-component-btn").get(0);a&&(a.disabled=!0);try{await u.components.put(n,{source:o,bundled:t,meta:s}),E.toast(p?"Component updated.":"Component created.",{type:"success"}),p||(p=n,R.navigate(`/components/edit/${encodeURIComponent(n)}`))}catch(i){E.toast(i.message||"Failed to save component.",{type:"error"})}finally{a&&(a.disabled=!1)}}async function D(e){if(p)try{const n=await u.components.list(),o=e.find("#component-quick-switch").get(0);if(!o||!n?.length)return;const t=[...n].sort((s,r)=>s.name.localeCompare(r.name));for(const s of t){const r=document.createElement("option");r.value=s.name,r.textContent=s.name,s.name===p&&(r.selected=!0),o.appendChild(r)}o.style.display="",o.addEventListener("change",()=>{const s=o.value;s&&s!==p&&R.navigate(`/components/edit/${encodeURIComponent(s)}`)})}catch{}}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{api as c}from"../api.js";import{filterByProject as u,getProjectFromHash as f}from"../lib/project-context.js";import{keepTableIconsAlive as
|
|
2
|
-
<a href="#/components/edit/${
|
|
3
|
-
<button class="btn btn-sm btn-ghost js-export-component" data-name="${
|
|
1
|
+
import{api as c}from"../api.js";import{filterByProject as u,getProjectFromHash as f,renderProjectFilterNotice as g}from"../lib/project-context.js";import{keepTableIconsAlive as y}from"../lib/table-icons.js";function l(t){return String(t??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function h(t){for(;t.firstChild;)t.removeChild(t.firstChild)}export const componentsView={templateUrl:"/admin/js/templates/components.html",async onMount(t){k(),await p(t),b(t),Domma.icons.scan(t.get(0)),y(t.get(0))}};let d=!1;function k(){d||(d=!0,I.register("download",{viewBox:"0 0 24 24",paths:["M12 3v12","M7 10l5 5 5-5","M5 19h14"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("upload",{viewBox:"0 0 24 24",paths:["M12 21V9","M7 14l5-5 5 5","M5 5h14"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("plus",{viewBox:"0 0 24 24",paths:["M12 5v14","M5 12h14"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}))}async function p(t){const n=t.find("#components-table-container").get(0);if(!n)return;let o=[];const i=E.loader(t.get(0),{type:"dots"});try{o=await c.components.list()}catch(e){h(n);const s=document.createElement("p");s.className="text-muted",s.textContent=`Failed to load components: ${e.message}`,n.appendChild(s);return}finally{i.destroy()}const r=f();if(r){const e=o.length;o=u(o,r),g(t,{total:e,shown:o.length,slug:r,allHref:"#/components",noun:"components"})}T.create(n,{pageSize:25,data:o,emptyMessage:'No components yet. Click "New Component" to create your first one.',columns:[{key:"name",title:"Name",render:(e,s)=>{const a=s.origin==="plugin"?' <span class="badge badge-secondary" title="Provided by a plugin - read-only">plugin</span>':"";return`<a href="#/components/edit/${l(e)}">${l(e)}.dmc</a>${a}`}},{key:"props",title:"Props",render:e=>{const s=Object.keys(e||{});return s.length===0?'<span class="text-muted">-</span>':s.map(a=>`<span class="badge badge-secondary" style="margin-right:.25rem;">${l(a)}</span>`).join("")}},{key:"size",title:"Size",render:e=>`${e} B`},{key:"updatedAt",title:"Updated",render:e=>e?new Date(e).toLocaleString():"-"},{key:"name",title:"Actions",render:(e,s)=>{const a=l(e),m=s.origin==="plugin"?"":`<button class="btn btn-sm btn-ghost js-delete-component" data-name="${a}" data-tooltip="Delete"><span data-icon="trash" data-icon-size="14"></span></button>`;return`<div style="display:flex;gap:.4rem;justify-content:flex-end;">
|
|
2
|
+
<a href="#/components/edit/${a}" class="btn btn-sm btn-ghost" data-tooltip="Edit"><span data-icon="edit" data-icon-size="14"></span></a>
|
|
3
|
+
<button class="btn btn-sm btn-ghost js-export-component" data-name="${a}" data-tooltip="Export as .dmcomponent.json"><span data-icon="download" data-icon-size="14"></span></button>
|
|
4
4
|
${m}
|
|
5
|
-
</div>`}}]}),
|
|
5
|
+
</div>`}}]}),t.off("click",".js-delete-component").on("click",".js-delete-component",async function(){await w(this.dataset.name,t)}),t.off("click",".js-export-component").on("click",".js-export-component",async function(){try{await c.components.exportBundle(this.dataset.name)}catch(e){E.toast(e.message||"Export failed.",{type:"error"})}}),Domma.icons.scan(n),n.querySelectorAll("[data-tooltip]").forEach(e=>{E.tooltip(e,{content:e.getAttribute("data-tooltip"),position:"top"})})}async function w(t,n){if(await E.confirm(`Delete component "${t}"? This cannot be undone.`))try{await c.components.delete(t),E.toast("Component deleted.",{type:"success"}),await p(n)}catch(i){E.toast(i.message||"Failed to delete component.",{type:"error"})}}function b(t){const n=t.find("#import-component-btn").get(0),o=t.find("#import-component-file").get(0);!n||!o||(n.addEventListener("click",()=>o.click()),o.addEventListener("change",async()=>{const i=o.files?.[0];if(!i)return;o.value="";let r;try{const e=await i.text();r=JSON.parse(e)}catch{E.toast("Not a valid .dmcomponent.json file (could not parse JSON).",{type:"error"});return}if(!r||typeof r!="object"||!r.name||typeof r.source!="string"){E.toast("Bundle is missing a name or source field.",{type:"error"});return}try{const e=await c.components.importBundle(r);E.toast(`Imported "${e.name}".`,{type:"success"}),await p(t)}catch(e){if(e.code==="CONFLICT"){if(!await E.confirm(`A component named "${e.name}" already exists. Overwrite it with the imported version?`)){E.toast("Import cancelled.",{type:"info"});return}try{const a=await c.components.importBundle(r,{overwrite:!0});E.toast(`Overwrote "${a.name}".`,{type:"success"}),await p(t)}catch(a){E.toast(a.message||"Import failed.",{type:"error"})}return}E.toast(e.message||"Import failed.",{type:"error"})}}))}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{apiRequest as r}from"../../../api.js";function h(t){if(!t)return"never";const e=Date.now()-new Date(t).getTime();if(e<0)return"just now";const a=Math.floor(e/1e3);if(a<60)return`${a}s ago`;const i=Math.floor(a/60);if(i<60)return`${i}m ago`;const n=Math.floor(i/60);return n<24?`${n}h ago`:`${Math.floor(n/24)}d ago`}function d(t,e){const a=e.hits+e.misses,i=e.hitRate;t.find('[data-field="hit-rate"]').text(i===null?"
|
|
1
|
+
import{apiRequest as r}from"../../../api.js";function h(t){if(!t)return"never";const e=Date.now()-new Date(t).getTime();if(e<0)return"just now";const a=Math.floor(e/1e3);if(a<60)return`${a}s ago`;const i=Math.floor(a/60);if(i<60)return`${i}m ago`;const n=Math.floor(i/60);return n<24?`${n}h ago`:`${Math.floor(n/24)}d ago`}function d(t,e){const a=e.hits+e.misses,i=e.hitRate;t.find('[data-field="hit-rate"]').text(i===null?"-":(i*100).toFixed(1)+"%"),t.find('[data-field="hits-misses"]').text(a===0?"no traffic yet":`${e.hits.toLocaleString()} hits \xB7 ${e.misses.toLocaleString()} misses`);const n=e.size??0,c=e.maxItems??0;t.find('[data-field="size"]').text(c?`${n} / ${c}`:String(n));const l=c?Math.min(100,n/c*100):0,o=t.find('[data-field="size-fill"]').get(0);o&&(o.style.width=l+"%"),t.find('[data-field="writes"]').text(e.writes.toLocaleString()),t.find('[data-field="invalidations"]').text(`${e.invalidations.toLocaleString()} invalidations`),t.find('[data-field="last-cleared"]').text(h(e.lastClearedAt)),t.find('[data-field="driver"]').text("driver: "+e.driver);const f=t.find('[data-field="toggle"]').get(0);f&&(f.checked=!!e.enabled),t.find('[data-field="toggle-label"]').text(e.enabled?"On":"Off")}async function s(t){try{const e=await r("/cache/status");d(t,e),t.data("cache-stats",e)}catch(e){console.warn("[cache widget] failed to refresh:",e)}}export default async function g(t){await s(t);const e=t.find('[data-field="toggle"]');e.on("change",async()=>{const a=e.get(0).checked;try{const i=await r("/cache/toggle",{method:"POST",body:JSON.stringify({enabled:a})});d(t,i),E.toast(`Cache ${i.enabled?"enabled":"disabled"}.`,{type:"success"})}catch(i){e.get(0).checked=!a,E.toast(i.message||"Failed to toggle cache.",{type:"error"})}}),t.find('[data-field="clear-btn"]').on("click",async()=>{if(await E.confirm("Clear the entire response cache?"))try{const a=await r("/cache/clear",{method:"POST"});d(t,a),E.toast("Cache cleared.",{type:"success"})}catch(a){E.toast(a.message||"Failed to clear cache.",{type:"error"})}}),window.Domma&&Domma.icons&&Domma.icons.scan()}export{s as refreshCacheWidget};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{escapeHtml as r}from"../lib/escape.js";function s(n,a){return n.map(e=>'<div class="dash-spike-row">'+a(e)+"</div>").join("")}function i(n,a){n&&(n.innerHTML=a)}export default function f(n,a){const e=a?.journeys,d=n.find(".dash-empty"),o=n.find('[data-field="entry"]'),p=n.find('[data-field="exit"]'),u=n.find('[data-field="paths"]'),c=n.find('[data-field="bounce"]');if(!e||!e.totalSessions){d.removeAttr("hidden"),o.empty(),p.empty(),u.empty(),c.text("
|
|
1
|
+
import{escapeHtml as r}from"../lib/escape.js";function s(n,a){return n.map(e=>'<div class="dash-spike-row">'+a(e)+"</div>").join("")}function i(n,a){n&&(n.innerHTML=a)}export default function f(n,a){const e=a?.journeys,d=n.find(".dash-empty"),o=n.find('[data-field="entry"]'),p=n.find('[data-field="exit"]'),u=n.find('[data-field="paths"]'),c=n.find('[data-field="bounce"]');if(!e||!e.totalSessions){d.removeAttr("hidden"),o.empty(),p.empty(),u.empty(),c.text("-");return}d.attr("hidden","hidden"),i(o.get(0),s(e.entry||[],t=>"<span>"+r(t.url)+"</span><span>"+(Number(t.count)|0)+"</span>")),i(p.get(0),s(e.exit||[],t=>"<span>"+r(t.url)+"</span><span>"+(Number(t.count)|0)+"</span>")),i(u.get(0),s(e.paths||[],t=>"<span>"+r(t.from)+" → "+r(t.to)+"</span><span>"+(Number(t.count)|0)+"</span>")),c.text((Number(e.bounceRate)*100).toFixed(1)+"%")}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export default function n(e,t){const d=t?.traffic?.today??0,a=t?.traffic?.deltaPct;e.find('[data-field="hits-today"]').text(d);const s=e.find('[data-field="hits-delta"]');a==null?s.text("").removeClass("up down"):a>=0?s.text("+"+a+"% vs yesterday").removeClass("down").addClass("up"):s.text(a+"% vs yesterday").removeClass("up").addClass("down"),e.find('[data-field="active-sessions"]').text(t?.realtime?.activeSessions??0),e.find('[data-field="submissions-week"]').text(t?._submissionsWeek??"
|
|
1
|
+
export default function n(e,t){const d=t?.traffic?.today??0,a=t?.traffic?.deltaPct;e.find('[data-field="hits-today"]').text(d);const s=e.find('[data-field="hits-delta"]');a==null?s.text("").removeClass("up down"):a>=0?s.text("+"+a+"% vs yesterday").removeClass("down").addClass("up"):s.text(a+"% vs yesterday").removeClass("up").addClass("down"),e.find('[data-field="active-sessions"]').text(t?.realtime?.activeSessions??0),e.find('[data-field="submissions-week"]').text(t?._submissionsWeek??"-");const i=t?.health?.status||"ok",l={ok:"OK",warn:"Attention",fail:"Failing"};e.find('[data-field="health-pill"]').attr("data-level",i),e.find('[data-field="health-label"]').text(l[i])}
|