kempo 4.2.16 → 4.2.17
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/bin/cli.js +21 -4
- package/dist/admin/components/AddGroupControl.js +2 -2
- package/dist/admin/components/AddGroupControl.js.map +1 -1
- package/dist/admin/components/ClearExpiredSessionsControl.js +2 -2
- package/dist/admin/components/ClearExpiredSessionsControl.js.map +1 -1
- package/dist/admin/components/FragmentEditor.js +15 -15
- package/dist/admin/components/FragmentEditor.js.map +1 -1
- package/dist/admin/components/GlobalContentEditor.js +12 -12
- package/dist/admin/components/GlobalContentEditor.js.map +1 -1
- package/dist/admin/components/GroupDeleteSelected.js +2 -2
- package/dist/admin/components/GroupDeleteSelected.js.map +1 -1
- package/dist/admin/components/GroupRemoveRecord.js +2 -2
- package/dist/admin/components/GroupRemoveRecord.js.map +1 -1
- package/dist/admin/components/Monaco.js +1 -1
- package/dist/admin/components/Monaco.js.map +1 -1
- package/dist/admin/components/PageEditor.js +42 -28
- package/dist/admin/components/PageEditor.js.map +1 -1
- package/dist/admin/components/TableRowDelete.js +2 -2
- package/dist/admin/components/TableRowDelete.js.map +1 -1
- package/dist/admin/components/TableRowLink.js +2 -2
- package/dist/admin/components/TableRowLink.js.map +1 -1
- package/dist/admin/components/TemplateEditor.js +18 -18
- package/dist/admin/components/TemplateEditor.js.map +1 -1
- package/dist/admin/components/ValueEditor.js +17 -17
- package/dist/admin/components/ValueEditor.js.map +1 -1
- package/dist/admin/components/tableControls/AddMember.js +2 -2
- package/dist/admin/components/tableControls/AddMember.js.map +1 -1
- package/dist/admin/components/tableControls/AddPermission.js +2 -2
- package/dist/admin/components/tableControls/AddPermission.js.map +1 -1
- package/dist/admin/components/tableControls/InstallExtension.js +2 -2
- package/dist/admin/components/tableControls/InstallExtension.js.map +1 -1
- package/dist/admin/components/tableControls/UninstallExtension.js +2 -2
- package/dist/admin/components/tableControls/UninstallExtension.js.map +1 -1
- package/dist/admin/extensions/index.page.html +49 -15
- package/dist/admin/icons/open_in_new.svg +1 -0
- package/dist/admin/nav.fragment.html +1 -1
- package/dist/kempo/api/admin-globals/DELETE.js +1 -1
- package/dist/kempo/api/admin-globals/DELETE.js.map +1 -1
- package/dist/kempo/api/admin-globals/GET.js +1 -1
- package/dist/kempo/api/admin-globals/GET.js.map +1 -1
- package/dist/kempo/api/admin-globals/POST.js +1 -1
- package/dist/kempo/api/admin-globals/POST.js.map +1 -1
- package/dist/kempo/api/admin-globals/[id]/GET.js +1 -1
- package/dist/kempo/api/admin-globals/[id]/GET.js.map +1 -1
- package/dist/kempo/api/admin-globals/[id]/PUT.js +1 -1
- package/dist/kempo/api/admin-globals/[id]/PUT.js.map +1 -1
- package/dist/kempo/api/admin-globals/[id]/disable/PUT.js +1 -1
- package/dist/kempo/api/admin-globals/[id]/disable/PUT.js.map +1 -1
- package/dist/kempo/api/admin-globals/[id]/enable/PUT.js +1 -1
- package/dist/kempo/api/admin-globals/[id]/enable/PUT.js.map +1 -1
- package/dist/kempo/api/auth/change-password/POST.js +1 -1
- package/dist/kempo/api/auth/change-password/POST.js.map +1 -1
- package/dist/kempo/api/auth/login/email/POST.js +1 -1
- package/dist/kempo/api/auth/login/email/POST.js.map +1 -1
- package/dist/kempo/api/auth/logout/POST.js +1 -1
- package/dist/kempo/api/auth/logout/POST.js.map +1 -1
- package/dist/kempo/api/auth/register/email/POST.js +1 -1
- package/dist/kempo/api/auth/register/email/POST.js.map +1 -1
- package/dist/kempo/api/auth/reset-password/POST.js +1 -1
- package/dist/kempo/api/auth/reset-password/POST.js.map +1 -1
- package/dist/kempo/api/auth/session/GET.js +1 -1
- package/dist/kempo/api/auth/session/GET.js.map +1 -1
- package/dist/kempo/api/auth/verify-email/POST.js +1 -1
- package/dist/kempo/api/auth/verify-email/POST.js.map +1 -1
- package/dist/kempo/api/extensions/DELETE.js +1 -1
- package/dist/kempo/api/extensions/DELETE.js.map +1 -1
- package/dist/kempo/api/extensions/GET.js +1 -1
- package/dist/kempo/api/extensions/GET.js.map +1 -1
- package/dist/kempo/api/extensions/POST.js +1 -1
- package/dist/kempo/api/extensions/POST.js.map +1 -1
- package/dist/kempo/api/extensions/[name]/disable/POST.js +1 -1
- package/dist/kempo/api/extensions/[name]/disable/POST.js.map +1 -1
- package/dist/kempo/api/extensions/[name]/enable/POST.js +1 -1
- package/dist/kempo/api/extensions/[name]/enable/POST.js.map +1 -1
- package/dist/kempo/api/extensions/[name]/update/POST.js +1 -1
- package/dist/kempo/api/extensions/[name]/update/POST.js.map +1 -1
- package/dist/kempo/api/extensions/[name]/update-check/GET.js +1 -1
- package/dist/kempo/api/extensions/[name]/update-check/GET.js.map +1 -1
- package/dist/kempo/api/extensions/available/GET.js +1 -1
- package/dist/kempo/api/extensions/available/GET.js.map +1 -1
- package/dist/kempo/api/extensions/known/GET.js +1 -1
- package/dist/kempo/api/extensions/known/GET.js.map +1 -1
- package/dist/kempo/api/forgot-password/POST.js +1 -1
- package/dist/kempo/api/forgot-password/POST.js.map +1 -1
- package/dist/kempo/api/fragments/DELETE.js +1 -1
- package/dist/kempo/api/fragments/DELETE.js.map +1 -1
- package/dist/kempo/api/fragments/GET.js +1 -1
- package/dist/kempo/api/fragments/GET.js.map +1 -1
- package/dist/kempo/api/fragments/POST.js +1 -1
- package/dist/kempo/api/fragments/POST.js.map +1 -1
- package/dist/kempo/api/fragments/disable/PUT.js +1 -1
- package/dist/kempo/api/fragments/disable/PUT.js.map +1 -1
- package/dist/kempo/api/fragments/enable/PUT.js +1 -1
- package/dist/kempo/api/fragments/enable/PUT.js.map +1 -1
- package/dist/kempo/api/fragments/file/GET.js +1 -1
- package/dist/kempo/api/fragments/file/GET.js.map +1 -1
- package/dist/kempo/api/fragments/file/PATCH.js +1 -1
- package/dist/kempo/api/fragments/file/PATCH.js.map +1 -1
- package/dist/kempo/api/fragments/file/PUT.js +1 -1
- package/dist/kempo/api/fragments/file/PUT.js.map +1 -1
- package/dist/kempo/api/fragments/lock/PUT.js +2 -2
- package/dist/kempo/api/fragments/lock/PUT.js.map +1 -1
- package/dist/kempo/api/globals/DELETE.js +1 -1
- package/dist/kempo/api/globals/DELETE.js.map +1 -1
- package/dist/kempo/api/globals/GET.js +1 -1
- package/dist/kempo/api/globals/GET.js.map +1 -1
- package/dist/kempo/api/globals/POST.js +1 -1
- package/dist/kempo/api/globals/POST.js.map +1 -1
- package/dist/kempo/api/globals/disable/PUT.js +1 -1
- package/dist/kempo/api/globals/disable/PUT.js.map +1 -1
- package/dist/kempo/api/globals/enable/PUT.js +1 -1
- package/dist/kempo/api/globals/enable/PUT.js.map +1 -1
- package/dist/kempo/api/globals/entry/GET.js +1 -1
- package/dist/kempo/api/globals/entry/GET.js.map +1 -1
- package/dist/kempo/api/globals/entry/PUT.js +1 -1
- package/dist/kempo/api/globals/entry/PUT.js.map +1 -1
- package/dist/kempo/api/globals/lock/PUT.js +2 -2
- package/dist/kempo/api/globals/lock/PUT.js.map +1 -1
- package/dist/kempo/api/groups/DELETE.js +1 -1
- package/dist/kempo/api/groups/DELETE.js.map +1 -1
- package/dist/kempo/api/groups/GET.js +1 -1
- package/dist/kempo/api/groups/GET.js.map +1 -1
- package/dist/kempo/api/groups/PATCH.js +1 -1
- package/dist/kempo/api/groups/PATCH.js.map +1 -1
- package/dist/kempo/api/groups/POST.js +1 -1
- package/dist/kempo/api/groups/POST.js.map +1 -1
- package/dist/kempo/api/groups/[name]/GET.js +1 -1
- package/dist/kempo/api/groups/[name]/GET.js.map +1 -1
- package/dist/kempo/api/groups/[name]/members/DELETE.js +1 -1
- package/dist/kempo/api/groups/[name]/members/DELETE.js.map +1 -1
- package/dist/kempo/api/groups/[name]/members/GET.js +1 -1
- package/dist/kempo/api/groups/[name]/members/GET.js.map +1 -1
- package/dist/kempo/api/groups/[name]/members/POST.js +1 -1
- package/dist/kempo/api/groups/[name]/members/POST.js.map +1 -1
- package/dist/kempo/api/groups/[name]/permissions/DELETE.js +1 -1
- package/dist/kempo/api/groups/[name]/permissions/DELETE.js.map +1 -1
- package/dist/kempo/api/groups/[name]/permissions/GET.js +1 -1
- package/dist/kempo/api/groups/[name]/permissions/GET.js.map +1 -1
- package/dist/kempo/api/groups/[name]/permissions/POST.js +1 -1
- package/dist/kempo/api/groups/[name]/permissions/POST.js.map +1 -1
- package/dist/kempo/api/pages/DELETE.js +1 -1
- package/dist/kempo/api/pages/DELETE.js.map +1 -1
- package/dist/kempo/api/pages/GET.js +1 -1
- package/dist/kempo/api/pages/GET.js.map +1 -1
- package/dist/kempo/api/pages/POST.js +1 -1
- package/dist/kempo/api/pages/POST.js.map +1 -1
- package/dist/kempo/api/pages/directories/GET.js +1 -1
- package/dist/kempo/api/pages/directories/GET.js.map +1 -1
- package/dist/kempo/api/pages/disable/PUT.js +1 -1
- package/dist/kempo/api/pages/disable/PUT.js.map +1 -1
- package/dist/kempo/api/pages/enable/PUT.js +1 -1
- package/dist/kempo/api/pages/enable/PUT.js.map +1 -1
- package/dist/kempo/api/pages/file/GET.js +1 -1
- package/dist/kempo/api/pages/file/GET.js.map +1 -1
- package/dist/kempo/api/pages/file/PATCH.js +1 -1
- package/dist/kempo/api/pages/file/PATCH.js.map +1 -1
- package/dist/kempo/api/pages/file/PUT.js +1 -1
- package/dist/kempo/api/pages/file/PUT.js.map +1 -1
- package/dist/kempo/api/pages/lock/PUT.js +2 -2
- package/dist/kempo/api/pages/lock/PUT.js.map +1 -1
- package/dist/kempo/api/pages/search/GET.js +2 -2
- package/dist/kempo/api/pages/search/GET.js.map +1 -1
- package/dist/kempo/api/pages/templates/GET.js +1 -1
- package/dist/kempo/api/pages/templates/GET.js.map +1 -1
- package/dist/kempo/api/permissions/DELETE.js +1 -1
- package/dist/kempo/api/permissions/DELETE.js.map +1 -1
- package/dist/kempo/api/permissions/GET.js +1 -1
- package/dist/kempo/api/permissions/GET.js.map +1 -1
- package/dist/kempo/api/permissions/PATCH.js +1 -1
- package/dist/kempo/api/permissions/PATCH.js.map +1 -1
- package/dist/kempo/api/permissions/POST.js +1 -1
- package/dist/kempo/api/permissions/POST.js.map +1 -1
- package/dist/kempo/api/settings/[owner]/GET.js +1 -1
- package/dist/kempo/api/settings/[owner]/GET.js.map +1 -1
- package/dist/kempo/api/settings/[owner]/[name]/DELETE.js +1 -1
- package/dist/kempo/api/settings/[owner]/[name]/DELETE.js.map +1 -1
- package/dist/kempo/api/settings/[owner]/[name]/GET.js +1 -1
- package/dist/kempo/api/settings/[owner]/[name]/GET.js.map +1 -1
- package/dist/kempo/api/settings/[owner]/[name]/POST.js +1 -1
- package/dist/kempo/api/settings/[owner]/[name]/POST.js.map +1 -1
- package/dist/kempo/api/settings/public/GET.js +1 -1
- package/dist/kempo/api/settings/public/GET.js.map +1 -1
- package/dist/kempo/api/templates/DELETE.js +1 -1
- package/dist/kempo/api/templates/DELETE.js.map +1 -1
- package/dist/kempo/api/templates/GET.js +1 -1
- package/dist/kempo/api/templates/GET.js.map +1 -1
- package/dist/kempo/api/templates/POST.js +1 -1
- package/dist/kempo/api/templates/POST.js.map +1 -1
- package/dist/kempo/api/templates/disable/PUT.js +1 -1
- package/dist/kempo/api/templates/disable/PUT.js.map +1 -1
- package/dist/kempo/api/templates/enable/PUT.js +1 -1
- package/dist/kempo/api/templates/enable/PUT.js.map +1 -1
- package/dist/kempo/api/templates/file/GET.js +1 -1
- package/dist/kempo/api/templates/file/GET.js.map +1 -1
- package/dist/kempo/api/templates/file/PATCH.js +1 -1
- package/dist/kempo/api/templates/file/PATCH.js.map +1 -1
- package/dist/kempo/api/templates/file/PUT.js +1 -1
- package/dist/kempo/api/templates/file/PUT.js.map +1 -1
- package/dist/kempo/api/templates/lock/PUT.js +2 -2
- package/dist/kempo/api/templates/lock/PUT.js.map +1 -1
- package/dist/kempo/api/user/DELETE.js +1 -1
- package/dist/kempo/api/user/DELETE.js.map +1 -1
- package/dist/kempo/api/user/GET.js +1 -1
- package/dist/kempo/api/user/GET.js.map +1 -1
- package/dist/kempo/api/user/PATCH.js +1 -1
- package/dist/kempo/api/user/PATCH.js.map +1 -1
- package/dist/kempo/api/user/[userid]/GET.js +1 -1
- package/dist/kempo/api/user/[userid]/GET.js.map +1 -1
- package/dist/kempo/api/user/[userid]/groups/DELETE.js +1 -1
- package/dist/kempo/api/user/[userid]/groups/DELETE.js.map +1 -1
- package/dist/kempo/api/user/[userid]/groups/GET.js +1 -1
- package/dist/kempo/api/user/[userid]/groups/GET.js.map +1 -1
- package/dist/kempo/api/user/[userid]/groups/POST.js +1 -1
- package/dist/kempo/api/user/[userid]/groups/POST.js.map +1 -1
- package/dist/kempo/api/user/[userid]/permissions/GET.js +1 -1
- package/dist/kempo/api/user/[userid]/permissions/GET.js.map +1 -1
- package/dist/kempo/api/user/[userid]/permissions/all/GET.js +1 -1
- package/dist/kempo/api/user/[userid]/permissions/all/GET.js.map +1 -1
- package/dist/kempo/api/user/[userid]/permissions/list/GET.js +1 -1
- package/dist/kempo/api/user/[userid]/permissions/list/GET.js.map +1 -1
- package/dist/kempo/api/user/[userid]/permissions/some/GET.js +1 -1
- package/dist/kempo/api/user/[userid]/permissions/some/GET.js.map +1 -1
- package/dist/kempo/api/user/[userid]/sessions/DELETE.js +1 -1
- package/dist/kempo/api/user/[userid]/sessions/DELETE.js.map +1 -1
- package/dist/kempo/api/user/[userid]/sessions/GET.js +1 -1
- package/dist/kempo/api/user/[userid]/sessions/GET.js.map +1 -1
- package/dist/kempo/api/user/[userid]/sessions/expired/DELETE.js +1 -1
- package/dist/kempo/api/user/[userid]/sessions/expired/DELETE.js.map +1 -1
- package/dist/kempo/api/user/create/POST.js +1 -1
- package/dist/kempo/api/user/create/POST.js.map +1 -1
- package/dist/kempo/api/user/search/GET.js +1 -1
- package/dist/kempo/api/user/search/GET.js.map +1 -1
- package/dist/kempo/components/LogoutBtn.js +1 -1
- package/dist/kempo/components/LogoutBtn.js.map +1 -1
- package/dist/kempo/components/Menu.js +9 -9
- package/dist/kempo/components/Menu.js.map +1 -1
- package/dist/kempo/components/Permission.js +1 -1
- package/dist/kempo/components/Permission.js.map +1 -1
- package/dist/kempo/components/Role.js +1 -1
- package/dist/kempo/components/Role.js.map +1 -1
- package/dist/kempo/components/UserCreatedAt.js +1 -1
- package/dist/kempo/components/UserCreatedAt.js.map +1 -1
- package/dist/kempo/components/UserEmail.js +1 -1
- package/dist/kempo/components/UserEmail.js.map +1 -1
- package/dist/kempo/components/UserEmailVerified.js +1 -1
- package/dist/kempo/components/UserEmailVerified.js.map +1 -1
- package/dist/kempo/components/UserName.js +1 -1
- package/dist/kempo/components/UserName.js.map +1 -1
- package/dist/kempo/fetch.js +1 -1
- package/dist/kempo/fetch.js.map +1 -1
- package/dist/kempo/sdk.js +1 -1
- package/dist/kempo/sdk.js.map +1 -1
- package/middleware/kempo.js +36 -6
- package/package.json +2 -2
- package/server/utils/extensions/installExtension.js +19 -13
- package/server/utils/extensions/uninstallExtension.js +6 -10
- package/server/utils/pages/deletePage.js +2 -10
- package/dist/admin/accounts/groups/[name]/index.html +0 -518
- package/dist/admin/accounts/groups/index.html +0 -378
- package/dist/admin/accounts/permissions/index.html +0 -397
- package/dist/admin/accounts/users/[id]/index.html +0 -541
- package/dist/admin/accounts/users/index.html +0 -396
- package/dist/admin/content/fragments/edit/index.html +0 -132
- package/dist/admin/content/fragments/index.html +0 -375
- package/dist/admin/content/globals/edit/index.html +0 -132
- package/dist/admin/content/globals/index.html +0 -358
- package/dist/admin/content/pages/edit/index.html +0 -132
- package/dist/admin/content/pages/index.html +0 -509
- package/dist/admin/content/templates/edit/index.html +0 -132
- package/dist/admin/content/templates/index.html +0 -429
- package/dist/admin/extensions/index.html +0 -222
- package/dist/admin/index.html +0 -130
- package/dist/admin/settings/[owner]/[name]/index.html +0 -449
- package/dist/admin/settings/index.html +0 -410
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src\\admin\\components\\TemplateEditor.js","names":["ShadowComponent","html","getTemplate","updateTemplate","deleteTemplates","moveTemplate","createTemplate","listDirectories","Dialog","Toast","TemplateEditor","static","loading","state","error","saving","template","constructor","super","this","file","connectedCallback","document","addEventListener","handleKeyDown","param","URLSearchParams","window","location","search","get","err","title","name","disconnectedCallback","removeEventListener","getFormState","root","shadowRoot","querySelector","value","markup","getValue","e","ctrlKey","metaKey","key","preventDefault","locked","handleSave","handleDelete","confirm","async","confirmed","msg","success","setTimeout","href","handleMove","dirData","directories","parts","replace","split","currentName","pop","currentDir","join","dirToInternal","p","currentDirDisplay","$dialog","create","map","d","confirmText","confirmAction","dirInput","trim","newName","test","includes","newDir","newFile","saveError","moveError","moved","newParam","encodeURIComponent","cancelText","updatePreview","dir","prefix","textContent","handleCopy","directory","data","copyFrom","handleReset","saved","updatedAt","currentSlug","newSlug","toLowerCase","render","isCustom","owner","isLocked","length","author","createdAt","Date","toLocaleString","customElements","define"],"sources":["0"],"sourcesContent":["import ShadowComponent from '/kempo-ui/components/ShadowComponent.js';\nimport { html } from '/kempo-ui/lit-all.min.js';\nimport { getTemplate, updateTemplate, deleteTemplates, moveTemplate, createTemplate, listDirectories } from '/kempo/sdk.js';\nimport Dialog from '/kempo-ui/components/Dialog.js';\nimport Toast from '/kempo-ui/components/Toast.js';\nimport '/kempo-ui/components/Icon.js';\nimport '/kempo-ui/components/Accordion.js';\nimport '/kempo-ui/components/CodeEditor.js';\n\nexport default class TemplateEditor extends ShadowComponent {\n static properties = {\n loading: { state: true },\n error: { state: true },\n saving: { state: true },\n template: { state: true }\n };\n\n constructor() {\n super();\n this.loading = true;\n this.error = false;\n this.saving = false;\n this.template = null;\n this.file = '';\n }\n\n async connectedCallback() {\n super.connectedCallback();\n document.addEventListener('keydown', this.handleKeyDown);\n const param = new URLSearchParams(window.location.search).get('template');\n this.file = param + '.template.html';\n\n if (!this.file || this.file === '.template.html') {\n this.loading = false;\n this.error = true;\n return;\n }\n\n const [err, template] = await getTemplate(this.file);\n this.loading = false;\n\n if (err) {\n this.error = true;\n return;\n }\n\n this.template = template;\n document.title = `Edit: ${template.name} - Admin`;\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n document.removeEventListener('keydown', this.handleKeyDown);\n }\n\n /*\n Helpers\n */\n\n getFormState() {\n const root = this.shadowRoot;\n return {\n name: root.querySelector('#metaName')?.value ?? this.template.name,\n markup: root.querySelector('#templateEditor')?.getValue() ?? this.template.markup\n };\n }\n\n /*\n Event Handlers\n */\n\n handleKeyDown = e => {\n if ((e.ctrlKey || e.metaKey) && e.key === 's') {\n e.preventDefault();\n if (!this.saving && !this.template?.locked) this.handleSave();\n }\n };\n\n handleDelete = () => {\n Dialog.confirm('Delete this template? This action cannot be undone.', async confirmed => {\n if (!confirmed) return;\n const [error] = await deleteTemplates([this.file]);\n if (error) {\n Toast.error(error.msg || 'Failed to delete template');\n return;\n }\n Toast.success('Template deleted');\n setTimeout(() => { window.location.href = '/admin/content/templates'; }, 1000);\n });\n };\n\n handleMove = async () => {\n const [, dirData] = await listDirectories();\n const directories = dirData?.directories || ['.'];\n\n const parts = this.file.replace(/\\.template\\.html$/, '').split('/');\n const currentName = parts.pop();\n const currentDir = parts.join('/') || '.';\n\n const isValidDir = p => /^\\/[a-zA-Z0-9_\\-\\[\\]\\/]*$/.test(p) && !p.includes('..') && !p.includes('//');\n const dirToInternal = p => { const t = (p || '/').replace(/^\\//, '').replace(/\\/$/, ''); return t || '.'; };\n const currentDirDisplay = currentDir === '.' ? '/' : '/' + currentDir;\n\n const $dialog = Dialog.create(html`\n <div class=\"p\">\n <div class=\"p r mb bc-warning tc-warning\">\n <k-icon name=\"warning\"></k-icon>\n <strong>Warning:</strong> Moving a template may break pages that reference it by name.<br />Pages search for templates by name starting from their own directory up to the root.<br />Moving this template could cause those pages to fall back to the <code>default</code> template.\n </div>\n <div class=\"mb\">\n <label class=\"d-b mb-sm\"><strong>Location</strong></label>\n <input type=\"text\" id=\"dlg-move-dir\" class=\"full\" list=\"dlg-move-dir-list\" .value=\"${currentDirDisplay}\" placeholder=\"/\">\n <datalist id=\"dlg-move-dir-list\">\n ${directories.map(d => html`<option value=\"${d === '.' ? '/' : '/' + d}\">`)} \n </datalist>\n </div>\n <div>\n <label class=\"d-b mb-sm\"><strong>Template Name</strong></label>\n <input type=\"text\" id=\"dlg-move-name\" class=\"full\" .value=\"${currentName}\">\n <p class=\"mt-sm muted\"><small id=\"dlg-move-preview\"></small></p>\n </div>\n </div>\n `, {\n title: 'Move Template',\n confirmText: 'Save and Move Template',\n confirmAction: async () => {\n const dirInput = $dialog.querySelector('#dlg-move-dir').value.trim() || '/';\n const newName = $dialog.querySelector('#dlg-move-name').value.trim();\n if (!newName) {\n Toast.error('Template name is required');\n return;\n }\n if (!isValidDir(dirInput)) {\n Toast.error('Invalid directory path');\n return;\n }\n const newDir = dirToInternal(dirInput);\n const newFile = newDir === '.'\n ? `${newName}.template.html`\n : `${newDir}/${newName}.template.html`;\n\n this.saving = true;\n const [saveError] = await updateTemplate({ file: this.file, ...this.getFormState() });\n this.saving = false;\n if (saveError) {\n Toast.error(saveError.msg || 'Failed to save template');\n return;\n }\n\n const [moveError, moved] = await moveTemplate({ file: this.file, newFile });\n if (moveError) {\n Toast.error(moveError.msg || 'Failed to move template');\n return;\n }\n\n Toast.success('Template saved and moved');\n const newParam = moved.file.replace(/\\.template\\.html$/, '');\n setTimeout(() => {\n window.location.href = `/admin/content/templates/edit?template=${encodeURIComponent(newParam)}`;\n }, 1000);\n },\n cancelText: 'Cancel'\n });\n\n const updatePreview = () => {\n const dir = dirToInternal($dialog.querySelector('#dlg-move-dir').value || '/');\n const name = $dialog.querySelector('#dlg-move-name').value;\n const prefix = dir === '.' ? '/' : '/' + dir + '/';\n $dialog.querySelector('#dlg-move-preview').textContent = name ? prefix + name : '';\n };\n $dialog.querySelector('#dlg-move-dir').addEventListener('input', updatePreview);\n $dialog.querySelector('#dlg-move-name').addEventListener('input', updatePreview);\n updatePreview();\n };\n\n handleCopy = async () => {\n const [, dirData] = await listDirectories();\n const directories = dirData?.directories || ['.'];\n\n const parts = this.file.replace(/\\.template\\.html$/, '').split('/');\n const currentName = parts.pop();\n const currentDir = parts.join('/') || '.';\n\n const isValidDir = p => /^\\/[a-zA-Z0-9_\\-\\[\\]\\/]*$/.test(p) && !p.includes('..') && !p.includes('//');\n const dirToInternal = p => { const t = (p || '/').replace(/^\\//, '').replace(/\\/$/, ''); return t || '.'; };\n const currentDirDisplay = currentDir === '.' ? '/' : '/' + currentDir;\n\n const $dialog = Dialog.create(html`\n <div class=\"p\">\n <div class=\"mb\">\n <label class=\"d-b mb-sm\"><strong>Location</strong></label>\n <input type=\"text\" id=\"dlg-copy-dir\" class=\"full\" list=\"dlg-copy-dir-list\" .value=\"${currentDirDisplay}\" placeholder=\"/\">\n <datalist id=\"dlg-copy-dir-list\">\n ${directories.map(d => html`<option value=\"${d === '.' ? '/' : '/' + d}\">`)} \n </datalist>\n </div>\n <div>\n <label class=\"d-b mb-sm\"><strong>Template Name</strong></label>\n <input type=\"text\" id=\"dlg-copy-name\" class=\"full\" .value=\"${currentName}-copy\">\n <p class=\"mt-sm muted\"><small id=\"dlg-copy-preview\"></small></p>\n </div>\n </div>\n `, {\n title: 'Copy Template',\n confirmText: 'Copy Template',\n confirmAction: async () => {\n const dirInput = $dialog.querySelector('#dlg-copy-dir').value.trim() || '/';\n const newName = $dialog.querySelector('#dlg-copy-name').value.trim();\n if(!newName){\n Toast.error('Template name is required');\n return;\n }\n if(!isValidDir(dirInput)){\n Toast.error('Invalid directory path');\n return;\n }\n const directory = dirToInternal(dirInput);\n const [error, data] = await createTemplate({ directory: directory === '.' ? '' : directory, name: newName, copyFrom: this.file });\n if(error){\n Toast.error(error.msg || 'Failed to copy template');\n return;\n }\n Toast.success('Template copied');\n setTimeout(() => {\n window.location.href = `/admin/content/templates/edit?template=${encodeURIComponent(data.file.replace(/\\.template\\.html$/, ''))}`;\n }, 1000);\n },\n cancelText: 'Cancel'\n });\n\n const updatePreview = () => {\n const dir = dirToInternal($dialog.querySelector('#dlg-copy-dir').value || '/');\n const name = $dialog.querySelector('#dlg-copy-name').value;\n const prefix = dir === '.' ? '/' : '/' + dir + '/';\n $dialog.querySelector('#dlg-copy-preview').textContent = name ? prefix + name : '';\n };\n $dialog.querySelector('#dlg-copy-dir').addEventListener('input', updatePreview);\n $dialog.querySelector('#dlg-copy-name').addEventListener('input', updatePreview);\n updatePreview();\n };\n\n handleReset = () => {\n Dialog.confirm('Reset this template? Any unsaved changes will be lost.', confirmed => {\n if (!confirmed) return;\n this.template = { ...this.template };\n });\n };\n\n handleSave = async () => {\n this.saving = true;\n const state = this.getFormState();\n const [saveError, saved] = await updateTemplate({ file: this.file, markup: state.markup });\n this.saving = false;\n\n if(saveError){\n Toast.error(saveError.msg || 'Failed to save template');\n return;\n }\n\n this.template = { ...this.template, markup: state.markup, updatedAt: saved.updatedAt };\n\n const slugify = n => n.toLowerCase().trim().replace(/[^\\w\\s-]/g, '').replace(/[\\s_]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');\n const parts = this.file.replace(/\\.template\\.html$/, '').split('/');\n const currentSlug = parts.pop();\n const dir = parts.join('/');\n const newSlug = slugify(state.name);\n\n if(newSlug && newSlug !== currentSlug){\n const newFile = dir ? `${dir}/${newSlug}.template.html` : `${newSlug}.template.html`;\n const [moveError, moved] = await moveTemplate({ file: this.file, newFile });\n if(moveError){\n Toast.error(moveError.msg || 'Failed to rename template file');\n return;\n }\n Toast.success('Template saved and renamed');\n const newParam = moved.file.replace(/\\.template\\.html$/, '');\n setTimeout(() => {\n window.location.href = `/admin/content/templates/edit?template=${encodeURIComponent(newParam)}`;\n }, 1000);\n return;\n }\n\n document.title = `Edit: ${template.name} - Admin`;\n Toast.success('Template saved');\n };\n\n /*\n Render\n */\n\n render() {\n if (this.loading) return html`<div>Loading template...</div>`;\n\n if (this.error) return html`\n <div>\n <p>Template not found.</p>\n <a href=\"/admin/content/templates\">Back to Templates</a>\n </div>\n `;\n\n const { template } = this;\n const isCustom = template.owner === 'custom';\n const isLocked = template.locked;\n\n return html`\n ${isLocked ? html`\n <div class=\"p r mb bc-warning tc-warning\">\n <k-icon name=\"lock\"></k-icon> This template is locked and cannot be edited. It is managed by an extension.\n </div>\n ` : ''}\n <div class=\"d-f mb\">\n <div class=\"btn-grp mrh mb\">\n <a href=\"/admin/content/templates\" class=\"btn\">\n <k-icon name=\"arrow\" direction=\"left\"></k-icon> Templates\n </a>\n </div>\n <div class=\"flex\"></div>\n ${isCustom && !isLocked ? html`\n <div class=\"btn-grp mrh mb\">\n <button class=\"danger\" @click=\"${this.handleDelete}\"><k-icon name=\"delete\"></k-icon> Delete</button>\n <button @click=\"${this.handleMove}\"><k-icon name=\"drive_file_move\"></k-icon> Move Template</button>\n </div>\n ` : ''}\n <div class=\"btn-grp mrh mb\">\n <button @click=\"${this.handleCopy}\"><k-icon name=\"content_copy\"></k-icon> Copy Template</button>\n </div>\n ${!isLocked ? html`\n <div class=\"btn-grp mrh mb\">\n <button @click=\"${this.handleReset}\"><k-icon name=\"restart_alt\"></k-icon> Reset</button>\n <button id=\"saveBtn\" class=\"primary\" ?disabled=\"${this.saving}\" @click=\"${this.handleSave}\">\n <k-icon name=\"save\"></k-icon> Save\n </button>\n </div>\n ` : ''}\n </div>\n\n <h1 class=\"mb\">Template: ${template.name}</h1>\n\n <k-accordion>\n <k-accordion-header for-panel=\"metadata\">Metadata</k-accordion-header>\n <k-accordion-panel name=\"metadata\">\n <div class=\"p\">\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Name</strong></label>\n <input type=\"text\" id=\"metaName\" class=\"flex\" .value=\"${template.name || ''}\" ?disabled=\"${!isCustom || isLocked}\">\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Directory</strong></label>\n <span class=\"muted\">${(() => { const parts = this.file.replace(/\\.template\\.html$/, '').split('/'); parts.pop(); return parts.length ? parts.join('/') : '/'; })()}</span>\n ${isCustom && !isLocked ? html`\n <button class=\"icon-btn no-btn ph\" title=\"Move Template\" @click=\"${this.handleMove}\"><k-icon name=\"drive_file_move\"></k-icon></button>\n ` : ''}\n </div>\n ${template.author ? html`\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Author</strong></label>\n <span class=\"muted\">${template.author}</span>\n </div>\n ` : ''}\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Owner</strong></label>\n <span class=\"muted\">${template.owner || ''}</span>\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Created</strong></label>\n <span class=\"muted\">${template.createdAt ? new Date(template.createdAt).toLocaleString() : ''}</span>\n </div>\n <div class=\"d-f\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Updated</strong></label>\n <span class=\"muted\">${template.updatedAt ? new Date(template.updatedAt).toLocaleString() : ''}</span>\n </div>\n </div>\n </k-accordion-panel>\n\n <k-accordion-header for-panel=\"template\" active>Template</k-accordion-header>\n <k-accordion-panel name=\"template\" active>\n <div class=\"p\">\n <k-code-editor\n id=\"templateEditor\"\n class=\"r b\"\n language=\"html\"\n .value=\"${template.markup || ''}\"\n style=\"height: 70vh; min-height: 400px;\"\n ?disabled=\"${isLocked}\"\n ></k-code-editor>\n </div>\n </k-accordion-panel>\n </k-accordion>\n `;\n }\n}\n\ncustomElements.define('admin-template-editor', TemplateEditor);\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"src\\admin\\components\\TemplateEditor.js","names":["ShadowComponent","html","getTemplate","updateTemplate","deleteTemplates","moveTemplate","createTemplate","listDirectories","Dialog","Toast","TemplateEditor","static","loading","state","error","saving","template","constructor","super","this","file","connectedCallback","document","addEventListener","handleKeyDown","param","URLSearchParams","window","location","search","get","err","title","name","disconnectedCallback","removeEventListener","getFormState","root","shadowRoot","querySelector","value","markup","getValue","e","ctrlKey","metaKey","key","preventDefault","locked","handleSave","handleDelete","confirm","async","confirmed","msg","success","setTimeout","href","handleMove","dirData","directories","parts","replace","split","currentName","pop","currentDir","join","dirToInternal","p","currentDirDisplay","$dialog","create","map","d","confirmText","confirmAction","dirInput","trim","newName","test","includes","newDir","newFile","saveError","moveError","moved","newParam","encodeURIComponent","cancelText","updatePreview","dir","prefix","textContent","handleCopy","directory","data","copyFrom","handleReset","saved","updatedAt","currentSlug","newSlug","toLowerCase","render","isCustom","owner","isLocked","length","author","createdAt","Date","toLocaleString","customElements","define"],"sources":["0"],"sourcesContent":["import ShadowComponent from '/kempo-ui/components/ShadowComponent.js';\nimport { html } from '/kempo-ui/lit-all.min.js';\nimport { getTemplate, updateTemplate, deleteTemplates, moveTemplate, createTemplate, listDirectories } from '/kempo/sdk.js';\nimport Dialog from '/kempo-ui/components/Dialog.js';\nimport Toast from '/kempo-ui/components/Toast.js';\nimport '/kempo-ui/components/Icon.js';\nimport '/kempo-ui/components/Accordion.js';\nimport '/kempo-ui/components/CodeEditor.js';\n\nexport default class TemplateEditor extends ShadowComponent {\n static properties = {\n loading: { state: true },\n error: { state: true },\n saving: { state: true },\n template: { state: true }\n };\n\n constructor() {\n super();\n this.loading = true;\n this.error = false;\n this.saving = false;\n this.template = null;\n this.file = '';\n }\n\n async connectedCallback() {\n super.connectedCallback();\n document.addEventListener('keydown', this.handleKeyDown);\n const param = new URLSearchParams(window.location.search).get('template');\n this.file = param + '.template.html';\n\n if (!this.file || this.file === '.template.html') {\n this.loading = false;\n this.error = true;\n return;\n }\n\n const [err, template] = await getTemplate(this.file);\n this.loading = false;\n\n if (err) {\n this.error = true;\n return;\n }\n\n this.template = template;\n document.title = `Edit: ${template.name} - Admin`;\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n document.removeEventListener('keydown', this.handleKeyDown);\n }\n\n /*\n Helpers\n */\n\n getFormState() {\n const root = this.shadowRoot;\n return {\n name: root.querySelector('#metaName')?.value ?? this.template.name,\n markup: root.querySelector('#templateEditor')?.getValue() ?? this.template.markup\n };\n }\n\n /*\n Event Handlers\n */\n\n handleKeyDown = e => {\n if ((e.ctrlKey || e.metaKey) && e.key === 's') {\n e.preventDefault();\n if (!this.saving && !this.template?.locked) this.handleSave();\n }\n };\n\n handleDelete = () => {\n Dialog.confirm('Delete this template? This action cannot be undone.', async confirmed => {\n if (!confirmed) return;\n const [error] = await deleteTemplates([this.file]);\n if (error) {\n Toast.error(error.msg || 'Failed to delete template');\n return;\n }\n Toast.success('Template deleted');\n setTimeout(() => { window.location.href = '/admin/content/templates'; }, 1000);\n });\n };\n\n handleMove = async () => {\n const [, dirData] = await listDirectories();\n const directories = dirData?.directories || ['.'];\n\n const parts = this.file.replace(/\\.template\\.html$/, '').split('/');\n const currentName = parts.pop();\n const currentDir = parts.join('/') || '.';\n\n const isValidDir = p => /^\\/[a-zA-Z0-9_\\-\\[\\]\\/]*$/.test(p) && !p.includes('..') && !p.includes('//');\n const dirToInternal = p => { const t = (p || '/').replace(/^\\//, '').replace(/\\/$/, ''); return t || '.'; };\n const currentDirDisplay = currentDir === '.' ? '/' : '/' + currentDir;\n\n const $dialog = Dialog.create(html`\n <div class=\"p\">\n <div class=\"p r mb bc-warning tc-warning\">\n <k-icon name=\"warning\"></k-icon>\n <strong>Warning:</strong> Moving a template may break pages that reference it by name.<br />Pages search for templates by name starting from their own directory up to the root.<br />Moving this template could cause those pages to fall back to the <code>default</code> template.\n </div>\n <div class=\"mb\">\n <label class=\"d-b mb-sm\"><strong>Location</strong></label>\n <input type=\"text\" id=\"dlg-move-dir\" class=\"full\" list=\"dlg-move-dir-list\" .value=\"${currentDirDisplay}\" placeholder=\"/\">\n <datalist id=\"dlg-move-dir-list\">\n ${directories.map(d => html`<option value=\"${d === '.' ? '/' : '/' + d}\">`)} \n </datalist>\n </div>\n <div>\n <label class=\"d-b mb-sm\"><strong>Template Name</strong></label>\n <input type=\"text\" id=\"dlg-move-name\" class=\"full\" .value=\"${currentName}\">\n <p class=\"mt-sm muted\"><small id=\"dlg-move-preview\"></small></p>\n </div>\n </div>\n `, {\n title: 'Move Template',\n confirmText: 'Save and Move Template',\n confirmAction: async () => {\n const dirInput = $dialog.querySelector('#dlg-move-dir').value.trim() || '/';\n const newName = $dialog.querySelector('#dlg-move-name').value.trim();\n if (!newName) {\n Toast.error('Template name is required');\n return;\n }\n if (!isValidDir(dirInput)) {\n Toast.error('Invalid directory path');\n return;\n }\n const newDir = dirToInternal(dirInput);\n const newFile = newDir === '.'\n ? `${newName}.template.html`\n : `${newDir}/${newName}.template.html`;\n\n this.saving = true;\n const [saveError] = await updateTemplate({ file: this.file, ...this.getFormState() });\n this.saving = false;\n if (saveError) {\n Toast.error(saveError.msg || 'Failed to save template');\n return;\n }\n\n const [moveError, moved] = await moveTemplate({ file: this.file, newFile });\n if (moveError) {\n Toast.error(moveError.msg || 'Failed to move template');\n return;\n }\n\n Toast.success('Template saved and moved');\n const newParam = moved.file.replace(/\\.template\\.html$/, '');\n setTimeout(() => {\n window.location.href = `/admin/content/templates/edit?template=${encodeURIComponent(newParam)}`;\n }, 1000);\n },\n cancelText: 'Cancel'\n });\n\n const updatePreview = () => {\n const dir = dirToInternal($dialog.querySelector('#dlg-move-dir').value || '/');\n const name = $dialog.querySelector('#dlg-move-name').value;\n const prefix = dir === '.' ? '/' : '/' + dir + '/';\n $dialog.querySelector('#dlg-move-preview').textContent = name ? prefix + name : '';\n };\n $dialog.querySelector('#dlg-move-dir').addEventListener('input', updatePreview);\n $dialog.querySelector('#dlg-move-name').addEventListener('input', updatePreview);\n updatePreview();\n };\n\n handleCopy = async () => {\n const [, dirData] = await listDirectories();\n const directories = dirData?.directories || ['.'];\n\n const parts = this.file.replace(/\\.template\\.html$/, '').split('/');\n const currentName = parts.pop();\n const currentDir = parts.join('/') || '.';\n\n const isValidDir = p => /^\\/[a-zA-Z0-9_\\-\\[\\]\\/]*$/.test(p) && !p.includes('..') && !p.includes('//');\n const dirToInternal = p => { const t = (p || '/').replace(/^\\//, '').replace(/\\/$/, ''); return t || '.'; };\n const currentDirDisplay = currentDir === '.' ? '/' : '/' + currentDir;\n\n const $dialog = Dialog.create(html`\n <div class=\"p\">\n <div class=\"mb\">\n <label class=\"d-b mb-sm\"><strong>Location</strong></label>\n <input type=\"text\" id=\"dlg-copy-dir\" class=\"full\" list=\"dlg-copy-dir-list\" .value=\"${currentDirDisplay}\" placeholder=\"/\">\n <datalist id=\"dlg-copy-dir-list\">\n ${directories.map(d => html`<option value=\"${d === '.' ? '/' : '/' + d}\">`)} \n </datalist>\n </div>\n <div>\n <label class=\"d-b mb-sm\"><strong>Template Name</strong></label>\n <input type=\"text\" id=\"dlg-copy-name\" class=\"full\" .value=\"${currentName}-copy\">\n <p class=\"mt-sm muted\"><small id=\"dlg-copy-preview\"></small></p>\n </div>\n </div>\n `, {\n title: 'Copy Template',\n confirmText: 'Copy Template',\n confirmAction: async () => {\n const dirInput = $dialog.querySelector('#dlg-copy-dir').value.trim() || '/';\n const newName = $dialog.querySelector('#dlg-copy-name').value.trim();\n if(!newName){\n Toast.error('Template name is required');\n return;\n }\n if(!isValidDir(dirInput)){\n Toast.error('Invalid directory path');\n return;\n }\n const directory = dirToInternal(dirInput);\n const [error, data] = await createTemplate({ directory: directory === '.' ? '' : directory, name: newName, copyFrom: this.file });\n if(error){\n Toast.error(error.msg || 'Failed to copy template');\n return;\n }\n Toast.success('Template copied');\n setTimeout(() => {\n window.location.href = `/admin/content/templates/edit?template=${encodeURIComponent(data.file.replace(/\\.template\\.html$/, ''))}`;\n }, 1000);\n },\n cancelText: 'Cancel'\n });\n\n const updatePreview = () => {\n const dir = dirToInternal($dialog.querySelector('#dlg-copy-dir').value || '/');\n const name = $dialog.querySelector('#dlg-copy-name').value;\n const prefix = dir === '.' ? '/' : '/' + dir + '/';\n $dialog.querySelector('#dlg-copy-preview').textContent = name ? prefix + name : '';\n };\n $dialog.querySelector('#dlg-copy-dir').addEventListener('input', updatePreview);\n $dialog.querySelector('#dlg-copy-name').addEventListener('input', updatePreview);\n updatePreview();\n };\n\n handleReset = () => {\n Dialog.confirm('Reset this template? Any unsaved changes will be lost.', confirmed => {\n if (!confirmed) return;\n this.template = { ...this.template };\n });\n };\n\n handleSave = async () => {\n this.saving = true;\n const state = this.getFormState();\n const [saveError, saved] = await updateTemplate({ file: this.file, markup: state.markup });\n this.saving = false;\n\n if(saveError){\n Toast.error(saveError.msg || 'Failed to save template');\n return;\n }\n\n this.template = { ...this.template, markup: state.markup, updatedAt: saved.updatedAt };\n\n const slugify = n => n.toLowerCase().trim().replace(/[^\\w\\s-]/g, '').replace(/[\\s_]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');\n const parts = this.file.replace(/\\.template\\.html$/, '').split('/');\n const currentSlug = parts.pop();\n const dir = parts.join('/');\n const newSlug = slugify(state.name);\n\n if(newSlug && newSlug !== currentSlug){\n const newFile = dir ? `${dir}/${newSlug}.template.html` : `${newSlug}.template.html`;\n const [moveError, moved] = await moveTemplate({ file: this.file, newFile });\n if(moveError){\n Toast.error(moveError.msg || 'Failed to rename template file');\n return;\n }\n Toast.success('Template saved and renamed');\n const newParam = moved.file.replace(/\\.template\\.html$/, '');\n setTimeout(() => {\n window.location.href = `/admin/content/templates/edit?template=${encodeURIComponent(newParam)}`;\n }, 1000);\n return;\n }\n\n document.title = `Edit: ${template.name} - Admin`;\n Toast.success('Template saved');\n };\n\n /*\n Render\n */\n\n render() {\n if (this.loading) return html`<div>Loading template...</div>`;\n\n if (this.error) return html`\n <div>\n <p>Template not found.</p>\n <a href=\"/admin/content/templates\">Back to Templates</a>\n </div>\n `;\n\n const { template } = this;\n const isCustom = template.owner === 'custom';\n const isLocked = template.locked;\n\n return html`\n ${isLocked ? html`\n <div class=\"p r mb bc-warning tc-warning\">\n <k-icon name=\"lock\"></k-icon> This template is locked and cannot be edited. ${template.owner === 'custom' ? 'Locked by developer' : `Managed by: ${template.owner || 'external system'}`}\n </div>\n ` : ''}\n <div class=\"d-f mb\">\n <div class=\"btn-grp mrh mb\">\n <a href=\"/admin/content/templates\" class=\"btn\">\n <k-icon name=\"arrow\" direction=\"left\"></k-icon> Templates\n </a>\n </div>\n <div class=\"flex\"></div>\n ${isCustom && !isLocked ? html`\n <div class=\"btn-grp mrh mb\">\n <button class=\"danger\" @click=\"${this.handleDelete}\"><k-icon name=\"delete\"></k-icon> Delete</button>\n <button @click=\"${this.handleMove}\"><k-icon name=\"drive_file_move\"></k-icon> Move Template</button>\n </div>\n ` : ''}\n <div class=\"btn-grp mrh mb\">\n <button @click=\"${this.handleCopy}\"><k-icon name=\"content_copy\"></k-icon> Copy Template</button>\n </div>\n ${!isLocked ? html`\n <div class=\"btn-grp mrh mb\">\n <button @click=\"${this.handleReset}\"><k-icon name=\"restart_alt\"></k-icon> Reset</button>\n <button id=\"saveBtn\" class=\"primary\" ?disabled=\"${this.saving}\" @click=\"${this.handleSave}\">\n <k-icon name=\"save\"></k-icon> Save\n </button>\n </div>\n ` : ''}\n </div>\n\n <h1 class=\"mb\">Template: ${template.name}</h1>\n\n <k-accordion>\n <k-accordion-header for-panel=\"metadata\">Metadata</k-accordion-header>\n <k-accordion-panel name=\"metadata\">\n <div class=\"p\">\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Name</strong></label>\n <input type=\"text\" id=\"metaName\" class=\"flex\" .value=\"${template.name || ''}\" ?disabled=\"${!isCustom || isLocked}\">\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Directory</strong></label>\n <span class=\"muted\">${(() => { const parts = this.file.replace(/\\.template\\.html$/, '').split('/'); parts.pop(); return parts.length ? parts.join('/') : '/'; })()}</span>\n ${isCustom && !isLocked ? html`\n <button class=\"icon-btn no-btn ph\" title=\"Move Template\" @click=\"${this.handleMove}\"><k-icon name=\"drive_file_move\"></k-icon></button>\n ` : ''}\n </div>\n ${template.author ? html`\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Author</strong></label>\n <span class=\"muted\">${template.author}</span>\n </div>\n ` : ''}\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Owner</strong></label>\n <span class=\"muted\">${template.owner || ''}</span>\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Created</strong></label>\n <span class=\"muted\">${template.createdAt ? new Date(template.createdAt).toLocaleString() : ''}</span>\n </div>\n <div class=\"d-f\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Updated</strong></label>\n <span class=\"muted\">${template.updatedAt ? new Date(template.updatedAt).toLocaleString() : ''}</span>\n </div>\n </div>\n </k-accordion-panel>\n\n <k-accordion-header for-panel=\"template\" active>Template</k-accordion-header>\n <k-accordion-panel name=\"template\" active>\n <div class=\"p\">\n <k-code-editor\n id=\"templateEditor\"\n class=\"r b\"\n language=\"html\"\n .value=\"${template.markup || ''}\"\n style=\"height: 70vh; min-height: 400px;\"\n ?disabled=\"${isLocked}\"\n ></k-code-editor>\n </div>\n </k-accordion-panel>\n </k-accordion>\n `;\n }\n}\n\ncustomElements.define('admin-template-editor', TemplateEditor);\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import
|
|
1
|
+
import t from"/kempo-ui/components/ShadowComponent.js";import{html as e,nothing as s}from"/kempo-ui/lit-all.min.js";import"/admin/components/Monaco.js";const a=new Set(["html","css","javascript","json","xml"]),i={html:"html",css:"css",javascript:"javascript",json:"json",xml:"xml"};export default class n extends t{static get properties(){return{type:{type:String,reflect:!0},readonly:{type:Boolean,reflect:!0},disabled:{type:Boolean,reflect:!0},placeholder:{type:String},min:{type:String},max:{type:String},step:{type:String},rows:{type:Number},height:{type:String}}}#t="";#e=null;constructor(){super(),this.type="string",this.readonly=!1,this.disabled=!1,this.placeholder="",this.step="any",this.rows=12,this.height="400px"}get value(){if(a.has(this.type))return this.#e?.value??this.#t;const t=this.renderRoot?.querySelector("[data-ve-input]");return t?"boolean"===this.type?"true"===t.value:"number"===this.type?Number(t.value):t.value:this.#t}set value(t){this.#t=t??"",a.has(this.type)&&this.#e?this.#e.value=String(this.#t):this.requestUpdate()}updated(t){t.has("type")&&this.#s(),this.#e&&((t.has("readonly")||t.has("disabled"))&&(this.#e.readOnly=this.readonly||this.disabled),t.has("height")&&(this.#e.height=this.height))}disconnectedCallback(){super.disconnectedCallback(),this.#a()}#s=()=>{a.has(this.type)?this.#e?this.#e.language=i[this.type]||"plaintext":this.#i():this.#a()};#i=()=>{this.#e=document.createElement("admin-monaco"),this.#e.language=i[this.type]||"plaintext",this.#e.readOnly=this.readonly||this.disabled,this.#e.height=this.height,this.#e.value=String(this.#t),this.#e.addEventListener("change",this.#n),this.appendChild(this.#e)};#a=()=>{this.#e&&(this.#e.removeEventListener("change",this.#n),this.#e.remove(),this.#e=null)};#o=t=>{this.dispatchEvent(new Event(t,{bubbles:!0,composed:!0}))};#n=()=>{this.#t=this.#e.value,this.#o("input"),this.#o("change")};#l=()=>{const t=this.renderRoot?.querySelector("[data-ve-input]");t&&(this.#t=t.value),this.#o("input")};#h=()=>{const t=this.renderRoot?.querySelector("[data-ve-input]");t&&(this.#t=t.value),this.#o("change")};render(){return a.has(this.type)?e`<slot></slot>`:"boolean"===this.type?e`<select
|
|
2
2
|
data-ve-input
|
|
3
3
|
class="full"
|
|
4
4
|
?disabled="${this.disabled||this.readonly}"
|
|
5
|
-
@change="${this.#
|
|
5
|
+
@change="${this.#h}"
|
|
6
6
|
>
|
|
7
7
|
<option value="true" ?selected="${"true"===String(this.#t)}">true</option>
|
|
8
8
|
<option value="false" ?selected="${"true"!==String(this.#t)}">false</option>
|
|
9
|
-
</select>`:"number"===this.type?
|
|
9
|
+
</select>`:"number"===this.type?e`<input
|
|
10
10
|
data-ve-input
|
|
11
11
|
type="number"
|
|
12
12
|
class="full"
|
|
13
13
|
.value="${String(this.#t??0)}"
|
|
14
|
-
placeholder="${this.placeholder||
|
|
15
|
-
step="${this.step||
|
|
16
|
-
min="${this.min??
|
|
17
|
-
max="${this.max??
|
|
14
|
+
placeholder="${this.placeholder||s}"
|
|
15
|
+
step="${this.step||s}"
|
|
16
|
+
min="${this.min??s}"
|
|
17
|
+
max="${this.max??s}"
|
|
18
18
|
?readonly="${this.readonly}"
|
|
19
19
|
?disabled="${this.disabled}"
|
|
20
|
-
@input="${this.#
|
|
21
|
-
@change="${this.#
|
|
22
|
-
>`:"color"===this.type?
|
|
20
|
+
@input="${this.#l}"
|
|
21
|
+
@change="${this.#h}"
|
|
22
|
+
>`:"color"===this.type?e`<input
|
|
23
23
|
data-ve-input
|
|
24
24
|
type="color"
|
|
25
25
|
.value="${this.#t||"#000000"}"
|
|
26
26
|
?disabled="${this.disabled||this.readonly}"
|
|
27
|
-
@input="${this.#
|
|
28
|
-
@change="${this.#
|
|
29
|
-
>`:
|
|
27
|
+
@input="${this.#l}"
|
|
28
|
+
@change="${this.#h}"
|
|
29
|
+
>`:e`<textarea
|
|
30
30
|
data-ve-input
|
|
31
31
|
class="full ff-mono"
|
|
32
32
|
rows="${this.rows}"
|
|
33
|
-
placeholder="${this.placeholder||
|
|
33
|
+
placeholder="${this.placeholder||s}"
|
|
34
34
|
?readonly="${this.readonly}"
|
|
35
35
|
?disabled="${this.disabled}"
|
|
36
|
-
@input="${this.#
|
|
37
|
-
@change="${this.#
|
|
36
|
+
@input="${this.#l}"
|
|
37
|
+
@change="${this.#h}"
|
|
38
38
|
.value="${String(this.#t)}"
|
|
39
|
-
></textarea>`}}customElements.define("admin-value-editor",
|
|
39
|
+
></textarea>`}}customElements.define("admin-value-editor",n);
|
|
40
40
|
//# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\ValueEditor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src\\admin\\components\\ValueEditor.js","names":["ShadowComponent","html","nothing","CODE_TYPES","Set","TYPE_TO_LANG","css","javascript","json","xml","ValueEditor","properties","type","String","reflect","readonly","Boolean","disabled","placeholder","min","max","step","rows","Number","height","value","monacoEl","constructor","super","this","has","el","renderRoot","querySelector","v","requestUpdate","updated","changedProperties","syncEditor","readOnly","disconnectedCallback","destroyMonaco","language","createMonaco","document","createElement","addEventListener","onMonacoChange","appendChild","removeEventListener","remove","emit","name","dispatchEvent","Event","bubbles","composed","onInput","onChange","render","customElements","define"],"sources":["0"],"sourcesContent":["import ShadowComponent from '/kempo-ui/components/ShadowComponent.js';\r\nimport { html, nothing } from '/kempo-ui/lit-all.min.js';\r\nimport '/admin/components/Monaco.js';\r\n\r\nconst CODE_TYPES = new Set(['html', 'css', 'javascript', 'json', 'xml']);\r\nconst TYPE_TO_LANG = { html: 'html', css: 'css', javascript: 'javascript', json: 'json', xml: 'xml' };\r\n\r\nexport default class ValueEditor extends ShadowComponent {\r\n\t/*\r\n\t\tReactive Properties\r\n\t*/\r\n\r\n\tstatic get properties() {\r\n\t\treturn {\r\n\t\t\ttype: { type: String, reflect: true },\r\n\t\t\treadonly: { type: Boolean, reflect: true },\r\n\t\t\tdisabled: { type: Boolean, reflect: true },\r\n\t\t\tplaceholder: { type: String },\r\n\t\t\tmin: { type: String },\r\n\t\t\tmax: { type: String },\r\n\t\t\tstep: { type: String },\r\n\t\t\trows: { type: Number },\r\n\t\t\theight: { type: String },\r\n\t\t};\r\n\t}\r\n\r\n\t#value = '';\r\n\t#monacoEl = null;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis.type = 'string';\r\n\t\tthis.readonly = false;\r\n\t\tthis.disabled = false;\r\n\t\tthis.placeholder = '';\r\n\t\tthis.step = 'any';\r\n\t\tthis.rows = 12;\r\n\t\tthis.height = '400px';\r\n\t}\r\n\r\n\t/*\r\n\t\tValue Accessors\r\n\t*/\r\n\r\n\tget value() {\r\n\t\tif(CODE_TYPES.has(this.type)){\r\n\t\t\treturn this.#monacoEl?.value ?? this.#value;\r\n\t\t}\r\n\t\tconst el = this.renderRoot?.querySelector('[data-ve-input]');\r\n\t\tif(!el) return this.#value;\r\n\t\tif(this.type === 'boolean') return el.value === 'true';\r\n\t\tif(this.type === 'number') return Number(el.value);\r\n\t\treturn el.value;\r\n\t}\r\n\r\n\tset value(v) {\r\n\t\tthis.#value = v ?? '';\r\n\t\tif(CODE_TYPES.has(this.type) && this.#monacoEl){\r\n\t\t\tthis.#monacoEl.value = String(this.#value);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.requestUpdate();\r\n\t}\r\n\r\n\t/*\r\n\t\tLifecycle\r\n\t*/\r\n\r\n\tupdated(changedProperties) {\r\n\t\tif(changedProperties.has('type')) this.#syncEditor();\r\n\t\tif(!this.#monacoEl) return;\r\n\t\tif(changedProperties.has('readonly') || changedProperties.has('disabled')){\r\n\t\t\tthis.#monacoEl.readOnly = this.readonly || this.disabled;\r\n\t\t}\r\n\t\tif(changedProperties.has('height')){\r\n\t\t\tthis.#monacoEl.height = this.height;\r\n\t\t}\r\n\t}\r\n\r\n\tdisconnectedCallback() {\r\n\t\tsuper.disconnectedCallback();\r\n\t\tthis.#destroyMonaco();\r\n\t}\r\n\r\n\t/*\r\n\t\tMonaco Management (light DOM child projected via <slot> for style compat)\r\n\t*/\r\n\r\n\t#syncEditor = () => {\r\n\t\tif(CODE_TYPES.has(this.type)){\r\n\t\t\tif(this.#monacoEl){\r\n\t\t\t\tthis.#monacoEl.language = TYPE_TO_LANG[this.type] || 'plaintext';\r\n\t\t\t} else {\r\n\t\t\t\tthis.#createMonaco();\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tthis.#destroyMonaco();\r\n\t\t}\r\n\t};\r\n\r\n\t#createMonaco = () => {\r\n\t\tthis.#monacoEl = document.createElement('admin-monaco');\r\n\t\tthis.#monacoEl.language = TYPE_TO_LANG[this.type] || 'plaintext';\r\n\t\tthis.#monacoEl.readOnly = this.readonly || this.disabled;\r\n\t\tthis.#monacoEl.height = this.height;\r\n\t\tthis.#monacoEl.value = String(this.#value);\r\n\t\tthis.#monacoEl.addEventListener('change', this.#onMonacoChange);\r\n\t\tthis.appendChild(this.#monacoEl);\r\n\t};\r\n\r\n\t#destroyMonaco = () => {\r\n\t\tif(!this.#monacoEl) return;\r\n\t\tthis.#monacoEl.removeEventListener('change', this.#onMonacoChange);\r\n\t\tthis.#monacoEl.remove();\r\n\t\tthis.#monacoEl = null;\r\n\t};\r\n\r\n\t/*\r\n\t\tEvent Handlers\r\n\t*/\r\n\r\n\t#emit = name => {\r\n\t\tthis.dispatchEvent(new Event(name, { bubbles: true, composed: true }));\r\n\t};\r\n\r\n\t#onMonacoChange = () => {\r\n\t\tthis.#value = this.#monacoEl.value;\r\n\t\tthis.#emit('input');\r\n\t\tthis.#emit('change');\r\n\t};\r\n\r\n\t#onInput = () => {\r\n\t\tconst el = this.renderRoot?.querySelector('[data-ve-input]');\r\n\t\tif(el) this.#value = el.value;\r\n\t\tthis.#emit('input');\r\n\t};\r\n\r\n\t#onChange = () => {\r\n\t\tconst el = this.renderRoot?.querySelector('[data-ve-input]');\r\n\t\tif(el) this.#value = el.value;\r\n\t\tthis.#emit('change');\r\n\t};\r\n\r\n\t/*\r\n\t\tRender\r\n\t*/\r\n\r\n\trender() {\r\n\t\tif(CODE_TYPES.has(this.type)){\r\n\t\t\treturn html`<slot></slot>`;\r\n\t\t}\r\n\r\n\t\tif(this.type === 'boolean'){\r\n\t\t\treturn html`<select\r\n\t\t\t\tdata-ve-input\r\n\t\t\t\tclass=\"full\"\r\n\t\t\t\t?disabled=\"${this.disabled || this.readonly}\"\r\n\t\t\t\t@change=\"${this.#onChange}\"\r\n\t\t\t>\r\n\t\t\t\t<option value=\"true\" ?selected=\"${String(this.#value) === 'true'}\">true</option>\r\n\t\t\t\t<option value=\"false\" ?selected=\"${String(this.#value) !== 'true'}\">false</option>\r\n\t\t\t</select>`;\r\n\t\t}\r\n\r\n\t\tif(this.type === 'number'){\r\n\t\t\treturn html`<input\r\n\t\t\t\tdata-ve-input\r\n\t\t\t\ttype=\"number\"\r\n\t\t\t\tclass=\"full\"\r\n\t\t\t\t.value=\"${String(this.#value ?? 0)}\"\r\n\t\t\t\tplaceholder=\"${this.placeholder || nothing}\"\r\n\t\t\t\tstep=\"${this.step || nothing}\"\r\n\t\t\t\tmin=\"${this.min ?? nothing}\"\r\n\t\t\t\tmax=\"${this.max ?? nothing}\"\r\n\t\t\t\t?readonly=\"${this.readonly}\"\r\n\t\t\t\t?disabled=\"${this.disabled}\"\r\n\t\t\t\t@input=\"${this.#onInput}\"\r\n\t\t\t\t@change=\"${this.#onChange}\"\r\n\t\t\t>`;\r\n\t\t}\r\n\r\n\t\tif(this.type === 'color'){\r\n\t\t\treturn html`<input\r\n\t\t\t\tdata-ve-input\r\n\t\t\t\ttype=\"color\"\r\n\t\t\t\t.value=\"${this.#value || '#000000'}\"\r\n\t\t\t\t?disabled=\"${this.disabled || this.readonly}\"\r\n\t\t\t\t@input=\"${this.#onInput}\"\r\n\t\t\t\t@change=\"${this.#onChange}\"\r\n\t\t\t>`;\r\n\t\t}\r\n\r\n\t\treturn html`<textarea\r\n\t\t\tdata-ve-input\r\n\t\t\tclass=\"full ff-mono\"\r\n\t\t\trows=\"${this.rows}\"\r\n\t\t\tplaceholder=\"${this.placeholder || nothing}\"\r\n\t\t\t?readonly=\"${this.readonly}\"\r\n\t\t\t?disabled=\"${this.disabled}\"\r\n\t\t\t@input=\"${this.#onInput}\"\r\n\t\t\t@change=\"${this.#onChange}\"\r\n\t\t\t.value=\"${String(this.#value)}\"\r\n\t\t></textarea>`;\r\n\t}\r\n}\r\n\r\ncustomElements.define('admin-value-editor', ValueEditor);\r\n"],"mappings":"OAAOA,
|
|
1
|
+
{"version":3,"file":"src\\admin\\components\\ValueEditor.js","names":["ShadowComponent","html","nothing","CODE_TYPES","Set","TYPE_TO_LANG","css","javascript","json","xml","ValueEditor","properties","type","String","reflect","readonly","Boolean","disabled","placeholder","min","max","step","rows","Number","height","value","monacoEl","constructor","super","this","has","el","renderRoot","querySelector","v","requestUpdate","updated","changedProperties","syncEditor","readOnly","disconnectedCallback","destroyMonaco","language","createMonaco","document","createElement","addEventListener","onMonacoChange","appendChild","removeEventListener","remove","emit","name","dispatchEvent","Event","bubbles","composed","onInput","onChange","render","customElements","define"],"sources":["0"],"sourcesContent":["import ShadowComponent from '/kempo-ui/components/ShadowComponent.js';\r\nimport { html, nothing } from '/kempo-ui/lit-all.min.js';\r\nimport '/admin/components/Monaco.js';\r\n\r\nconst CODE_TYPES = new Set(['html', 'css', 'javascript', 'json', 'xml']);\r\nconst TYPE_TO_LANG = { html: 'html', css: 'css', javascript: 'javascript', json: 'json', xml: 'xml' };\r\n\r\nexport default class ValueEditor extends ShadowComponent {\r\n\t/*\r\n\t\tReactive Properties\r\n\t*/\r\n\r\n\tstatic get properties() {\r\n\t\treturn {\r\n\t\t\ttype: { type: String, reflect: true },\r\n\t\t\treadonly: { type: Boolean, reflect: true },\r\n\t\t\tdisabled: { type: Boolean, reflect: true },\r\n\t\t\tplaceholder: { type: String },\r\n\t\t\tmin: { type: String },\r\n\t\t\tmax: { type: String },\r\n\t\t\tstep: { type: String },\r\n\t\t\trows: { type: Number },\r\n\t\t\theight: { type: String },\r\n\t\t};\r\n\t}\r\n\r\n\t#value = '';\r\n\t#monacoEl = null;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis.type = 'string';\r\n\t\tthis.readonly = false;\r\n\t\tthis.disabled = false;\r\n\t\tthis.placeholder = '';\r\n\t\tthis.step = 'any';\r\n\t\tthis.rows = 12;\r\n\t\tthis.height = '400px';\r\n\t}\r\n\r\n\t/*\r\n\t\tValue Accessors\r\n\t*/\r\n\r\n\tget value() {\r\n\t\tif(CODE_TYPES.has(this.type)){\r\n\t\t\treturn this.#monacoEl?.value ?? this.#value;\r\n\t\t}\r\n\t\tconst el = this.renderRoot?.querySelector('[data-ve-input]');\r\n\t\tif(!el) return this.#value;\r\n\t\tif(this.type === 'boolean') return el.value === 'true';\r\n\t\tif(this.type === 'number') return Number(el.value);\r\n\t\treturn el.value;\r\n\t}\r\n\r\n\tset value(v) {\r\n\t\tthis.#value = v ?? '';\r\n\t\tif(CODE_TYPES.has(this.type) && this.#monacoEl){\r\n\t\t\tthis.#monacoEl.value = String(this.#value);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.requestUpdate();\r\n\t}\r\n\r\n\t/*\r\n\t\tLifecycle\r\n\t*/\r\n\r\n\tupdated(changedProperties) {\r\n\t\tif(changedProperties.has('type')) this.#syncEditor();\r\n\t\tif(!this.#monacoEl) return;\r\n\t\tif(changedProperties.has('readonly') || changedProperties.has('disabled')){\r\n\t\t\tthis.#monacoEl.readOnly = this.readonly || this.disabled;\r\n\t\t}\r\n\t\tif(changedProperties.has('height')){\r\n\t\t\tthis.#monacoEl.height = this.height;\r\n\t\t}\r\n\t}\r\n\r\n\tdisconnectedCallback() {\r\n\t\tsuper.disconnectedCallback();\r\n\t\tthis.#destroyMonaco();\r\n\t}\r\n\r\n\t/*\r\n\t\tMonaco Management (light DOM child projected via <slot> for style compat)\r\n\t*/\r\n\r\n\t#syncEditor = () => {\r\n\t\tif(CODE_TYPES.has(this.type)){\r\n\t\t\tif(this.#monacoEl){\r\n\t\t\t\tthis.#monacoEl.language = TYPE_TO_LANG[this.type] || 'plaintext';\r\n\t\t\t} else {\r\n\t\t\t\tthis.#createMonaco();\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tthis.#destroyMonaco();\r\n\t\t}\r\n\t};\r\n\r\n\t#createMonaco = () => {\r\n\t\tthis.#monacoEl = document.createElement('admin-monaco');\r\n\t\tthis.#monacoEl.language = TYPE_TO_LANG[this.type] || 'plaintext';\r\n\t\tthis.#monacoEl.readOnly = this.readonly || this.disabled;\r\n\t\tthis.#monacoEl.height = this.height;\r\n\t\tthis.#monacoEl.value = String(this.#value);\r\n\t\tthis.#monacoEl.addEventListener('change', this.#onMonacoChange);\r\n\t\tthis.appendChild(this.#monacoEl);\r\n\t};\r\n\r\n\t#destroyMonaco = () => {\r\n\t\tif(!this.#monacoEl) return;\r\n\t\tthis.#monacoEl.removeEventListener('change', this.#onMonacoChange);\r\n\t\tthis.#monacoEl.remove();\r\n\t\tthis.#monacoEl = null;\r\n\t};\r\n\r\n\t/*\r\n\t\tEvent Handlers\r\n\t*/\r\n\r\n\t#emit = name => {\r\n\t\tthis.dispatchEvent(new Event(name, { bubbles: true, composed: true }));\r\n\t};\r\n\r\n\t#onMonacoChange = () => {\r\n\t\tthis.#value = this.#monacoEl.value;\r\n\t\tthis.#emit('input');\r\n\t\tthis.#emit('change');\r\n\t};\r\n\r\n\t#onInput = () => {\r\n\t\tconst el = this.renderRoot?.querySelector('[data-ve-input]');\r\n\t\tif(el) this.#value = el.value;\r\n\t\tthis.#emit('input');\r\n\t};\r\n\r\n\t#onChange = () => {\r\n\t\tconst el = this.renderRoot?.querySelector('[data-ve-input]');\r\n\t\tif(el) this.#value = el.value;\r\n\t\tthis.#emit('change');\r\n\t};\r\n\r\n\t/*\r\n\t\tRender\r\n\t*/\r\n\r\n\trender() {\r\n\t\tif(CODE_TYPES.has(this.type)){\r\n\t\t\treturn html`<slot></slot>`;\r\n\t\t}\r\n\r\n\t\tif(this.type === 'boolean'){\r\n\t\t\treturn html`<select\r\n\t\t\t\tdata-ve-input\r\n\t\t\t\tclass=\"full\"\r\n\t\t\t\t?disabled=\"${this.disabled || this.readonly}\"\r\n\t\t\t\t@change=\"${this.#onChange}\"\r\n\t\t\t>\r\n\t\t\t\t<option value=\"true\" ?selected=\"${String(this.#value) === 'true'}\">true</option>\r\n\t\t\t\t<option value=\"false\" ?selected=\"${String(this.#value) !== 'true'}\">false</option>\r\n\t\t\t</select>`;\r\n\t\t}\r\n\r\n\t\tif(this.type === 'number'){\r\n\t\t\treturn html`<input\r\n\t\t\t\tdata-ve-input\r\n\t\t\t\ttype=\"number\"\r\n\t\t\t\tclass=\"full\"\r\n\t\t\t\t.value=\"${String(this.#value ?? 0)}\"\r\n\t\t\t\tplaceholder=\"${this.placeholder || nothing}\"\r\n\t\t\t\tstep=\"${this.step || nothing}\"\r\n\t\t\t\tmin=\"${this.min ?? nothing}\"\r\n\t\t\t\tmax=\"${this.max ?? nothing}\"\r\n\t\t\t\t?readonly=\"${this.readonly}\"\r\n\t\t\t\t?disabled=\"${this.disabled}\"\r\n\t\t\t\t@input=\"${this.#onInput}\"\r\n\t\t\t\t@change=\"${this.#onChange}\"\r\n\t\t\t>`;\r\n\t\t}\r\n\r\n\t\tif(this.type === 'color'){\r\n\t\t\treturn html`<input\r\n\t\t\t\tdata-ve-input\r\n\t\t\t\ttype=\"color\"\r\n\t\t\t\t.value=\"${this.#value || '#000000'}\"\r\n\t\t\t\t?disabled=\"${this.disabled || this.readonly}\"\r\n\t\t\t\t@input=\"${this.#onInput}\"\r\n\t\t\t\t@change=\"${this.#onChange}\"\r\n\t\t\t>`;\r\n\t\t}\r\n\r\n\t\treturn html`<textarea\r\n\t\t\tdata-ve-input\r\n\t\t\tclass=\"full ff-mono\"\r\n\t\t\trows=\"${this.rows}\"\r\n\t\t\tplaceholder=\"${this.placeholder || nothing}\"\r\n\t\t\t?readonly=\"${this.readonly}\"\r\n\t\t\t?disabled=\"${this.disabled}\"\r\n\t\t\t@input=\"${this.#onInput}\"\r\n\t\t\t@change=\"${this.#onChange}\"\r\n\t\t\t.value=\"${String(this.#value)}\"\r\n\t\t></textarea>`;\r\n\t}\r\n}\r\n\r\ncustomElements.define('admin-value-editor', ValueEditor);\r\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import e from"/kempo-ui/components/tableControls/TableControl.js";import{html as t}from"/kempo-ui/lit-all.min.js";import o from"/kempo-ui/components/Dialog.js";import m from"/kempo-ui/components/Toast.js";import"/kempo-ui/components/Icon.js";import"/kempo-ui/components/Combobox.js";import"/kempo-ui/components/Spinner.js";export default class n extends e{groupName="";addMember=()=>{let e=null;const t=document.createElement("k-combobox");t.setAttribute("placeholder","Search users..."),t.setAttribute("debounce-ms","350"),t.setAttribute("require-match",""),t.addEventListener("search",async e=>{t.searching=!0;const{searchUsers:o}=await import("/kempo/sdk.js"),[m,n]=await o({q:e.detail.value,notInGroup:this.groupName,limit:20});t.searching=!1,!m&&n&&t.setOptions(n.users.map(e=>({label:`${e.name} (${e.email})`,value:e.id})))}),t.addEventListener("select",t=>{e=t.detail.value});const n=document.createElement("div");n.className="p",n.appendChild(t),o.create(n,{title:"Add Member",confirmText:"Add",confirmAction:async()=>{if(!e)return;const{addMemberToGroup:t}=await import("/kempo/sdk.js"),[o]=await t(this.groupName,e);o?m.error(o.msg||"Failed to add member"):(m.success("Member added"),this.dispatchEvent(new CustomEvent("memberAdded",{bubbles:!0,composed:!0})))},cancelText:"Cancel"})};render(){return t`
|
|
2
2
|
<button class="no-btn icon-btn" title="Add Member" @click="${this.addMember}">
|
|
3
3
|
<k-icon name="person_add"></k-icon>
|
|
4
4
|
</button>
|
|
5
|
-
`}}customElements.define("admin-add-member",
|
|
5
|
+
`}}customElements.define("admin-add-member",n);
|
|
6
6
|
//# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\tableControls\AddMember.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src\\admin\\components\\tableControls\\AddMember.js","names":["TableControl","html","Dialog","Toast","AddMember","groupName","addMember","selectedUserId","$combobox","document","createElement","setAttribute","addEventListener","async","searching","searchUsers","import","err","data","q","e","detail","value","notInGroup","this","limit","setOptions","users","map","u","label","name","email","id","$wrap","className","appendChild","create","title","confirmText","confirmAction","addMemberToGroup","error","msg","success","dispatchEvent","CustomEvent","bubbles","composed","cancelText","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport Dialog from '/kempo-ui/components/Dialog.js';\r\nimport Toast from '/kempo-ui/components/Toast.js';\r\nimport '/kempo-ui/components/Icon.js';\r\nimport '/kempo-ui/components/Combobox.js';\r\nimport '/kempo-ui/components/Spinner.js';\r\n\r\nexport default class AddMember extends TableControl {\r\n groupName = '';\r\n\r\n addMember = () => {\r\n let selectedUserId = null;\r\n\r\n const $combobox = document.createElement('k-combobox');\r\n $combobox.setAttribute('placeholder', 'Search users...');\r\n $combobox.setAttribute('debounce-ms', '350');\r\n $combobox.setAttribute('require-match', '');\r\n\r\n $combobox.addEventListener('search', async e => {\r\n $combobox.searching = true;\r\n const { searchUsers } = await import('/kempo/sdk.js');\r\n const [err, data] = await searchUsers({ q: e.detail.value, notInGroup: this.groupName, limit: 20 });\r\n $combobox.searching = false;\r\n if(err || !data) return;\r\n $combobox.setOptions(data.users.map(u => ({ label: `${u.name} (${u.email})`, value: u.id })));\r\n });\r\n\r\n $combobox.addEventListener('select', e => {\r\n selectedUserId = e.detail.value;\r\n });\r\n\r\n const $wrap = document.createElement('div');\r\n $wrap.className = 'p';\r\n $wrap.appendChild($combobox);\r\n\r\n Dialog.create($wrap, {\r\n title: 'Add Member',\r\n confirmText: 'Add',\r\n confirmAction: async () => {\r\n if(!selectedUserId) return;\r\n const { addMemberToGroup } = await import('/kempo/sdk.js');\r\n const [err] = await addMemberToGroup(this.groupName, selectedUserId);\r\n if(err){ Toast.error(err.msg || 'Failed to add member'); return; }\r\n Toast.success('Member added');\r\n this.dispatchEvent(new CustomEvent('memberAdded', { bubbles: true, composed: true }));\r\n },\r\n cancelText: 'Cancel'\r\n });\r\n };\r\n\r\n render(){\r\n return html`\r\n <button class=\"no-btn icon-btn\" title=\"Add Member\" @click=\"${this.addMember}\">\r\n <k-icon name=\"person_add\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-add-member', AddMember);\r\n"],"mappings":"OAAOA,
|
|
1
|
+
{"version":3,"file":"src\\admin\\components\\tableControls\\AddMember.js","names":["TableControl","html","Dialog","Toast","AddMember","groupName","addMember","selectedUserId","$combobox","document","createElement","setAttribute","addEventListener","async","searching","searchUsers","import","err","data","q","e","detail","value","notInGroup","this","limit","setOptions","users","map","u","label","name","email","id","$wrap","className","appendChild","create","title","confirmText","confirmAction","addMemberToGroup","error","msg","success","dispatchEvent","CustomEvent","bubbles","composed","cancelText","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport Dialog from '/kempo-ui/components/Dialog.js';\r\nimport Toast from '/kempo-ui/components/Toast.js';\r\nimport '/kempo-ui/components/Icon.js';\r\nimport '/kempo-ui/components/Combobox.js';\r\nimport '/kempo-ui/components/Spinner.js';\r\n\r\nexport default class AddMember extends TableControl {\r\n groupName = '';\r\n\r\n addMember = () => {\r\n let selectedUserId = null;\r\n\r\n const $combobox = document.createElement('k-combobox');\r\n $combobox.setAttribute('placeholder', 'Search users...');\r\n $combobox.setAttribute('debounce-ms', '350');\r\n $combobox.setAttribute('require-match', '');\r\n\r\n $combobox.addEventListener('search', async e => {\r\n $combobox.searching = true;\r\n const { searchUsers } = await import('/kempo/sdk.js');\r\n const [err, data] = await searchUsers({ q: e.detail.value, notInGroup: this.groupName, limit: 20 });\r\n $combobox.searching = false;\r\n if(err || !data) return;\r\n $combobox.setOptions(data.users.map(u => ({ label: `${u.name} (${u.email})`, value: u.id })));\r\n });\r\n\r\n $combobox.addEventListener('select', e => {\r\n selectedUserId = e.detail.value;\r\n });\r\n\r\n const $wrap = document.createElement('div');\r\n $wrap.className = 'p';\r\n $wrap.appendChild($combobox);\r\n\r\n Dialog.create($wrap, {\r\n title: 'Add Member',\r\n confirmText: 'Add',\r\n confirmAction: async () => {\r\n if(!selectedUserId) return;\r\n const { addMemberToGroup } = await import('/kempo/sdk.js');\r\n const [err] = await addMemberToGroup(this.groupName, selectedUserId);\r\n if(err){ Toast.error(err.msg || 'Failed to add member'); return; }\r\n Toast.success('Member added');\r\n this.dispatchEvent(new CustomEvent('memberAdded', { bubbles: true, composed: true }));\r\n },\r\n cancelText: 'Cancel'\r\n });\r\n };\r\n\r\n render(){\r\n return html`\r\n <button class=\"no-btn icon-btn\" title=\"Add Member\" @click=\"${this.addMember}\">\r\n <k-icon name=\"person_add\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-add-member', AddMember);\r\n"],"mappings":"OAAOA,MAAkB,oEAChBC,MAAY,kCACdC,MAAY,wCACZC,MAAW,sCACX,qCACA,yCACA,iDAEQ,MAAMC,UAAkBJ,EACrCK,UAAY,GAEZC,UAAY,KACV,IAAIC,EAAiB,KAErB,MAAMC,EAAYC,SAASC,cAAc,cACzCF,EAAUG,aAAa,cAAe,mBACtCH,EAAUG,aAAa,cAAe,OACtCH,EAAUG,aAAa,gBAAiB,IAExCH,EAAUI,iBAAiB,SAAUC,UACnCL,EAAUM,WAAY,EACtB,MAAMC,YAAEA,SAAsBC,OAAO,kBAC9BC,EAAKC,SAAcH,EAAY,CAAEI,EAAGC,EAAEC,OAAOC,MAAOC,WAAYC,KAAKnB,UAAWoB,MAAO,KAC9FjB,EAAUM,WAAY,GACnBG,GAAQC,GACXV,EAAUkB,WAAWR,EAAKS,MAAMC,IAAIC,IAAK,CAAGC,MAAO,GAAGD,EAAEE,SAASF,EAAEG,SAAUV,MAAOO,EAAEI,SAGxFzB,EAAUI,iBAAiB,SAAUQ,IACnCb,EAAiBa,EAAEC,OAAOC,QAG5B,MAAMY,EAAQzB,SAASC,cAAc,OACrCwB,EAAMC,UAAY,IAClBD,EAAME,YAAY5B,GAElBN,EAAOmC,OAAOH,EAAO,CACnBI,MAAO,aACPC,YAAa,MACbC,cAAe3B,UACb,IAAIN,EAAgB,OACpB,MAAMkC,iBAAEA,SAA2BzB,OAAO,kBACnCC,SAAawB,EAAiBjB,KAAKnB,UAAWE,GAClDU,EAAMd,EAAMuC,MAAMzB,EAAI0B,KAAO,yBAChCxC,EAAMyC,QAAQ,gBACdpB,KAAKqB,cAAc,IAAIC,YAAY,cAAe,CAAEC,SAAS,EAAMC,UAAU,OAE/EC,WAAY,YAIhB,MAAAC,GACE,OAAOjD,CAAI;mEACoDuB,KAAKlB;;;KAItE,EAGF6C,eAAeC,OAAO,mBAAoBhD","ignoreList":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import e from"/kempo-ui/components/tableControls/TableControl.js";import{html as o}from"/kempo-ui/lit-all.min.js";import s from"/kempo-ui/components/Dialog.js";import i from"/kempo-ui/components/Toast.js";import"/kempo-ui/components/Icon.js";import"/kempo-ui/components/Combobox.js";export default class t extends e{groupName="";addPermission=async()=>{const{listPermissions:e,getGroupPermissions:o,addPermissionToGroup:t}=await import("/kempo/sdk.js"),[[n,r],[m,a]]=await Promise.all([e({limit:1e3}),o(this.groupName)]);if(n)return void i.error(n.msg||"Failed to load permissions");if(m)return void i.error(m.msg||"Failed to load group permissions");const d=new Set(a.permissions),l=r.permissions.filter(e=>!d.has(e.name));let c=null;const p=document.createElement("k-combobox");p.setAttribute("placeholder","Search permissions..."),p.setAttribute("require-match",""),p.setOptions(l.map(e=>({label:e.name,value:e.name}))),p.addEventListener("select",e=>{c=e.detail.value});const u=document.createElement("div");u.className="p",u.appendChild(p),s.create(u,{title:"Add Permission",confirmText:"Add",confirmAction:async()=>{if(!c)return;const[e]=await t(this.groupName,c);e?i.error(e.msg||"Failed to add permission"):(i.success("Permission added"),this.dispatchEvent(new CustomEvent("permissionAdded",{bubbles:!0,composed:!0})))},cancelText:"Cancel"})};render(){return o`
|
|
2
2
|
<button class="no-btn icon-btn" title="Add Permission" @click="${this.addPermission}">
|
|
3
3
|
<k-icon name="lock_add"></k-icon>
|
|
4
4
|
</button>
|
|
5
|
-
`}}customElements.define("admin-add-permission",
|
|
5
|
+
`}}customElements.define("admin-add-permission",t);
|
|
6
6
|
//# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\tableControls\AddPermission.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src\\admin\\components\\tableControls\\AddPermission.js","names":["TableControl","html","Dialog","Toast","AddPermission","groupName","addPermission","async","listPermissions","getGroupPermissions","addPermissionToGroup","import","allErr","allData","groupErr","groupPerms","Promise","all","limit","this","error","msg","assigned","Set","permissions","available","filter","p","has","name","selectedPermName","$combobox","document","createElement","setAttribute","setOptions","map","label","value","addEventListener","e","detail","$wrap","className","appendChild","create","title","confirmText","confirmAction","err","success","dispatchEvent","CustomEvent","bubbles","composed","cancelText","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport Dialog from '/kempo-ui/components/Dialog.js';\r\nimport Toast from '/kempo-ui/components/Toast.js';\r\nimport '/kempo-ui/components/Icon.js';\r\nimport '/kempo-ui/components/Combobox.js';\r\n\r\nexport default class AddPermission extends TableControl {\r\n groupName = '';\r\n\r\n addPermission = async () => {\r\n const { listPermissions, getGroupPermissions, addPermissionToGroup } = await import('/kempo/sdk.js');\r\n\r\n const [[allErr, allData], [groupErr, groupPerms]] = await Promise.all([\r\n listPermissions({ limit: 1000 }),\r\n getGroupPermissions(this.groupName)\r\n ]);\r\n\r\n if(allErr){ Toast.error(allErr.msg || 'Failed to load permissions'); return; }\r\n if(groupErr){ Toast.error(groupErr.msg || 'Failed to load group permissions'); return; }\r\n\r\n const assigned = new Set(groupPerms.permissions);\r\n const available = allData.permissions.filter(p => !assigned.has(p.name));\r\n\r\n let selectedPermName = null;\r\n\r\n const $combobox = document.createElement('k-combobox');\r\n $combobox.setAttribute('placeholder', 'Search permissions...');\r\n $combobox.setAttribute('require-match', '');\r\n $combobox.setOptions(available.map(p => ({ label: p.name, value: p.name })));\r\n\r\n $combobox.addEventListener('select', e => {\r\n selectedPermName = e.detail.value;\r\n });\r\n\r\n const $wrap = document.createElement('div');\r\n $wrap.className = 'p';\r\n $wrap.appendChild($combobox);\r\n\r\n Dialog.create($wrap, {\r\n title: 'Add Permission',\r\n confirmText: 'Add',\r\n confirmAction: async () => {\r\n if(!selectedPermName) return;\r\n const [err] = await addPermissionToGroup(this.groupName, selectedPermName);\r\n if(err){ Toast.error(err.msg || 'Failed to add permission'); return; }\r\n Toast.success('Permission added');\r\n this.dispatchEvent(new CustomEvent('permissionAdded', { bubbles: true, composed: true }));\r\n },\r\n cancelText: 'Cancel'\r\n });\r\n };\r\n\r\n render(){\r\n return html`\r\n <button class=\"no-btn icon-btn\" title=\"Add Permission\" @click=\"${this.addPermission}\">\r\n <k-icon name=\"lock_add\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-add-permission', AddPermission);\r\n"],"mappings":"OAAOA,
|
|
1
|
+
{"version":3,"file":"src\\admin\\components\\tableControls\\AddPermission.js","names":["TableControl","html","Dialog","Toast","AddPermission","groupName","addPermission","async","listPermissions","getGroupPermissions","addPermissionToGroup","import","allErr","allData","groupErr","groupPerms","Promise","all","limit","this","error","msg","assigned","Set","permissions","available","filter","p","has","name","selectedPermName","$combobox","document","createElement","setAttribute","setOptions","map","label","value","addEventListener","e","detail","$wrap","className","appendChild","create","title","confirmText","confirmAction","err","success","dispatchEvent","CustomEvent","bubbles","composed","cancelText","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport Dialog from '/kempo-ui/components/Dialog.js';\r\nimport Toast from '/kempo-ui/components/Toast.js';\r\nimport '/kempo-ui/components/Icon.js';\r\nimport '/kempo-ui/components/Combobox.js';\r\n\r\nexport default class AddPermission extends TableControl {\r\n groupName = '';\r\n\r\n addPermission = async () => {\r\n const { listPermissions, getGroupPermissions, addPermissionToGroup } = await import('/kempo/sdk.js');\r\n\r\n const [[allErr, allData], [groupErr, groupPerms]] = await Promise.all([\r\n listPermissions({ limit: 1000 }),\r\n getGroupPermissions(this.groupName)\r\n ]);\r\n\r\n if(allErr){ Toast.error(allErr.msg || 'Failed to load permissions'); return; }\r\n if(groupErr){ Toast.error(groupErr.msg || 'Failed to load group permissions'); return; }\r\n\r\n const assigned = new Set(groupPerms.permissions);\r\n const available = allData.permissions.filter(p => !assigned.has(p.name));\r\n\r\n let selectedPermName = null;\r\n\r\n const $combobox = document.createElement('k-combobox');\r\n $combobox.setAttribute('placeholder', 'Search permissions...');\r\n $combobox.setAttribute('require-match', '');\r\n $combobox.setOptions(available.map(p => ({ label: p.name, value: p.name })));\r\n\r\n $combobox.addEventListener('select', e => {\r\n selectedPermName = e.detail.value;\r\n });\r\n\r\n const $wrap = document.createElement('div');\r\n $wrap.className = 'p';\r\n $wrap.appendChild($combobox);\r\n\r\n Dialog.create($wrap, {\r\n title: 'Add Permission',\r\n confirmText: 'Add',\r\n confirmAction: async () => {\r\n if(!selectedPermName) return;\r\n const [err] = await addPermissionToGroup(this.groupName, selectedPermName);\r\n if(err){ Toast.error(err.msg || 'Failed to add permission'); return; }\r\n Toast.success('Permission added');\r\n this.dispatchEvent(new CustomEvent('permissionAdded', { bubbles: true, composed: true }));\r\n },\r\n cancelText: 'Cancel'\r\n });\r\n };\r\n\r\n render(){\r\n return html`\r\n <button class=\"no-btn icon-btn\" title=\"Add Permission\" @click=\"${this.addPermission}\">\r\n <k-icon name=\"lock_add\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-add-permission', AddPermission);\r\n"],"mappings":"OAAOA,MAAkB,oEAChBC,MAAY,kCACdC,MAAY,wCACZC,MAAW,sCACX,qCACA,kDAEQ,MAAMC,UAAsBJ,EACzCK,UAAY,GAEZC,cAAgBC,UACd,MAAMC,gBAAEA,EAAeC,oBAAEA,EAAmBC,qBAAEA,SAA+BC,OAAO,mBAE5EC,EAAQC,IAAWC,EAAUC,UAAqBC,QAAQC,IAAI,CACpET,EAAgB,CAAEU,MAAO,MACzBT,EAAoBU,KAAKd,aAG3B,GAAGO,EAAkE,YAAzDT,EAAMiB,MAAMR,EAAOS,KAAO,8BACtC,GAAGP,EAA4E,YAAjEX,EAAMiB,MAAMN,EAASO,KAAO,oCAE1C,MAAMC,EAAW,IAAIC,IAAIR,EAAWS,aAC9BC,EAAYZ,EAAQW,YAAYE,OAAOC,IAAML,EAASM,IAAID,EAAEE,OAElE,IAAIC,EAAmB,KAEvB,MAAMC,EAAYC,SAASC,cAAc,cACzCF,EAAUG,aAAa,cAAe,yBACtCH,EAAUG,aAAa,gBAAiB,IACxCH,EAAUI,WAAWV,EAAUW,IAAIT,IAAK,CAAGU,MAAOV,EAAEE,KAAMS,MAAOX,EAAEE,SAEnEE,EAAUQ,iBAAiB,SAAUC,IACnCV,EAAmBU,EAAEC,OAAOH,QAG9B,MAAMI,EAAQV,SAASC,cAAc,OACrCS,EAAMC,UAAY,IAClBD,EAAME,YAAYb,GAElB7B,EAAO2C,OAAOH,EAAO,CACnBI,MAAO,iBACPC,YAAa,MACbC,cAAezC,UACb,IAAIuB,EAAkB,OACtB,MAAOmB,SAAavC,EAAqBS,KAAKd,UAAWyB,GACtDmB,EAAM9C,EAAMiB,MAAM6B,EAAI5B,KAAO,6BAChClB,EAAM+C,QAAQ,oBACd/B,KAAKgC,cAAc,IAAIC,YAAY,kBAAmB,CAAEC,SAAS,EAAMC,UAAU,OAEnFC,WAAY,YAIhB,MAAAC,GACE,OAAOvD,CAAI;uEACwDkB,KAAKb;;;KAI1E,EAGFmD,eAAeC,OAAO,uBAAwBtD","ignoreList":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import o from"/kempo-ui/components/tableControls/TableControl.js";import{html as t}from"/kempo-ui/lit-all.min.js";import n from"/kempo-ui/components/Dialog.js";import e from"/kempo-ui/components/Toast.js";import"/kempo-ui/components/Icon.js";export default class s extends o{install=async()=>{this.record&&n.confirm(`Install "${this.record.name}"?`,async o=>{if(!o)return;const{installExtension:t}=await import("/kempo/sdk.js"),[n]=await t(this.record.name);n?e.error(n.msg||"Failed to install extension"):(e.success(`"${this.record.name}" installed successfully`),this.table.deleteRecord(this.record))})};render(){return t`
|
|
2
2
|
<button class="no-btn icon-btn" title="Install Extension" @click="${this.install}">
|
|
3
3
|
<k-icon name="download"></k-icon>
|
|
4
4
|
</button>
|
|
5
|
-
`}}customElements.define("admin-install-extension",
|
|
5
|
+
`}}customElements.define("admin-install-extension",s);
|
|
6
6
|
//# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\tableControls\InstallExtension.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src\\admin\\components\\tableControls\\InstallExtension.js","names":["TableControl","html","Dialog","Toast","InstallExtension","install","async","this","record","confirm","name","confirmed","installExtension","import","error","success","table","deleteRecord","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport Dialog from '/kempo-ui/components/Dialog.js';\r\nimport Toast from '/kempo-ui/components/Toast.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class InstallExtension extends TableControl {\r\n install = async () => {\r\n if(!this.record) return;\r\n\r\n Dialog.confirm(`Install \"${this.record.name}\"?`, async confirmed => {\r\n if(!confirmed) return;\r\n\r\n const { installExtension } = await import('
|
|
1
|
+
{"version":3,"file":"src\\admin\\components\\tableControls\\InstallExtension.js","names":["TableControl","html","Dialog","Toast","InstallExtension","install","async","this","record","confirm","name","confirmed","installExtension","import","error","msg","success","table","deleteRecord","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport Dialog from '/kempo-ui/components/Dialog.js';\r\nimport Toast from '/kempo-ui/components/Toast.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class InstallExtension extends TableControl {\r\n install = async () => {\r\n if(!this.record) return;\r\n\r\n Dialog.confirm(`Install \"${this.record.name}\"?`, async confirmed => {\r\n if(!confirmed) return;\r\n\r\n const { installExtension } = await import('/kempo/sdk.js');\r\n const [error] = await installExtension(this.record.name);\r\n\r\n if(error){\r\n Toast.error(error.msg || 'Failed to install extension');\r\n return;\r\n }\r\n\r\n Toast.success(`\"${this.record.name}\" installed successfully`);\r\n this.table.deleteRecord(this.record);\r\n });\r\n };\r\n\r\n render(){\r\n return html`\r\n <button class=\"no-btn icon-btn\" title=\"Install Extension\" @click=\"${this.install}\">\r\n <k-icon name=\"download\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-install-extension', InstallExtension);\r\n"],"mappings":"OAAOA,MAAkB,oEAChBC,MAAY,kCACdC,MAAY,wCACZC,MAAW,sCACX,8CAEQ,MAAMC,UAAyBJ,EAC5CK,QAAUC,UACJC,KAAKC,QAETN,EAAOO,QAAQ,YAAYF,KAAKC,OAAOE,SAAUJ,UAC/C,IAAIK,EAAW,OAEf,MAAMC,iBAAEA,SAA2BC,OAAO,kBACnCC,SAAeF,EAAiBL,KAAKC,OAAOE,MAEhDI,EACDX,EAAMW,MAAMA,EAAMC,KAAO,gCAI3BZ,EAAMa,QAAQ,IAAIT,KAAKC,OAAOE,gCAC9BH,KAAKU,MAAMC,aAAaX,KAAKC,YAIjC,MAAAW,GACE,OAAOlB,CAAI;0EAC2DM,KAAKF;;;KAI7E,EAGFe,eAAeC,OAAO,0BAA2BjB","ignoreList":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import n from"/kempo-ui/components/tableControls/TableControl.js";import{html as t}from"/kempo-ui/lit-all.min.js";import e from"/kempo-ui/components/Dialog.js";import o from"/kempo-ui/components/Toast.js";import"/kempo-ui/components/Icon.js";export default class s extends n{uninstall=async()=>{this.record&&e.confirm(`Uninstall "${this.record.name}"? This may delete extension data.`,async n=>{if(!n)return;const{uninstallExtension:t}=await import("/kempo/sdk.js"),[e]=await t(this.record.name);e?o.error(e.msg||"Failed to uninstall extension"):(o.success(`"${this.record.name}" uninstalled successfully`),this.table.deleteRecord(this.record))})};render(){return t`
|
|
2
2
|
<button class="no-btn icon-btn" title="Uninstall Extension" @click="${this.uninstall}">
|
|
3
3
|
<k-icon name="delete"></k-icon>
|
|
4
4
|
</button>
|
|
5
|
-
`}}customElements.define("admin-uninstall-extension",
|
|
5
|
+
`}}customElements.define("admin-uninstall-extension",s);
|
|
6
6
|
//# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\tableControls\UninstallExtension.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src\\admin\\components\\tableControls\\UninstallExtension.js","names":["TableControl","html","Dialog","Toast","UninstallExtension","uninstall","async","this","record","confirm","name","confirmed","uninstallExtension","import","error","success","table","deleteRecord","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport Dialog from '/kempo-ui/components/Dialog.js';\r\nimport Toast from '/kempo-ui/components/Toast.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class UninstallExtension extends TableControl {\r\n uninstall = async () => {\r\n if(!this.record) return;\r\n\r\n Dialog.confirm(`Uninstall \"${this.record.name}\"? This may delete extension data.`, async confirmed => {\r\n if(!confirmed) return;\r\n\r\n const { uninstallExtension } = await import('
|
|
1
|
+
{"version":3,"file":"src\\admin\\components\\tableControls\\UninstallExtension.js","names":["TableControl","html","Dialog","Toast","UninstallExtension","uninstall","async","this","record","confirm","name","confirmed","uninstallExtension","import","error","msg","success","table","deleteRecord","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport Dialog from '/kempo-ui/components/Dialog.js';\r\nimport Toast from '/kempo-ui/components/Toast.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class UninstallExtension extends TableControl {\r\n uninstall = async () => {\r\n if(!this.record) return;\r\n\r\n Dialog.confirm(`Uninstall \"${this.record.name}\"? This may delete extension data.`, async confirmed => {\r\n if(!confirmed) return;\r\n\r\n const { uninstallExtension } = await import('/kempo/sdk.js');\r\n const [error] = await uninstallExtension(this.record.name);\r\n\r\n if(error){\r\n Toast.error(error.msg || 'Failed to uninstall extension');\r\n return;\r\n }\r\n\r\n Toast.success(`\"${this.record.name}\" uninstalled successfully`);\r\n this.table.deleteRecord(this.record);\r\n });\r\n };\r\n\r\n render(){\r\n return html`\r\n <button class=\"no-btn icon-btn\" title=\"Uninstall Extension\" @click=\"${this.uninstall}\">\r\n <k-icon name=\"delete\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-uninstall-extension', UninstallExtension);\r\n"],"mappings":"OAAOA,MAAkB,oEAChBC,MAAY,kCACdC,MAAY,wCACZC,MAAW,sCACX,8CAEQ,MAAMC,UAA2BJ,EAC9CK,UAAYC,UACNC,KAAKC,QAETN,EAAOO,QAAQ,cAAcF,KAAKC,OAAOE,yCAA0CJ,UACjF,IAAIK,EAAW,OAEf,MAAMC,mBAAEA,SAA6BC,OAAO,kBACrCC,SAAeF,EAAmBL,KAAKC,OAAOE,MAElDI,EACDX,EAAMW,MAAMA,EAAMC,KAAO,kCAI3BZ,EAAMa,QAAQ,IAAIT,KAAKC,OAAOE,kCAC9BH,KAAKU,MAAMC,aAAaX,KAAKC,YAIjC,MAAAW,GACE,OAAOlB,CAAI;4EAC6DM,KAAKF;;;KAI/E,EAGFe,eAAeC,OAAO,4BAA6BjB","ignoreList":[]}
|
|
@@ -1,32 +1,66 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
locked: true
|
|
3
3
|
-->
|
|
4
|
-
<page title="Extensions - Admin"><content><script type="module" src="/kempo-ui/components/Table.js"></script><script type="module" src="/kempo-ui/components/tableControls/FirstPage.js"></script><script type="module" src="/kempo-ui/components/tableControls/PrevPage.js"></script><script type="module" src="/kempo-ui/components/tableControls/NextPage.js"></script><script type="module" src="/kempo-ui/components/tableControls/LastPage.js"></script><script type="module" src="/kempo-ui/components/tableControls/PageSelect.js"></script><script type="module" src="/kempo-ui/components/tableControls/PageSize.js"></script><script type="module" src="/admin/components/tableControls/InstallExtension.js"></script><script type="module" src="/admin/components/tableControls/UninstallExtension.js"></script><script type="module" src="/kempo/components/Permission.js"></script><div class="d-f mb" style="align-items: center; gap: var(--spacer);"><h1 class="flex mb0">Extensions</h1></div><h2>Installed Extensions</h2><k-table id="installedTable" enable-pages page-size="25" placeholder="No extensions are currently installed."><
|
|
4
|
+
<page title="Extensions - Admin"><content><script type="module" src="/kempo-ui/components/Table.js"></script><script type="module" src="/kempo-ui/components/tableControls/FirstPage.js"></script><script type="module" src="/kempo-ui/components/tableControls/PrevPage.js"></script><script type="module" src="/kempo-ui/components/tableControls/NextPage.js"></script><script type="module" src="/kempo-ui/components/tableControls/LastPage.js"></script><script type="module" src="/kempo-ui/components/tableControls/PageSelect.js"></script><script type="module" src="/kempo-ui/components/tableControls/PageSize.js"></script><script type="module" src="/admin/components/tableControls/InstallExtension.js"></script><script type="module" src="/admin/components/tableControls/UninstallExtension.js"></script><script type="module" src="/kempo/components/Permission.js"></script><div class="d-f mb" style="align-items: center; gap: var(--spacer);"><h1 class="flex mb0">Extensions</h1></div><h2>Installed Extensions</h2><k-table id="installedTable" enable-pages page-size="25" placeholder="No extensions are currently installed."><admin-uninstall-extension slot="after"></admin-uninstall-extension><div class="d-f full" style="align-items: center;"><div><k-tc-first-page></k-tc-first-page><k-tc-prev-page></k-tc-prev-page><k-tc-next-page></k-tc-next-page><k-tc-last-page></k-tc-last-page></div><div class="flex"></div><div><k-tc-page-select></k-tc-page-select></div><div class="flex"></div><div><k-tc-page-size></k-tc-page-size></div></div></k-table><h2>Available Extensions</h2><k-table id="availableTable" enable-pages page-size="25" placeholder="No extensions are available to install. Install a kempo extension package via npm first."><admin-install-extension slot="after"></admin-install-extension><div class="d-f full" style="align-items: center;"><div><k-tc-first-page></k-tc-first-page><k-tc-prev-page></k-tc-prev-page><k-tc-next-page></k-tc-next-page><k-tc-last-page></k-tc-last-page></div><div class="flex"></div><div><k-tc-page-select></k-tc-page-select></div><div class="flex"></div><div><k-tc-page-size></k-tc-page-size></div></div></k-table></content><content location="scripts"><script type="module">import { listExtensions, listAvailableExtensions } from '/kempo/sdk.js';
|
|
5
5
|
|
|
6
6
|
const installedTable = document.getElementById('installedTable');
|
|
7
7
|
const availableTable = document.getElementById('availableTable');
|
|
8
8
|
|
|
9
|
-
const [installedErr, installedData] = await
|
|
9
|
+
const [installedErr, installedData] = await listExtensions();
|
|
10
10
|
if(!installedErr){
|
|
11
|
-
installedTable.setData(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
{
|
|
15
|
-
{
|
|
16
|
-
{
|
|
11
|
+
installedTable.setData({
|
|
12
|
+
records: installedData.items,
|
|
13
|
+
fields: [
|
|
14
|
+
{ name: 'name', label: 'Name' },
|
|
15
|
+
{ name: 'version', label: 'Version' },
|
|
16
|
+
{ name: 'description', label: 'Description' },
|
|
17
|
+
{ name: 'enabled', label: 'Enabled' },
|
|
17
18
|
]
|
|
18
19
|
});
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
const [availableErr, availableData] = await
|
|
22
|
+
const [availableErr, availableData] = await listAvailableExtensions();
|
|
22
23
|
if(!availableErr){
|
|
23
24
|
const installedNames = new Set((installedData?.items || []).map(e => e.name));
|
|
24
25
|
const notInstalled = availableData.items.filter(e => !installedNames.has(e.name));
|
|
25
|
-
availableTable.setData(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
{
|
|
29
|
-
{
|
|
26
|
+
availableTable.setData({
|
|
27
|
+
records: notInstalled,
|
|
28
|
+
fields: [
|
|
29
|
+
{ name: 'name', label: 'Name' },
|
|
30
|
+
{ name: 'version', label: 'Version' },
|
|
31
|
+
{ name: 'description', label: 'Description' },
|
|
30
32
|
]
|
|
31
33
|
});
|
|
32
|
-
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const refreshInstalledTable = async () => {
|
|
37
|
+
const [err, data] = await listExtensions();
|
|
38
|
+
if(!err) installedTable.setData({
|
|
39
|
+
records: data.items,
|
|
40
|
+
fields: [
|
|
41
|
+
{ name: 'name', label: 'Name' },
|
|
42
|
+
{ name: 'version', label: 'Version' },
|
|
43
|
+
{ name: 'description', label: 'Description' },
|
|
44
|
+
{ name: 'enabled', label: 'Enabled' },
|
|
45
|
+
]
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const refreshAvailableTable = async () => {
|
|
50
|
+
const [instErr, instData] = await listExtensions();
|
|
51
|
+
const [availErr, availData] = await listAvailableExtensions();
|
|
52
|
+
if(!instErr && !availErr){
|
|
53
|
+
const installedNames = new Set((instData?.items || []).map(e => e.name));
|
|
54
|
+
availableTable.setData({
|
|
55
|
+
records: availData.items.filter(e => !installedNames.has(e.name)),
|
|
56
|
+
fields: [
|
|
57
|
+
{ name: 'name', label: 'Name' },
|
|
58
|
+
{ name: 'version', label: 'Version' },
|
|
59
|
+
{ name: 'description', label: 'Description' },
|
|
60
|
+
]
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
availableTable.addEventListener('recordDeleted', refreshInstalledTable);
|
|
66
|
+
installedTable.addEventListener('recordDeleted', refreshAvailableTable);</script></content></page>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h560v-280h80v280q0 33-23.5 56.5T760-120H200Zm188-212-56-56 372-372H560v-80h280v280h-80v-144L388-332Z"/></svg>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
locked: true
|
|
3
3
|
-->
|
|
4
|
-
<fragment><k-aside main="push" state="expanded" style="--aside_padding: 0;" persistent-id="admin-nav"><k-aside-toggle><h3 class="m0">Kempo Admin</h3></k-aside-toggle><k-aside-item icon="preview" href="/" no-expand>Site</k-aside-item><k-aside-item icon="cards" href="/admin" no-expand>Dashboard</k-aside-item><k-aside-menu icon="manage-accounts" label="Accounts"><k-aside-item icon="person" href="/admin/accounts/users" no-expand>Users</k-aside-item><k-aside-item icon="group" href="/admin/accounts/groups" no-expand>Groups</k-aside-item><k-aside-item icon="lock" href="/admin/accounts/permissions" no-expand>Permissions</k-aside-item></k-aside-menu><k-aside-menu icon="cards_stack" label="Content"><k-aside-item icon="browse" href="/admin/content/templates">Templates</k-aside-item><k-aside-item icon="docs" href="/admin/content/pages">Pages</k-aside-item><k-aside-item icon="content" href="/admin/content/fragments">Fragments</k-aside-item><k-aside-item icon="globe" href="/admin/content/globals">Global Content</k-aside-item></k-aside-menu><k-aside-item icon="settings" href="/admin/settings" no-expand>Settings</k-aside-item><k-aside-item icon="extension" href="/admin/extensions" no-expand>Extensions</k-aside-item><hr><k-aside-spacer></k-aside-spacer><k-theme-switcher labels style="--padding:var(--spacer_h);margin:var(--spacer_h) auto"></k-theme-switcher></k-aside><script type="module">import '/kempo-ui/components/ThemeSwitcher.js';
|
|
4
|
+
<fragment><k-aside main="push" state="expanded" style="--aside_padding: 0;" persistent-id="admin-nav"><k-aside-toggle><h3 class="m0">Kempo Admin</h3></k-aside-toggle><k-aside-item icon="preview" href="/" no-expand>Site</k-aside-item><k-aside-item icon="cards" href="/admin" no-expand>Dashboard</k-aside-item><k-aside-menu icon="manage-accounts" label="Accounts"><k-aside-item icon="person" href="/admin/accounts/users" no-expand>Users</k-aside-item><k-aside-item icon="group" href="/admin/accounts/groups" no-expand>Groups</k-aside-item><k-aside-item icon="lock" href="/admin/accounts/permissions" no-expand>Permissions</k-aside-item></k-aside-menu><k-aside-menu icon="cards_stack" label="Content"><k-aside-item icon="browse" href="/admin/content/templates">Templates</k-aside-item><k-aside-item icon="docs" href="/admin/content/pages">Pages</k-aside-item><k-aside-item icon="content" href="/admin/content/fragments">Fragments</k-aside-item><k-aside-item icon="globe" href="/admin/content/globals">Global Content</k-aside-item></k-aside-menu><k-aside-item icon="settings" href="/admin/settings" no-expand>Settings</k-aside-item><k-aside-item icon="extension" href="/admin/extensions" no-expand>Extensions</k-aside-item><hr><location name="admin-nav-extensions"></location><k-aside-spacer></k-aside-spacer><k-theme-switcher labels style="--padding:var(--spacer_h);margin:var(--spacer_h) auto"></k-theme-switcher></k-aside><script type="module">import '/kempo-ui/components/ThemeSwitcher.js';
|
|
5
5
|
const items = document.querySelectorAll('k-aside-item');
|
|
6
6
|
const currentPath = window.location.pathname;
|
|
7
7
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{resolve}from"path";import
|
|
1
|
+
import{resolve as s}from"path";import r from"../../../../server/utils/permissions/currentUserHasPermission.js";import t from"../../../../server/utils/admin-global-content/deleteAdminGlobalContent.js";const e=s(import.meta.dirname,"../../../../dist/admin");export default async(s,o)=>{const i=s.cookies.session_token,[n,a]=await r(i,"system:globals:delete");if(n)return o.status(n.code).json({error:n.msg});if(!a)return o.status(403).json({error:"Insufficient permissions"});const{ids:m}=s.body,[d,l]=await t({adminDir:e,ids:m});if(d)return o.status(d.code).json({error:d.msg});o.json(l)};
|
|
2
2
|
//# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\kempo\api\admin-globals\DELETE.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src\\kempo\\api\\admin-globals\\DELETE.js","names":["resolve","currentUserHasPermission","deleteAdminGlobalContent","adminDir","dirname","async","request","response","token","cookies","session_token","permError","hasPermission","status","code","json","error","msg","ids","body","data"],"sources":["0"],"sourcesContent":["import { resolve } from 'path';\r\nimport currentUserHasPermission from '../../../../server/utils/permissions/currentUserHasPermission.js';\r\nimport deleteAdminGlobalContent from '../../../../server/utils/admin-global-content/deleteAdminGlobalContent.js';\r\n\r\nconst adminDir = resolve(import.meta.dirname, '../../../../dist/admin');\r\n\r\nexport default async (request, response) => {\r\n const token = request.cookies.session_token;\r\n const [permError, hasPermission] = await currentUserHasPermission(token, 'system:globals:delete');\r\n\r\n if(permError){\r\n return response.status(permError.code).json({ error: permError.msg });\r\n }\r\n\r\n if(!hasPermission){\r\n return response.status(403).json({ error: 'Insufficient permissions' });\r\n }\r\n\r\n const { ids } = request.body;\r\n const [error, data] = await deleteAdminGlobalContent({ adminDir, ids });\r\n\r\n if(error){\r\n return response.status(error.code).json({ error: error.msg });\r\n }\r\n\r\n response.json(data);\r\n};\r\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"src\\kempo\\api\\admin-globals\\DELETE.js","names":["resolve","currentUserHasPermission","deleteAdminGlobalContent","adminDir","dirname","async","request","response","token","cookies","session_token","permError","hasPermission","status","code","json","error","msg","ids","body","data"],"sources":["0"],"sourcesContent":["import { resolve } from 'path';\r\nimport currentUserHasPermission from '../../../../server/utils/permissions/currentUserHasPermission.js';\r\nimport deleteAdminGlobalContent from '../../../../server/utils/admin-global-content/deleteAdminGlobalContent.js';\r\n\r\nconst adminDir = resolve(import.meta.dirname, '../../../../dist/admin');\r\n\r\nexport default async (request, response) => {\r\n const token = request.cookies.session_token;\r\n const [permError, hasPermission] = await currentUserHasPermission(token, 'system:globals:delete');\r\n\r\n if(permError){\r\n return response.status(permError.code).json({ error: permError.msg });\r\n }\r\n\r\n if(!hasPermission){\r\n return response.status(403).json({ error: 'Insufficient permissions' });\r\n }\r\n\r\n const { ids } = request.body;\r\n const [error, data] = await deleteAdminGlobalContent({ adminDir, ids });\r\n\r\n if(error){\r\n return response.status(error.code).json({ error: error.msg });\r\n }\r\n\r\n response.json(data);\r\n};\r\n"],"mappings":"kBAASA,MAAe,cACjBC,MAA8B,0EAC9BC,MAA8B,4EAErC,MAAMC,EAAWH,cAAoBI,QAAS,yCAE/BC,MAAOC,EAASC,KAC7B,MAAMC,EAAQF,EAAQG,QAAQC,eACvBC,EAAWC,SAAuBX,EAAyBO,EAAO,yBAEzE,GAAGG,EACD,OAAOJ,EAASM,OAAOF,EAAUG,MAAMC,KAAK,CAAEC,MAAOL,EAAUM,MAGjE,IAAIL,EACF,OAAOL,EAASM,OAAO,KAAKE,KAAK,CAAEC,MAAO,6BAG5C,MAAME,IAAEA,GAAQZ,EAAQa,MACjBH,EAAOI,SAAclB,EAAyB,CAAEC,WAAUe,QAEjE,GAAGF,EACD,OAAOT,EAASM,OAAOG,EAAMF,MAAMC,KAAK,CAAEC,MAAOA,EAAMC,MAGzDV,EAASQ,KAAKK","ignoreList":[]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{resolve}from"path";import
|
|
1
|
+
import{resolve as s}from"path";import r from"../../../../server/utils/permissions/currentUserHasPermission.js";import t from"../../../../server/utils/admin-global-content/listAdminGlobalContent.js";const o=s(import.meta.dirname,"../../../../dist/admin");export default async(s,e)=>{const i=s.cookies.session_token,[n,a]=await r(i,"system:globals:read");if(n)return e.status(n.code).json({error:n.msg});if(!a)return e.status(403).json({error:"Insufficient permissions"});const[m,u]=await t({adminDir:o});if(m)return e.status(m.code).json({error:m.msg});e.json(u)};
|
|
2
2
|
//# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\kempo\api\admin-globals\GET.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src\\kempo\\api\\admin-globals\\GET.js","names":["resolve","currentUserHasPermission","listAdminGlobalContent","adminDir","dirname","async","request","response","token","cookies","session_token","permError","hasPermission","status","code","json","error","msg","data"],"sources":["0"],"sourcesContent":["import { resolve } from 'path';\r\nimport currentUserHasPermission from '../../../../server/utils/permissions/currentUserHasPermission.js';\r\nimport listAdminGlobalContent from '../../../../server/utils/admin-global-content/listAdminGlobalContent.js';\r\n\r\nconst adminDir = resolve(import.meta.dirname, '../../../../dist/admin');\r\n\r\nexport default async (request, response) => {\r\n const token = request.cookies.session_token;\r\n const [permError, hasPermission] = await currentUserHasPermission(token, 'system:globals:read');\r\n\r\n if(permError){\r\n return response.status(permError.code).json({ error: permError.msg });\r\n }\r\n\r\n if(!hasPermission){\r\n return response.status(403).json({ error: 'Insufficient permissions' });\r\n }\r\n\r\n const [error, data] = await listAdminGlobalContent({ adminDir });\r\n\r\n if(error){\r\n return response.status(error.code).json({ error: error.msg });\r\n }\r\n\r\n response.json(data);\r\n};\r\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"src\\kempo\\api\\admin-globals\\GET.js","names":["resolve","currentUserHasPermission","listAdminGlobalContent","adminDir","dirname","async","request","response","token","cookies","session_token","permError","hasPermission","status","code","json","error","msg","data"],"sources":["0"],"sourcesContent":["import { resolve } from 'path';\r\nimport currentUserHasPermission from '../../../../server/utils/permissions/currentUserHasPermission.js';\r\nimport listAdminGlobalContent from '../../../../server/utils/admin-global-content/listAdminGlobalContent.js';\r\n\r\nconst adminDir = resolve(import.meta.dirname, '../../../../dist/admin');\r\n\r\nexport default async (request, response) => {\r\n const token = request.cookies.session_token;\r\n const [permError, hasPermission] = await currentUserHasPermission(token, 'system:globals:read');\r\n\r\n if(permError){\r\n return response.status(permError.code).json({ error: permError.msg });\r\n }\r\n\r\n if(!hasPermission){\r\n return response.status(403).json({ error: 'Insufficient permissions' });\r\n }\r\n\r\n const [error, data] = await listAdminGlobalContent({ adminDir });\r\n\r\n if(error){\r\n return response.status(error.code).json({ error: error.msg });\r\n }\r\n\r\n response.json(data);\r\n};\r\n"],"mappings":"kBAASA,MAAe,cACjBC,MAA8B,0EAC9BC,MAA4B,0EAEnC,MAAMC,EAAWH,cAAoBI,QAAS,yCAE/BC,MAAOC,EAASC,KAC7B,MAAMC,EAAQF,EAAQG,QAAQC,eACvBC,EAAWC,SAAuBX,EAAyBO,EAAO,uBAEzE,GAAGG,EACD,OAAOJ,EAASM,OAAOF,EAAUG,MAAMC,KAAK,CAAEC,MAAOL,EAAUM,MAGjE,IAAIL,EACF,OAAOL,EAASM,OAAO,KAAKE,KAAK,CAAEC,MAAO,6BAG5C,MAAOA,EAAOE,SAAchB,EAAuB,CAAEC,aAErD,GAAGa,EACD,OAAOT,EAASM,OAAOG,EAAMF,MAAMC,KAAK,CAAEC,MAAOA,EAAMC,MAGzDV,EAASQ,KAAKG","ignoreList":[]}
|