domma-cms 1.7.1 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/CLAUDE.md +30 -0
- package/admin/js/app.js +2 -2
- package/admin/js/lib/wordpress-import-arrange.js +1 -0
- package/admin/js/templates/docs/usage-tools.html +13 -1
- package/admin/js/templates/wordpress-import.html +223 -0
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/wordpress-import.js +38 -0
- package/package.json +1 -1
- package/server/routes/api/wordpress-import.js +220 -0
- package/server/server.js +12 -0
- package/server/services/hooks.js +1 -1
- package/server/services/permissionRegistry.js +10 -0
- package/server/services/roles.js +1 -1
- package/server/services/tools.js +2 -1
- package/server/services/wpImport/convert.js +491 -0
- package/server/services/wpImport/fetch.js +264 -0
- package/server/services/wpImport/index.js +832 -0
- package/server/services/wpImport/plan.js +549 -0
- package/server/services/wpImport/store.js +242 -0
- package/server/services/wpImport/wxr.js +167 -0
- package/server/services/wpImport/xml.js +261 -0
- package/server/services/wpImport/zip.js +142 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.7.2] - 2026-10-15
|
|
4
|
+
|
|
5
|
+
- **Import from WordPress**, a free built-in Tool (Tools › Maintenance). Upload a WordPress export (Tools › Export in WordPress) and see a preview of every page, post, file and menu before anything changes. Pages keep their addresses; posts go to the Blog with categories, tags, featured images and approved comments; media comes from the old site or a zip of `wp-content/uploads`; old addresses, including `?p=123`, redirect to the new ones - and keep redirecting with the importer switched off; Yoast and Rank Math titles and descriptions carry over. Shortcodes and page-builder layouts with no equivalent are listed to rebuild. Run it again and it updates what it made, leaving pages you edited alone unless you choose Overwrite; an import stopped by a restart can be run again to finish it. Each run's report is kept (out of git). Downloads go only to the export's own site, never to private or the server's own addresses, and only on ports 80/443; SVG and anything that is HTML or script is never imported.
|
|
6
|
+
|
|
3
7
|
## [1.7.1] - 2026-10-15
|
|
4
8
|
|
|
5
9
|
- **Email… opens Email Pro, not your desktop mail program.** In Contacts, form submissions and call links (and in Booking, Shopping Cart, Blog and Support), an Email action now opens Email Pro's compose window, already addressed, when you have a mailbox there; otherwise your device's mail program as before. Groups and selections can be emailed (everyone in Bcc). A prefilled message sits above your signature. A list too long for a mail link is copied for you to paste into Bcc, and says what was left out. New `admin/js/lib/mail-compose.js` (`openEmail`) for any screen - never `location.href = 'mailto:'`; the hand-off is `#/plugins/email-pro?compose=1&to=…`, read once by the mail reader.
|
package/CLAUDE.md
CHANGED
|
@@ -320,6 +320,36 @@ the collection mirrors the form's `required` - and stamps `meta.outcome`. `notif
|
|
|
320
320
|
forgetting triggers is the obvious failure. `goto-step` is announced as a `dm-form-trigger` DOM event
|
|
321
321
|
rather than performed, since the wizard handle belongs to the embed.
|
|
322
322
|
|
|
323
|
+
## Import from WordPress
|
|
324
|
+
|
|
325
|
+
A built-in Tool (`wordpress-import` in `services/tools.js`, permission `import.wordpress` - level 0, granted once to
|
|
326
|
+
`admin`), `#/wordpress-import`. Server: `server/services/wpImport/` + `routes/api/wordpress-import.js`
|
|
327
|
+
(`/api/import/wordpress`). Upload a WXR export -> preview (`planImport()`, pure, in `plan.js`) -> a background job
|
|
328
|
+
(`startRun()`, yields between items) -> a report kept in `content/imports/wordpress/` (history, reports, `map.json`).
|
|
329
|
+
|
|
330
|
+
- **The XML reader is its own** (`xml.js`): any DOCTYPE or ENTITY is refused, only the predefined and numeric
|
|
331
|
+
entities decode - do not swap in a parser that expands entities. Zips (`zip.js`) are read by offset with
|
|
332
|
+
zip-slip names dropped and ratio/size caps; nothing is ever extracted under its own name.
|
|
333
|
+
- **Media downloads go through `fetch.js` only**: the export's own hosts, every resolved address public, the
|
|
334
|
+
connection pinned to the checked address, never the server's own interface addresses, ports 80/443 only, no
|
|
335
|
+
redirect off-host; a non-image/PDF body that sniffs as HTML or script is refused (it would be served from /media).
|
|
336
|
+
`WP_IMPORT_ALLOW_PRIVATE_HOSTS=1` (ignored when `NODE_ENV=production`) is the tests' and local browser checks' way
|
|
337
|
+
to fetch from 127.0.0.1 on any port.
|
|
338
|
+
- **The mapping is saved as a run goes** (every few items and each phase), and `running.json` marks a run in
|
|
339
|
+
progress, so a restart mid-run is recorded as failed at boot and the re-run finishes it without duplicates.
|
|
340
|
+
`content/imports/wordpress/` is kept out of the site's git repo.
|
|
341
|
+
- **Re-runs**: `map.json` holds what each WordPress id became plus a fingerprint of what was written; a page,
|
|
342
|
+
post or menu whose fingerprint changed here is "Left as is" unless the person chooses Overwrite. A page moved in
|
|
343
|
+
the editor is followed (`content:pageRenamed` -> `followRename`).
|
|
344
|
+
- **Posts go to a Blog by feature, not by name** (`blogTarget()`): a switched-on plugin that ships `blog-posts`,
|
|
345
|
+
with the fields a post needs; comments only when `blog-comments` has the Blog's shape. Otherwise posts become
|
|
346
|
+
pages (under /blog, or /posts when a Blog is on).
|
|
347
|
+
- **Redirects**: path ones go into SEO's store (`seoEngine().addRule`); `/?p=`, `/?page_id=`, `/?attachment_id=`
|
|
348
|
+
are answered by the importer's own `onRequest` hook from `map.json`, because SEO's rules match paths only. That
|
|
349
|
+
hook is registered whatever the Tool switch says (the redirects belong to the migrated site) and re-reads
|
|
350
|
+
`map.json` when it changes.
|
|
351
|
+
- Unknown shortcodes are left as text with `[`/`]` brackets, so Domma never runs a WordPress `[button]`.
|
|
352
|
+
|
|
323
353
|
## Site search
|
|
324
354
|
|
|
325
355
|
Search is part of the CMS, not a plugin - `server/services/search.js` (settings, `stripMarkdown`, `scorePage`,
|
package/admin/js/app.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{views as K}from"./views/index.js";import{withPluginChrome as O}from"./lib/plugin-chrome.js";import{api as c,getUser as x,isAuthenticated as m,logout as J,sendToLogin as Y}from"./api.js";import{claimDrafts as Q}from"./lib/draft-owner.js";import{isAuthScreen as b,loginHashFor as X}from"./lib/login-arrange.js";import{installHttpInterceptor as Z}from"./http-interceptor.js";import{installResizableSlideovers as tt}from"./lib/slideover-resizable.js";import{installActivityThrobber as et}from"./lib/activity-throbber.js";import{installUpdateNotice as it}from"./lib/update-notice.js";import{isPathAllowed as ot,redirectFor as at}from"./lib/admin-scope.js";import{deliverDesktop as st,desktopActive as nt,notificationSettings as lt}from"./lib/desktop-notify.js";import{avatarUrl as rt}from"./lib/avatar.js";import{installCalculator as ct}from"./lib/calculator.js";import{takeOverviewPass as mt,withDashboardStrip as _}from"./lib/dashboards-strip.js";import{installHotkeys as pt}from"./lib/hotkeys-ui.js";import{applyAdminBrand as V}from"./lib/admin-brand.js";import{installRouterCatchUp as dt}from"./lib/router-catch-up.js";$(()=>{Z(),ct(),it(),et(),tt(),(async()=>{const{applyAdminTheme:t,refreshAdminTheme:i}=await import("./lib/admin-theme.js");m()?await i(c,{init:!0}):t({dommaTheme:"charcoal-dark"},{init:!0})})();let p=null,h=null,r="/",w=!1,g=null;function D(t){if(N[t])return E.toast(`${N[t]} is switched off on this site.`,{type:"info"}),"/";if(t.split("?")[0]==="/my-dashboard")return"/dashboards";const i=y[t]||at(p,t);return i||((t.split("?")[0]||"/")==="/"&&r&&r!=="/"&&!mt()?y[r]||r:null)}const y={},N={};R.use(async(t,i,e)=>{if(b(t.path))return e();if(!m()){Y();return}const o=D(t.path);if(o){R.navigate(o);return}e()});async function f(){try{const t=await c.get("/auth/permissions");p=t.adminScope||null,h=t.adminBrand||null,V(h),r=t.adminHome||"/";const i=t.permissions||[];return w=ot(p,"/settings")&&i.some(e=>e==="settings"||e.startsWith("settings.")),g=i.some(e=>e==="notifications"||e.startsWith("notifications.")),i}catch{return p=null,r="/",h||V(null),w=!1,g=null,[]}}document.addEventListener("dm:admin-home-changed",()=>{f()});let P=null,A=!1;document.addEventListener("dm:sidebar-rebuild",()=>{if(P){A=!0;return}P=(async()=>{do{A=!1;try{await j(await f())}catch{}}while(A)})().finally(()=>{P=null})});async function j(t){const{renderAdminSidebar:i}=await import("./lib/sidebar-renderer.js");await i({mount:"#admin-sidebar",permissions:t,adminScope:p,brand:h})}M.subscribe("router:afterChange",({to:t})=>{b(t.path)&&(u&&(clearInterval(u),u=null),p=null,r="/",w=!1,g=null)});const W=[{path:"/",view:"dashboard",title:"Dashboard - Domma CMS"},{path:"/dashboards",view:"dashboards",title:"Dashboards - Domma CMS"},{path:"/my-dashboard",view:"dashboards",title:"Dashboards - Domma CMS"},{path:"/pages",view:"pages",title:"Pages - Domma CMS"},{path:"/pages/new",view:"pageEditor",title:"New Page - Domma CMS"},{path:"/pages/edit/*",view:"pageEditor",title:"Edit Page - Domma CMS"},{path:"/media",view:"media",title:"Media - Domma CMS"},{path:"/menus",view:"menus",title:"Menus - Domma CMS"},{path:"/context-menus",view:"contextMenus",title:"Context Menus - Domma CMS"},{path:"/context-menus/new",view:"contextMenuEditor",title:"New Context Menu - Domma CMS"},{path:"/context-menus/edit/:slug",view:"contextMenuEditor",title:"Edit Context Menu - Domma CMS"},{path:"/menus/new",view:"menuEditor",title:"New Menu - Domma CMS"},{path:"/menus/edit/:slug",view:"menuEditor",title:"Edit Menu - Domma CMS"},{path:"/menu-locations",view:"menuLocations",title:"Menu Locations - Domma CMS"},{path:"/navigation",view:"menusRedirect",title:"Menus - Domma CMS"},{path:"/layouts",view:"layouts",title:"Layouts - Domma CMS"},{path:"/settings",view:"settings",title:"Settings - Domma CMS"},{path:"/theme",view:"theme",title:"Theme - Domma CMS"},{path:"/users",view:"users",title:"Users - Domma CMS"},{path:"/users/new",view:"userEditor",title:"New User - Domma CMS"},{path:"/users/edit/:id",view:"userEditor",title:"Edit User - Domma CMS"},{path:"/plugins",view:"plugins",title:"Plugins - Domma CMS"},{path:"/plugins/code/:name",view:"pluginCode",title:"Plugin Code - Domma CMS"},{path:"/documentation",view:"documentation",title:"Usage - Domma CMS"},{path:"/tutorials",view:"tutorials",title:"Tutorials - Domma CMS"},{path:"/tutorials/crud",view:"tutorialCrud",title:"Building a CRUD App - Domma CMS"},{path:"/tutorials/plugin",view:"tutorialPlugin",title:"Writing a Tool - Domma CMS"},{path:"/tutorials/forms",view:"tutorialForms",title:"Form Follow-Up - Domma CMS"},{path:"/docs/components",view:"componentsReference",title:"Components Reference - Domma CMS"},{path:"/docs/components-howto",view:"componentsHowto",title:"Components How-To - Domma CMS"},{path:"/docs/components-walkthrough",view:"componentsWalkthrough",title:"Components Walkthrough - Domma CMS"},{path:"/docs/components-rules",view:"componentsRules",title:"Components Rules - Domma CMS"},{path:"/docs/usage/pages",view:"usagePages",title:"Pages - Usage - Domma CMS"},{path:"/docs/usage/media",view:"usageMedia",title:"Media - Usage - Domma CMS"},{path:"/docs/usage/navigation",view:"usageNavigation",title:"Navigation - Usage - Domma CMS"},{path:"/docs/usage/dconfig",view:"usageDconfig",title:"DConfig - Usage - Domma CMS"},{path:"/docs/usage/shortcodes",view:"usageShortcodes",title:"Shortcodes - Usage - Domma CMS"},{path:"/docs/usage/site-settings",view:"usageSiteSettings",title:"Site Settings - Usage - Domma CMS"},{path:"/docs/usage/plugins",view:"usagePlugins",title:"Plugins - Usage - Domma CMS"},{path:"/docs/usage/users-roles",view:"usageUsersRoles",title:"Users & Roles - Usage - Domma CMS"},{path:"/docs/usage/views",view:"usageViews",title:"Views - Usage - Domma CMS"},{path:"/docs/usage/actions",view:"usageActions",title:"Actions - Usage - Domma CMS"},{path:"/docs/usage/cta-shortcode",view:"usageCtaShortcode",title:"CTA Shortcode - Usage - Domma CMS"},{path:"/docs/usage/editions",view:"usageEditions",title:"Editions & Licences - Usage - Domma CMS"},{path:"/docs/usage/collections",view:"usageCollections",title:"Collections & Forms - Usage - Domma CMS"},{path:"/docs/usage/blocks",view:"usageBlocks",title:"Blocks - Usage - Domma CMS"},{path:"/docs/usage/tools",view:"usageTools",title:"Built-in Tools - Usage - Domma CMS"},{path:"/docs/usage/dashboard",view:"usageDashboard",title:"Dashboard - Usage - Domma CMS"},{path:"/docs/plugins",view:"pluginGuides",title:"Plugin Guides - Domma CMS"},{path:"/docs/plugins/*",view:"pluginGuide",title:"Plugin Guide - Domma CMS"},{path:"/docs/api/authentication",view:"apiRefAuthentication",title:"Authentication - API - Domma CMS"},{path:"/docs/api/pages",view:"apiRefPages",title:"Pages - API - Domma CMS"},{path:"/docs/api/settings",view:"apiRefSettings",title:"Settings - API - Domma CMS"},{path:"/docs/api/layouts",view:"apiRefLayouts",title:"Layouts - API - Domma CMS"},{path:"/docs/api/navigation",view:"apiRefNavigation",title:"Navigation - API - Domma CMS"},{path:"/docs/api/media",view:"apiRefMedia",title:"Media - API - Domma CMS"},{path:"/docs/api/users",view:"apiRefUsers",title:"Users - API - Domma CMS"},{path:"/docs/api/plugins",view:"apiRefPlugins",title:"Plugins - API - Domma CMS"},{path:"/docs/api/collections",view:"apiRefCollections",title:"Collections - API - Domma CMS"},{path:"/docs/api/views",view:"apiRefViews",title:"Views API - Domma CMS"},{path:"/docs/api/actions",view:"apiRefActions",title:"Actions API - Domma CMS"},{path:"/docs/api/forms",view:"apiRefForms",title:"Forms API - Domma CMS"},{path:"/docs/api/scaffold",view:"apiRefScaffold",title:"Scaffold API - Domma CMS"},{path:"/docs/api/external",view:"apiRefExternal",title:"External API & Tokens - Domma CMS"},{path:"/docs/api/content",view:"apiRefContent",title:"Content API - Domma CMS"},{path:"/docs/api/builder",view:"apiRefBuilder",title:"API Builder - Domma CMS"},{path:"/api-reference",view:"apiReference",title:"API Reference - Domma CMS"},{path:"/collections",view:"collections",title:"Collections - Domma CMS"},{path:"/collections/new",view:"collectionEditor",title:"New Collection - Domma CMS"},{path:"/collections/edit/:slug",view:"collectionEditor",title:"Edit Collection - Domma CMS"},{path:"/collections/:slug/entries",view:"collectionEntries",title:"Entries - Domma CMS"},{path:"/forms",view:"forms",title:"Forms - Domma CMS"},{path:"/forms/new",view:"formEditor",title:"New Form - Domma CMS"},{path:"/forms/edit/:slug",view:"formEditor",title:"Edit Form - Domma CMS"},{path:"/forms/:slug/submissions",view:"formSubmissions",title:"Submissions - Domma CMS"},{path:"/views",view:"viewsList",title:"Views - Domma CMS"},{path:"/views/new",view:"viewEditor",title:"New View - Domma CMS"},{path:"/views/edit/:slug",view:"viewEditor",title:"Edit View - Domma CMS"},{path:"/views/:slug/preview",view:"viewPreview",title:"View Preview - Domma CMS"},{path:"/actions",view:"actionsList",title:"Actions - Domma CMS"},{path:"/actions/new",view:"actionEditor",title:"New Action - Domma CMS"},{path:"/actions/edit/:slug",view:"actionEditor",title:"Edit Action - Domma CMS"},{path:"/pro/docs",view:"proDocs",title:"Pro Documentation - Domma CMS"},{path:"/blocks",view:"blocks",title:"Blocks - Domma CMS"},{path:"/blocks/new",view:"blockEditor",title:"New Block - Domma CMS"},{path:"/blocks/edit/:name",view:"blockEditor",title:"Edit Block - Domma CMS"},{path:"/components",view:"components",title:"Components - Domma CMS"},{path:"/components/new",view:"componentEditor",title:"New Component - Domma CMS"},{path:"/components/edit/:name",view:"componentEditor",title:"Edit Component - Domma CMS"},{path:"/my-profile",view:"myProfile",title:"My Profile - Domma CMS"},{path:"/roles",view:"roles",title:"Roles & Permissions - Domma CMS"},{path:"/roles/edit/:id",view:"roleEditor",title:"Edit Role - Domma CMS"},{path:"/effects",view:"effects",title:"Effects - Domma CMS"},{path:"/search",view:"search",title:"Search - Domma CMS"},{path:"/content-api",view:"contentApi",title:"Content API - Domma CMS"},{path:"/notes",view:"notes",title:"Notes - Domma CMS"},{path:"/todo",view:"todo",title:"Todo - Domma CMS"},{path:"/calculator",view:"calculator",title:"Calculator - Domma CMS"},{path:"/analytics",view:"analytics",title:"Analytics - Domma CMS"},{path:"/seo",view:"seo",title:"SEO - Domma CMS"},{path:"/seo/:tab",view:"seo",title:"SEO - Domma CMS"},{path:"/contacts",view:"contacts",title:"Contacts - Domma CMS"},{path:"/calls/new",view:"callNew",title:"Call now - Domma CMS"},{path:"/system/notifications",view:"notifications",title:"Notifications - Domma CMS"},{path:"/api-tokens",view:"apiTokens",title:"API Tokens - Domma CMS"},{path:"/api-endpoints",view:"apiEndpoints",title:"API Builder - Domma CMS"},{path:"/api-endpoints/new",view:"apiEndpointEditor",title:"New API Endpoint - Domma CMS"},{path:"/api-endpoints/edit/:id",view:"apiEndpointEditor",title:"Edit API Endpoint - Domma CMS"},{path:"/projects",view:"projects",title:"Projects - Domma CMS"},{path:"/projects/new",view:"projects",title:"New Project - Domma CMS"},{path:"/projects/edit/:slug",view:"projects",title:"Edit Project - Domma CMS"},{path:"/projects/:slug/settings",view:"projectSettings",title:"Project settings - Domma CMS"},{path:"/projects/:slug/pages",view:"pages",title:"Project pages - Domma CMS"},{path:"/projects/:slug/collections",view:"collections",title:"Project collections - Domma CMS"},{path:"/projects/:slug/forms",view:"forms",title:"Project forms - Domma CMS"},{path:"/projects/:slug/actions",view:"actionsList",title:"Project actions - Domma CMS"},{path:"/projects/:slug/menus",view:"menus",title:"Project menus - Domma CMS"},{path:"/projects/:slug/blocks",view:"blocks",title:"Project blocks - Domma CMS"},{path:"/projects/:slug/components",view:"components",title:"Project components - Domma CMS"},{path:"/projects/:slug/views",view:"viewsList",title:"Project views - Domma CMS"},{path:"/projects/:slug/roles",view:"roles",title:"Project roles - Domma CMS"},{path:"/projects/:slug/users",view:"users",title:"Project users - Domma CMS"},{path:"/projects/:slug/apis",view:"apiEndpoints",title:"Project APIs - Domma CMS"},{path:"/projects/:slug",view:"projectDetail",title:"Project - Domma CMS"},{path:"/login",view:"login",title:"Sign in - Domma CMS",onEnter:()=>{$("#admin-sidebar").hide(),$("#admin-topbar").hide()}},{path:"/reset-password",view:"login",title:"Reset Password - Domma CMS",onEnter:()=>{$("#admin-sidebar").hide(),$("#admin-topbar").hide()}}];M.subscribe("router:afterChange",async({to:t,from:i})=>{if(!b(t.path)){if($("#admin-sidebar").show(),$("#admin-topbar").show(),b(i?.path)){$("#topbar-user-name").remove(),import("./lib/admin-theme.js").then(a=>a.refreshAdminTheme(c)),await U();const e=await f(),o=D(t.path);if(o&&R.navigate(o),j(e),lt.read().signInToasts)try{const a=await c.system.notifications.list().catch(()=>[]),n=(Array.isArray(a)?a:[]).filter(s=>s.unread&&["warning","critical"].includes(s.data?.severity)).slice(0,3);for(const s of n){const v=d(s.data?.title||""),T=d((s.data?.body||"").slice(0,120));E.toast(`${v} - ${T}`,{type:s.data?.severity==="critical"?"error":"warning",duration:0})}}catch{}}B()}}),M.subscribe("router:afterChange",()=>{setTimeout(()=>{$(".btn-primary, .btn-danger").length&&Domma.effects.reveal(".btn-primary, .btn-danger",{animation:"fade",stagger:40,duration:300})},50)});const H=["#field-project","#menu-project","#collection-project","#endpoint-project","#action-project","#view-project","#block-project","#component-project","#role-project",'[name="project"]','[name="ownedByProject"]'];function q(t){return/^\/(pages|menus|context-menus|collections|forms|actions|views|blocks|components|users|roles|api-endpoints)\/(new|edit\/)/.test(t)}M.subscribe("router:afterChange",({to:t})=>{const i=t?String(t.path).split("?")[0]:"";if(!t||!q(i))return;const o=new URLSearchParams(location.hash.split("?")[1]||"").get("project");if(!o||!/\/new$/.test(i))return;let a=0;const n=60,s=1500,v=()=>{a+=n;for(const T of H){const C=document.querySelector(T);if(!C)continue;if(Array.from(C.options||[]).find(z=>z.value===o)){C.value=o,C.dispatchEvent(new Event("change",{bubbles:!0}));return}}a<s&&setTimeout(v,n)};setTimeout(v,n)});const L="cms_card_states",k=S.get(L)||{};M.subscribe("router:afterChange",()=>{setTimeout(()=>{$("#view-container .card-collapsible").each(function(){const t=$(this).find(".card-header h2, .card-header h3").first().text().trim();t&&k[t]==="collapsed"&&$(this).addClass("card-collapsed")})},200)}),$("#view-container").on("click",".card-collapsible .card-header",function(t){if($(t.target).closest("button, a").length)return;const i=$(this).closest(".card");i.toggleClass("card-collapsed");const e=$(this).find("h2, h3").first().text().trim();e&&(k[e]=i.hasClass("card-collapsed")?"collapsed":"open",S.set(L,k))}),pt(),document.addEventListener("keydown",t=>{if(!(t.ctrlKey||t.metaKey)||t.key!=="s"||window.location.hash.startsWith("#/login")||window.location.hash.startsWith("#/reset-password"))return;const i=document.querySelector("#view-container .view-header button.btn-primary");i&&(t.preventDefault(),i.click())});const l={...K},G={notes:{displayName:"Notes",icon:"edit-3"},todo:{displayName:"Todo",icon:"check-square"},calculator:{displayName:"Calculator",icon:"calculator"},analytics:{displayName:"Analytics",icon:"chart-bar"},seo:{displayName:"SEO",icon:"search"},contacts:{displayName:"Contacts",icon:"users"},projects:{displayName:"Projects",icon:"folder"},pages:{displayName:"Pages",icon:"file-text"},media:{displayName:"Media",icon:"image"},menus:{displayName:"Site menus",icon:"menu"},contextMenus:{displayName:"Context Menus",icon:"menu"},theme:{displayName:"Theme",icon:"droplet"},collections:{displayName:"Collections",icon:"database"},forms:{displayName:"Forms",icon:"layout"},viewsList:{displayName:"Views",icon:"eye"},actionsList:{displayName:"Actions",icon:"zap"},apiEndpoints:{displayName:"API Builder",icon:"code"},blocks:{displayName:"Blocks",icon:"box"},components:{displayName:"Components",icon:"component"},notifications:{displayName:"Notifications",icon:"bell"},roles:{displayName:"Roles",icon:"shield"},users:{displayName:"Users",icon:"users"},settings:{displayName:"Site Settings",icon:"settings"},effects:{displayName:"Effects",icon:"sparkles"},layouts:{displayName:"Layouts",icon:"layout"},plugins:{displayName:"Marketplace",icon:"store"},myProfile:{displayName:"My Profile",icon:"user"},apiTokens:{displayName:"API Tokens",icon:"key"},search:{displayName:"Search",icon:"search"},contentApi:{displayName:"Content API",icon:"file-text"},dashboard:{displayName:"Dashboard",icon:"home"},dashboards:{displayName:"Dashboards",icon:"home"},pageEditor:{displayName:"Pages",section:"Edit",icon:"file-text"},menuEditor:{displayName:"Site menus",section:"Edit",icon:"menu"},menuLocations:{displayName:"Site menus",section:"Locations",icon:"map-pin"},contextMenuEditor:{displayName:"Context Menus",section:"Edit",icon:"menu"},collectionEditor:{displayName:"Collections",section:"Edit",icon:"database"},collectionEntries:{displayName:"Collections",section:"Entries",icon:"database"},formEditor:{displayName:"Forms",section:"Edit",icon:"layout"},formSubmissions:{displayName:"Forms",section:"Submissions",icon:"inbox"},viewEditor:{displayName:"Views",section:"Edit",icon:"eye"},viewPreview:{displayName:"Views",section:"Preview",icon:"eye"},actionEditor:{displayName:"Actions",section:"Edit",icon:"zap"},apiEndpointEditor:{displayName:"API Builder",section:"Edit",icon:"code"},blockEditor:{displayName:"Blocks",section:"Edit",icon:"box"},componentEditor:{displayName:"Components",section:"Edit",icon:"component"},roleEditor:{displayName:"Roles",section:"Edit",icon:"shield"},userEditor:{displayName:"Users",section:"Edit",icon:"users"},projectDetail:{displayName:"Projects",section:"Overview",icon:"folder"},projectSettings:{displayName:"Projects",section:"Settings",icon:"folder"},pluginCode:{displayName:"Marketplace",section:"Code",icon:"code"}};for(const[t,i]of Object.entries(G))l[t]&&(l[t]=O(l[t],{plugin:t,licence:"Built in",...i}));l.dashboard=_(l.dashboard);const I=[...W];async function U(){if(m())try{const t=await c.plugins.adminConfig(),i=new Set(I.map(e=>e.path));for(const e of t.routes||[])i.has(e.path)||I.push(e);for(const[e,o]of Object.entries(t.views||{}))try{const a=await import(`/plugins/${o.entry}`);l[e]=O(a[o.exportName],(t.meta||{})[e])}catch{}l.dashboard=_(l.dashboard);for(const[e,{route:o}]of Object.entries(t.takeovers||{}))o&&(y[`/${e}`]=o);for(const[e,{enabled:o,displayName:a}]of Object.entries(t.tools||{}))o===!1&&(N[`/${e}`]=a);for(const{id:e,href:o}of t.css||[])if(!document.getElementById(e)){const a=document.createElement("link");a.id=e,a.rel="stylesheet",a.href=o,document.head.appendChild(a)}}catch{}}function B(){const t=x();if(!t||$("#topbar-user-name").length)return;const e={"super-admin":"Super Admin",admin:"Admin",user:"User"}[t.role]||t.role,o=rt(t);$("#topbar-user").html(`
|
|
1
|
+
import{views as K}from"./views/index.js";import{withPluginChrome as O}from"./lib/plugin-chrome.js";import{api as c,getUser as x,isAuthenticated as m,logout as J,sendToLogin as Y}from"./api.js";import{claimDrafts as Q}from"./lib/draft-owner.js";import{isAuthScreen as b,loginHashFor as X}from"./lib/login-arrange.js";import{installHttpInterceptor as Z}from"./http-interceptor.js";import{installResizableSlideovers as tt}from"./lib/slideover-resizable.js";import{installActivityThrobber as et}from"./lib/activity-throbber.js";import{installUpdateNotice as it}from"./lib/update-notice.js";import{isPathAllowed as ot,redirectFor as at}from"./lib/admin-scope.js";import{deliverDesktop as st,desktopActive as nt,notificationSettings as rt}from"./lib/desktop-notify.js";import{avatarUrl as lt}from"./lib/avatar.js";import{installCalculator as ct}from"./lib/calculator.js";import{takeOverviewPass as mt,withDashboardStrip as _}from"./lib/dashboards-strip.js";import{installHotkeys as pt}from"./lib/hotkeys-ui.js";import{applyAdminBrand as V}from"./lib/admin-brand.js";import{installRouterCatchUp as dt}from"./lib/router-catch-up.js";$(()=>{Z(),ct(),it(),et(),tt(),(async()=>{const{applyAdminTheme:t,refreshAdminTheme:i}=await import("./lib/admin-theme.js");m()?await i(c,{init:!0}):t({dommaTheme:"charcoal-dark"},{init:!0})})();let p=null,h=null,l="/",w=!1,g=null;function D(t){if(N[t])return E.toast(`${N[t]} is switched off on this site.`,{type:"info"}),"/";if(t.split("?")[0]==="/my-dashboard")return"/dashboards";const i=y[t]||at(p,t);return i||((t.split("?")[0]||"/")==="/"&&l&&l!=="/"&&!mt()?y[l]||l:null)}const y={},N={};R.use(async(t,i,e)=>{if(b(t.path))return e();if(!m()){Y();return}const o=D(t.path);if(o){R.navigate(o);return}e()});async function f(){try{const t=await c.get("/auth/permissions");p=t.adminScope||null,h=t.adminBrand||null,V(h),l=t.adminHome||"/";const i=t.permissions||[];return w=ot(p,"/settings")&&i.some(e=>e==="settings"||e.startsWith("settings.")),g=i.some(e=>e==="notifications"||e.startsWith("notifications.")),i}catch{return p=null,l="/",h||V(null),w=!1,g=null,[]}}document.addEventListener("dm:admin-home-changed",()=>{f()});let P=null,A=!1;document.addEventListener("dm:sidebar-rebuild",()=>{if(P){A=!0;return}P=(async()=>{do{A=!1;try{await j(await f())}catch{}}while(A)})().finally(()=>{P=null})});async function j(t){const{renderAdminSidebar:i}=await import("./lib/sidebar-renderer.js");await i({mount:"#admin-sidebar",permissions:t,adminScope:p,brand:h})}M.subscribe("router:afterChange",({to:t})=>{b(t.path)&&(u&&(clearInterval(u),u=null),p=null,l="/",w=!1,g=null)});const W=[{path:"/",view:"dashboard",title:"Dashboard - Domma CMS"},{path:"/dashboards",view:"dashboards",title:"Dashboards - Domma CMS"},{path:"/my-dashboard",view:"dashboards",title:"Dashboards - Domma CMS"},{path:"/pages",view:"pages",title:"Pages - Domma CMS"},{path:"/pages/new",view:"pageEditor",title:"New Page - Domma CMS"},{path:"/pages/edit/*",view:"pageEditor",title:"Edit Page - Domma CMS"},{path:"/media",view:"media",title:"Media - Domma CMS"},{path:"/menus",view:"menus",title:"Menus - Domma CMS"},{path:"/context-menus",view:"contextMenus",title:"Context Menus - Domma CMS"},{path:"/context-menus/new",view:"contextMenuEditor",title:"New Context Menu - Domma CMS"},{path:"/context-menus/edit/:slug",view:"contextMenuEditor",title:"Edit Context Menu - Domma CMS"},{path:"/menus/new",view:"menuEditor",title:"New Menu - Domma CMS"},{path:"/menus/edit/:slug",view:"menuEditor",title:"Edit Menu - Domma CMS"},{path:"/menu-locations",view:"menuLocations",title:"Menu Locations - Domma CMS"},{path:"/navigation",view:"menusRedirect",title:"Menus - Domma CMS"},{path:"/layouts",view:"layouts",title:"Layouts - Domma CMS"},{path:"/settings",view:"settings",title:"Settings - Domma CMS"},{path:"/theme",view:"theme",title:"Theme - Domma CMS"},{path:"/users",view:"users",title:"Users - Domma CMS"},{path:"/users/new",view:"userEditor",title:"New User - Domma CMS"},{path:"/users/edit/:id",view:"userEditor",title:"Edit User - Domma CMS"},{path:"/plugins",view:"plugins",title:"Plugins - Domma CMS"},{path:"/plugins/code/:name",view:"pluginCode",title:"Plugin Code - Domma CMS"},{path:"/documentation",view:"documentation",title:"Usage - Domma CMS"},{path:"/tutorials",view:"tutorials",title:"Tutorials - Domma CMS"},{path:"/tutorials/crud",view:"tutorialCrud",title:"Building a CRUD App - Domma CMS"},{path:"/tutorials/plugin",view:"tutorialPlugin",title:"Writing a Tool - Domma CMS"},{path:"/tutorials/forms",view:"tutorialForms",title:"Form Follow-Up - Domma CMS"},{path:"/docs/components",view:"componentsReference",title:"Components Reference - Domma CMS"},{path:"/docs/components-howto",view:"componentsHowto",title:"Components How-To - Domma CMS"},{path:"/docs/components-walkthrough",view:"componentsWalkthrough",title:"Components Walkthrough - Domma CMS"},{path:"/docs/components-rules",view:"componentsRules",title:"Components Rules - Domma CMS"},{path:"/docs/usage/pages",view:"usagePages",title:"Pages - Usage - Domma CMS"},{path:"/docs/usage/media",view:"usageMedia",title:"Media - Usage - Domma CMS"},{path:"/docs/usage/navigation",view:"usageNavigation",title:"Navigation - Usage - Domma CMS"},{path:"/docs/usage/dconfig",view:"usageDconfig",title:"DConfig - Usage - Domma CMS"},{path:"/docs/usage/shortcodes",view:"usageShortcodes",title:"Shortcodes - Usage - Domma CMS"},{path:"/docs/usage/site-settings",view:"usageSiteSettings",title:"Site Settings - Usage - Domma CMS"},{path:"/docs/usage/plugins",view:"usagePlugins",title:"Plugins - Usage - Domma CMS"},{path:"/docs/usage/users-roles",view:"usageUsersRoles",title:"Users & Roles - Usage - Domma CMS"},{path:"/docs/usage/views",view:"usageViews",title:"Views - Usage - Domma CMS"},{path:"/docs/usage/actions",view:"usageActions",title:"Actions - Usage - Domma CMS"},{path:"/docs/usage/cta-shortcode",view:"usageCtaShortcode",title:"CTA Shortcode - Usage - Domma CMS"},{path:"/docs/usage/editions",view:"usageEditions",title:"Editions & Licences - Usage - Domma CMS"},{path:"/docs/usage/collections",view:"usageCollections",title:"Collections & Forms - Usage - Domma CMS"},{path:"/docs/usage/blocks",view:"usageBlocks",title:"Blocks - Usage - Domma CMS"},{path:"/docs/usage/tools",view:"usageTools",title:"Built-in Tools - Usage - Domma CMS"},{path:"/docs/usage/dashboard",view:"usageDashboard",title:"Dashboard - Usage - Domma CMS"},{path:"/docs/plugins",view:"pluginGuides",title:"Plugin Guides - Domma CMS"},{path:"/docs/plugins/*",view:"pluginGuide",title:"Plugin Guide - Domma CMS"},{path:"/docs/api/authentication",view:"apiRefAuthentication",title:"Authentication - API - Domma CMS"},{path:"/docs/api/pages",view:"apiRefPages",title:"Pages - API - Domma CMS"},{path:"/docs/api/settings",view:"apiRefSettings",title:"Settings - API - Domma CMS"},{path:"/docs/api/layouts",view:"apiRefLayouts",title:"Layouts - API - Domma CMS"},{path:"/docs/api/navigation",view:"apiRefNavigation",title:"Navigation - API - Domma CMS"},{path:"/docs/api/media",view:"apiRefMedia",title:"Media - API - Domma CMS"},{path:"/docs/api/users",view:"apiRefUsers",title:"Users - API - Domma CMS"},{path:"/docs/api/plugins",view:"apiRefPlugins",title:"Plugins - API - Domma CMS"},{path:"/docs/api/collections",view:"apiRefCollections",title:"Collections - API - Domma CMS"},{path:"/docs/api/views",view:"apiRefViews",title:"Views API - Domma CMS"},{path:"/docs/api/actions",view:"apiRefActions",title:"Actions API - Domma CMS"},{path:"/docs/api/forms",view:"apiRefForms",title:"Forms API - Domma CMS"},{path:"/docs/api/scaffold",view:"apiRefScaffold",title:"Scaffold API - Domma CMS"},{path:"/docs/api/external",view:"apiRefExternal",title:"External API & Tokens - Domma CMS"},{path:"/docs/api/content",view:"apiRefContent",title:"Content API - Domma CMS"},{path:"/docs/api/builder",view:"apiRefBuilder",title:"API Builder - Domma CMS"},{path:"/api-reference",view:"apiReference",title:"API Reference - Domma CMS"},{path:"/collections",view:"collections",title:"Collections - Domma CMS"},{path:"/collections/new",view:"collectionEditor",title:"New Collection - Domma CMS"},{path:"/collections/edit/:slug",view:"collectionEditor",title:"Edit Collection - Domma CMS"},{path:"/collections/:slug/entries",view:"collectionEntries",title:"Entries - Domma CMS"},{path:"/forms",view:"forms",title:"Forms - Domma CMS"},{path:"/forms/new",view:"formEditor",title:"New Form - Domma CMS"},{path:"/forms/edit/:slug",view:"formEditor",title:"Edit Form - Domma CMS"},{path:"/forms/:slug/submissions",view:"formSubmissions",title:"Submissions - Domma CMS"},{path:"/views",view:"viewsList",title:"Views - Domma CMS"},{path:"/views/new",view:"viewEditor",title:"New View - Domma CMS"},{path:"/views/edit/:slug",view:"viewEditor",title:"Edit View - Domma CMS"},{path:"/views/:slug/preview",view:"viewPreview",title:"View Preview - Domma CMS"},{path:"/actions",view:"actionsList",title:"Actions - Domma CMS"},{path:"/actions/new",view:"actionEditor",title:"New Action - Domma CMS"},{path:"/actions/edit/:slug",view:"actionEditor",title:"Edit Action - Domma CMS"},{path:"/pro/docs",view:"proDocs",title:"Pro Documentation - Domma CMS"},{path:"/blocks",view:"blocks",title:"Blocks - Domma CMS"},{path:"/blocks/new",view:"blockEditor",title:"New Block - Domma CMS"},{path:"/blocks/edit/:name",view:"blockEditor",title:"Edit Block - Domma CMS"},{path:"/components",view:"components",title:"Components - Domma CMS"},{path:"/components/new",view:"componentEditor",title:"New Component - Domma CMS"},{path:"/components/edit/:name",view:"componentEditor",title:"Edit Component - Domma CMS"},{path:"/my-profile",view:"myProfile",title:"My Profile - Domma CMS"},{path:"/roles",view:"roles",title:"Roles & Permissions - Domma CMS"},{path:"/roles/edit/:id",view:"roleEditor",title:"Edit Role - Domma CMS"},{path:"/effects",view:"effects",title:"Effects - Domma CMS"},{path:"/search",view:"search",title:"Search - Domma CMS"},{path:"/content-api",view:"contentApi",title:"Content API - Domma CMS"},{path:"/notes",view:"notes",title:"Notes - Domma CMS"},{path:"/todo",view:"todo",title:"Todo - Domma CMS"},{path:"/calculator",view:"calculator",title:"Calculator - Domma CMS"},{path:"/analytics",view:"analytics",title:"Analytics - Domma CMS"},{path:"/seo",view:"seo",title:"SEO - Domma CMS"},{path:"/seo/:tab",view:"seo",title:"SEO - Domma CMS"},{path:"/wordpress-import",view:"wordpressImport",title:"Import from WordPress - Domma CMS"},{path:"/contacts",view:"contacts",title:"Contacts - Domma CMS"},{path:"/calls/new",view:"callNew",title:"Call now - Domma CMS"},{path:"/system/notifications",view:"notifications",title:"Notifications - Domma CMS"},{path:"/api-tokens",view:"apiTokens",title:"API Tokens - Domma CMS"},{path:"/api-endpoints",view:"apiEndpoints",title:"API Builder - Domma CMS"},{path:"/api-endpoints/new",view:"apiEndpointEditor",title:"New API Endpoint - Domma CMS"},{path:"/api-endpoints/edit/:id",view:"apiEndpointEditor",title:"Edit API Endpoint - Domma CMS"},{path:"/projects",view:"projects",title:"Projects - Domma CMS"},{path:"/projects/new",view:"projects",title:"New Project - Domma CMS"},{path:"/projects/edit/:slug",view:"projects",title:"Edit Project - Domma CMS"},{path:"/projects/:slug/settings",view:"projectSettings",title:"Project settings - Domma CMS"},{path:"/projects/:slug/pages",view:"pages",title:"Project pages - Domma CMS"},{path:"/projects/:slug/collections",view:"collections",title:"Project collections - Domma CMS"},{path:"/projects/:slug/forms",view:"forms",title:"Project forms - Domma CMS"},{path:"/projects/:slug/actions",view:"actionsList",title:"Project actions - Domma CMS"},{path:"/projects/:slug/menus",view:"menus",title:"Project menus - Domma CMS"},{path:"/projects/:slug/blocks",view:"blocks",title:"Project blocks - Domma CMS"},{path:"/projects/:slug/components",view:"components",title:"Project components - Domma CMS"},{path:"/projects/:slug/views",view:"viewsList",title:"Project views - Domma CMS"},{path:"/projects/:slug/roles",view:"roles",title:"Project roles - Domma CMS"},{path:"/projects/:slug/users",view:"users",title:"Project users - Domma CMS"},{path:"/projects/:slug/apis",view:"apiEndpoints",title:"Project APIs - Domma CMS"},{path:"/projects/:slug",view:"projectDetail",title:"Project - Domma CMS"},{path:"/login",view:"login",title:"Sign in - Domma CMS",onEnter:()=>{$("#admin-sidebar").hide(),$("#admin-topbar").hide()}},{path:"/reset-password",view:"login",title:"Reset Password - Domma CMS",onEnter:()=>{$("#admin-sidebar").hide(),$("#admin-topbar").hide()}}];M.subscribe("router:afterChange",async({to:t,from:i})=>{if(!b(t.path)){if($("#admin-sidebar").show(),$("#admin-topbar").show(),b(i?.path)){$("#topbar-user-name").remove(),import("./lib/admin-theme.js").then(a=>a.refreshAdminTheme(c)),await U();const e=await f(),o=D(t.path);if(o&&R.navigate(o),j(e),rt.read().signInToasts)try{const a=await c.system.notifications.list().catch(()=>[]),n=(Array.isArray(a)?a:[]).filter(s=>s.unread&&["warning","critical"].includes(s.data?.severity)).slice(0,3);for(const s of n){const v=d(s.data?.title||""),T=d((s.data?.body||"").slice(0,120));E.toast(`${v} - ${T}`,{type:s.data?.severity==="critical"?"error":"warning",duration:0})}}catch{}}B()}}),M.subscribe("router:afterChange",()=>{setTimeout(()=>{$(".btn-primary, .btn-danger").length&&Domma.effects.reveal(".btn-primary, .btn-danger",{animation:"fade",stagger:40,duration:300})},50)});const H=["#field-project","#menu-project","#collection-project","#endpoint-project","#action-project","#view-project","#block-project","#component-project","#role-project",'[name="project"]','[name="ownedByProject"]'];function q(t){return/^\/(pages|menus|context-menus|collections|forms|actions|views|blocks|components|users|roles|api-endpoints)\/(new|edit\/)/.test(t)}M.subscribe("router:afterChange",({to:t})=>{const i=t?String(t.path).split("?")[0]:"";if(!t||!q(i))return;const o=new URLSearchParams(location.hash.split("?")[1]||"").get("project");if(!o||!/\/new$/.test(i))return;let a=0;const n=60,s=1500,v=()=>{a+=n;for(const T of H){const C=document.querySelector(T);if(!C)continue;if(Array.from(C.options||[]).find(z=>z.value===o)){C.value=o,C.dispatchEvent(new Event("change",{bubbles:!0}));return}}a<s&&setTimeout(v,n)};setTimeout(v,n)});const L="cms_card_states",k=S.get(L)||{};M.subscribe("router:afterChange",()=>{setTimeout(()=>{$("#view-container .card-collapsible").each(function(){const t=$(this).find(".card-header h2, .card-header h3").first().text().trim();t&&k[t]==="collapsed"&&$(this).addClass("card-collapsed")})},200)}),$("#view-container").on("click",".card-collapsible .card-header",function(t){if($(t.target).closest("button, a").length)return;const i=$(this).closest(".card");i.toggleClass("card-collapsed");const e=$(this).find("h2, h3").first().text().trim();e&&(k[e]=i.hasClass("card-collapsed")?"collapsed":"open",S.set(L,k))}),pt(),document.addEventListener("keydown",t=>{if(!(t.ctrlKey||t.metaKey)||t.key!=="s"||window.location.hash.startsWith("#/login")||window.location.hash.startsWith("#/reset-password"))return;const i=document.querySelector("#view-container .view-header button.btn-primary");i&&(t.preventDefault(),i.click())});const r={...K},G={notes:{displayName:"Notes",icon:"edit-3"},todo:{displayName:"Todo",icon:"check-square"},calculator:{displayName:"Calculator",icon:"calculator"},analytics:{displayName:"Analytics",icon:"chart-bar"},seo:{displayName:"SEO",icon:"search"},wordpressImport:{displayName:"Import from WordPress",icon:"download"},contacts:{displayName:"Contacts",icon:"users"},projects:{displayName:"Projects",icon:"folder"},pages:{displayName:"Pages",icon:"file-text"},media:{displayName:"Media",icon:"image"},menus:{displayName:"Site menus",icon:"menu"},contextMenus:{displayName:"Context Menus",icon:"menu"},theme:{displayName:"Theme",icon:"droplet"},collections:{displayName:"Collections",icon:"database"},forms:{displayName:"Forms",icon:"layout"},viewsList:{displayName:"Views",icon:"eye"},actionsList:{displayName:"Actions",icon:"zap"},apiEndpoints:{displayName:"API Builder",icon:"code"},blocks:{displayName:"Blocks",icon:"box"},components:{displayName:"Components",icon:"component"},notifications:{displayName:"Notifications",icon:"bell"},roles:{displayName:"Roles",icon:"shield"},users:{displayName:"Users",icon:"users"},settings:{displayName:"Site Settings",icon:"settings"},effects:{displayName:"Effects",icon:"sparkles"},layouts:{displayName:"Layouts",icon:"layout"},plugins:{displayName:"Marketplace",icon:"store"},myProfile:{displayName:"My Profile",icon:"user"},apiTokens:{displayName:"API Tokens",icon:"key"},search:{displayName:"Search",icon:"search"},contentApi:{displayName:"Content API",icon:"file-text"},dashboard:{displayName:"Dashboard",icon:"home"},dashboards:{displayName:"Dashboards",icon:"home"},pageEditor:{displayName:"Pages",section:"Edit",icon:"file-text"},menuEditor:{displayName:"Site menus",section:"Edit",icon:"menu"},menuLocations:{displayName:"Site menus",section:"Locations",icon:"map-pin"},contextMenuEditor:{displayName:"Context Menus",section:"Edit",icon:"menu"},collectionEditor:{displayName:"Collections",section:"Edit",icon:"database"},collectionEntries:{displayName:"Collections",section:"Entries",icon:"database"},formEditor:{displayName:"Forms",section:"Edit",icon:"layout"},formSubmissions:{displayName:"Forms",section:"Submissions",icon:"inbox"},viewEditor:{displayName:"Views",section:"Edit",icon:"eye"},viewPreview:{displayName:"Views",section:"Preview",icon:"eye"},actionEditor:{displayName:"Actions",section:"Edit",icon:"zap"},apiEndpointEditor:{displayName:"API Builder",section:"Edit",icon:"code"},blockEditor:{displayName:"Blocks",section:"Edit",icon:"box"},componentEditor:{displayName:"Components",section:"Edit",icon:"component"},roleEditor:{displayName:"Roles",section:"Edit",icon:"shield"},userEditor:{displayName:"Users",section:"Edit",icon:"users"},projectDetail:{displayName:"Projects",section:"Overview",icon:"folder"},projectSettings:{displayName:"Projects",section:"Settings",icon:"folder"},pluginCode:{displayName:"Marketplace",section:"Code",icon:"code"}};for(const[t,i]of Object.entries(G))r[t]&&(r[t]=O(r[t],{plugin:t,licence:"Built in",...i}));r.dashboard=_(r.dashboard);const I=[...W];async function U(){if(m())try{const t=await c.plugins.adminConfig(),i=new Set(I.map(e=>e.path));for(const e of t.routes||[])i.has(e.path)||I.push(e);for(const[e,o]of Object.entries(t.views||{}))try{const a=await import(`/plugins/${o.entry}`);r[e]=O(a[o.exportName],(t.meta||{})[e])}catch{}r.dashboard=_(r.dashboard);for(const[e,{route:o}]of Object.entries(t.takeovers||{}))o&&(y[`/${e}`]=o);for(const[e,{enabled:o,displayName:a}]of Object.entries(t.tools||{}))o===!1&&(N[`/${e}`]=a);for(const{id:e,href:o}of t.css||[])if(!document.getElementById(e)){const a=document.createElement("link");a.id=e,a.rel="stylesheet",a.href=o,document.head.appendChild(a)}}catch{}}function B(){const t=x();if(!t||$("#topbar-user-name").length)return;const e={"super-admin":"Super Admin",admin:"Admin",user:"User"}[t.role]||t.role,o=lt(t);$("#topbar-user").html(`
|
|
2
2
|
${o?`<img id="topbar-avatar" class="topbar-avatar" src="${d(o)}" alt="">`:""}
|
|
3
3
|
<span id="topbar-user-name" class="topbar-user-name">${d(t.name)}</span>
|
|
4
4
|
<span class="topbar-role-badge topbar-role-badge--${d(t.role)}">${e}</span>
|
|
@@ -20,4 +20,4 @@ import{views as K}from"./views/index.js";import{withPluginChrome as O}from"./lib
|
|
|
20
20
|
<span data-icon="log-out"></span>
|
|
21
21
|
<span>Sign out</span>
|
|
22
22
|
</a>
|
|
23
|
-
`);const a=$("#topbar-bell").get(0);a&&(a.hidden=!0);const n=$("#topbar-settings").get(0);n&&(n.hidden=!w),$("#topbar-logout-btn").on("click",s=>{s.preventDefault(),J()}),Domma.icons.scan("#admin-topbar"),E.tooltip("#topbar-actions [data-tooltip]",{placement:"bottom"}),F(),u||(u=setInterval(F,6e4))}function d(t){return String(t).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}let u=null;async function F(){if(!(!m()||g===!1))try{const{count:t}=await c.system.notifications.unreadCount();$("#topbar-bell").removeAttr("hidden");const i=$("#topbar-bell-badge");t>0?i.text(t>99?"99+":String(t)).removeAttr("hidden"):i.attr("hidden","").text(""),t>0&&nt()&&st(await c.system.notifications.list().catch(()=>[]))}catch{}}(async()=>{if(!m()&&!window.location.hash.startsWith("#/reset-password"))window.location.hash.startsWith("#/login")||(window.location.hash=X(window.location.hash));else if(Q(x()?.id),await U(),x()){const a=await f(),n=(window.location.hash||"#/").slice(1)||"/",s=D(n);s&&(window.location.hash=`#${s}`),await j(a),B()}const t=R._extractParams.bind(R);R._extractParams=function(o,a){const n=a.indexOf("?");if(n!==-1&&(a=a.slice(0,n)),o.endsWith("/*")){const s=o.slice(0,-2);return a.startsWith(s+"/")?{}:null}return t(o,a)};const i=R._renderNotFound.bind(R);let e="";R._renderNotFound=async function(o){return m()&&e!==o&&(e=o,await U(),R._matchRoute(o).route)?(e="",R._handleRouteChange()):(e="",m()&&$("#admin-sidebar").get(0)?.style.display==="none"?(E.toast("That link goes nowhere - here is your home page.",{type:"warning"}),R.navigate("/")):i(o))},dt(R),R.init({container:"#view-container",routes:I,views:
|
|
23
|
+
`);const a=$("#topbar-bell").get(0);a&&(a.hidden=!0);const n=$("#topbar-settings").get(0);n&&(n.hidden=!w),$("#topbar-logout-btn").on("click",s=>{s.preventDefault(),J()}),Domma.icons.scan("#admin-topbar"),E.tooltip("#topbar-actions [data-tooltip]",{placement:"bottom"}),F(),u||(u=setInterval(F,6e4))}function d(t){return String(t).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}let u=null;async function F(){if(!(!m()||g===!1))try{const{count:t}=await c.system.notifications.unreadCount();$("#topbar-bell").removeAttr("hidden");const i=$("#topbar-bell-badge");t>0?i.text(t>99?"99+":String(t)).removeAttr("hidden"):i.attr("hidden","").text(""),t>0&&nt()&&st(await c.system.notifications.list().catch(()=>[]))}catch{}}(async()=>{if(!m()&&!window.location.hash.startsWith("#/reset-password"))window.location.hash.startsWith("#/login")||(window.location.hash=X(window.location.hash));else if(Q(x()?.id),await U(),x()){const a=await f(),n=(window.location.hash||"#/").slice(1)||"/",s=D(n);s&&(window.location.hash=`#${s}`),await j(a),B()}const t=R._extractParams.bind(R);R._extractParams=function(o,a){const n=a.indexOf("?");if(n!==-1&&(a=a.slice(0,n)),o.endsWith("/*")){const s=o.slice(0,-2);return a.startsWith(s+"/")?{}:null}return t(o,a)};const i=R._renderNotFound.bind(R);let e="";R._renderNotFound=async function(o){return m()&&e!==o&&(e=o,await U(),R._matchRoute(o).route)?(e="",R._handleRouteChange()):(e="",m()&&$("#admin-sidebar").get(0)?.style.display==="none"?(E.toast("That link goes nowhere - here is your home page.",{type:"warning"}),R.navigate("/")):i(o))},dt(R),R.init({container:"#view-container",routes:I,views:r,default:"/",transitions:{enter:"fadeIn",leave:"fadeOut",duration:150}})})()});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const KIND_LABEL={page:"Page",post:"Post",media:"Media",menu:"Menu",category:"Category"},KIND_PLURAL={page:"Pages",post:"Posts",media:"Media",menu:"Menus",category:"Categories"},KIND_ICON={page:"file-text",post:"edit-3",media:"image",menu:"menu",category:"tag"},ACTION={create:{text:"New",tone:"ok"},rename:{text:"New, renamed",tone:"warn"},update:{text:"Update",tone:"info"},keep:{text:"Left as is",tone:"muted"},skip:{text:"Skipped",tone:"muted"}},RESULT={created:{text:"Made",tone:"ok"},updated:{text:"Updated",tone:"info"},kept:{text:"Left as is",tone:"muted"},skipped:{text:"Skipped",tone:"muted"},failed:{text:"Failed",tone:"bad"}},PLAN_FILTERS=[{id:"all",label:"All"},{id:"new",label:"New"},{id:"update",label:"Updates"},{id:"renamed",label:"Renamed"},{id:"keep",label:"Left as is"},{id:"skip",label:"Skipped"},{id:"rebuild",label:"Needs rebuilding"}],REPORT_FILTERS=[{id:"all",label:"All"},{id:"created",label:"Made"},{id:"updated",label:"Updated"},{id:"kept",label:"Left as is"},{id:"skipped",label:"Skipped"},{id:"failed",label:"Failed"},{id:"rebuild",label:"Needs rebuilding"}];const d=e=>!!(e.builder||e.shortcodes?.length);export function planMatches(e,t){switch(t){case"new":return e.action==="create"||e.action==="rename";case"update":return e.action==="update";case"renamed":return e.action==="rename"||!!e.replaces;case"keep":return e.action==="keep";case"skip":return e.action==="skip";case"rebuild":return d(e);default:return!0}}export function reportMatches(e,t){return t==="rebuild"?d(e):t==="all"||!t||e.result===t}export function counts(e,t,i,o=""){const n=e.filter(s=>!o||s.kind===o);return Object.fromEntries(t.map(s=>[s.id,n.filter(a=>i(a,s.id)).length]))}export function kindTabs(e){const t=["page","post","media","menu","category"],i={};for(const o of e)i[o.kind]=(i[o.kind]||0)+1;return[{id:"",label:"Everything",count:e.length},...t.filter(o=>i[o]).map(o=>({id:o,label:KIND_PLURAL[o],count:i[o]}))]}export function planRow(e){const t=ACTION[e.action]||ACTION.skip,i=e.target?e.kind==="menu"?`Menu "${e.target}"`:e.target:"",o=[KIND_LABEL[e.kind]||e.kind];return e.status&&(e.kind==="page"||e.kind==="post")&&o.push(e.status),e.comments&&o.push(`${e.comments} comment${e.comments===1?"":"s"}`),e.count&&o.push(`${e.count} item${e.count===1?"":"s"}`),{key:e.key,kind:e.kind,icon:KIND_ICON[e.kind]||"file",title:e.title||"(untitled)",pill:e.replaces?"Replaces a page":t.text,pillClass:`is-${e.replaces?"warn":t.tone}`,where:i,meta:o.join(" \xB7 "),reason:e.reason||"",rebuild:[e.builder?`Built with ${e.builder}`:"",...(e.shortcodes||[]).map(n=>`[${n}]`)].filter(Boolean).join(" "),chosen:!!e.choice}}export function reportRow(e){const t=RESULT[e.result]||RESULT.skipped;return{key:e.key,kind:e.kind,icon:KIND_ICON[e.kind]||"file",title:e.title||"(untitled)",pill:t.text,pillClass:`is-${t.tone}`,where:e.target||"",meta:[KIND_LABEL[e.kind]||e.kind,e.format==="html"?"kept as HTML":""].filter(Boolean).join(" \xB7 "),reason:[e.reason,...e.notes||[]].filter(Boolean).join(" "),rebuild:[e.builder?`Built with ${e.builder}`:"",...(e.shortcodes||[]).map(i=>`[${i}]`)].filter(Boolean).join(" ")}}export function choiceItems(e,t){const i=[];return t&&i.push({id:"reset",label:"Undo my choice",icon:"rotate-ccw"}),t!=="skip"&&e.action!=="skip"&&e.action!=="keep"&&i.push({id:"skip",label:"Skip this",icon:"x-circle"}),t!=="overwrite"&&e.action==="keep"&&i.push({id:"overwrite",label:"Overwrite my changes here",icon:"refresh-cw"}),t!=="overwrite"&&e.action==="rename"&&(e.kind==="page"||e.kind==="post")&&e.wanted&&e.kind==="page"&&i.push({id:"overwrite",label:`Replace the page at ${e.wanted}`,icon:"refresh-cw"}),t!=="import"&&e.action==="skip"&&/Deleted (on this site|from the Blog)/.test(e.reason||"")&&i.push({id:"import",label:"Import again",icon:"download"}),i}export function applyChoice(e,t,i){const o={...e||{}};return!i||i==="reset"?delete o[t]:o[t]=i,o}export function defaultOptions(e=!1){return{posts:e?"blog":"pages",media:"download",comments:!0,menus:!0,redirects:!0,drafts:!0,choices:{}}}export function cleanOptions(e={},t=!1){const i=defaultOptions(t),o=(n,s,a)=>s.includes(n)?n:a;return{posts:o(e.posts,t?["blog","pages","skip"]:["pages","skip"],i.posts),media:o(e.media,["download","zip","skip"],i.media),comments:e.comments!==!1,menus:e.menus!==!1,redirects:e.redirects!==!1,drafts:e.drafts!==!1,choices:Object.fromEntries(Object.entries(e.choices||{}).filter(([n,s])=>typeof n=="string"&&["skip","overwrite","import"].includes(s)))}}export function optionsSnapshot(e){const t=cleanOptions(e,!0),i=Object.keys(t.choices).sort().map(o=>`${o}=${t.choices[o]}`).join(",");return[t.posts,t.media,t.comments,t.menus,t.redirects,t.drafts,i].join("|")}export const isDirty=(e,t)=>optionsSnapshot(e)!==optionsSnapshot(defaultOptions(t)),draftKey=e=>e?`wordpress-import.draft.${e}`:"";export function liveDrafts(e,t,i){if(!e||typeof e!="object"||!e.items||typeof e.items!="object")return{items:{},pruned:!1};if(e.owner&&i&&e.owner!==i)return{items:{},pruned:!1};const o={};let n=!1;for(const[s,a]of Object.entries(e.items))t.includes(s)&&a?.options&&a.was===s?o[s]=a:n=!0;return{items:o,pruned:n}}export function withDraft(e,t,i,o){const n={...e&&e.owner===t&&e.items||{}};return o?n[i]=o:delete n[i],{owner:t,items:n}}export function draftQuestion({when:e="",file:t=""}={}){return{title:"Choices you left last time",text:`You changed the import options${t?` for ${t}`:""}${e?` (${e})`:""} and left before running it. Throw away those choices and start from the defaults?`,confirmText:"Throw away",cancelText:"Keep them"}}export function progressText(e){if(!e)return"";const t=e.total?` \xB7 ${e.done} of ${e.total}`:"";return`${e.phase||"Working"}${t}${e.current?` \xB7 ${String(e.current).slice(0,80)}`:""}`}export const progressPercent=e=>e?.total?Math.min(100,Math.round(e.done/e.total*100)):0;export function planTiles(e){const t=e?.summary?.counts||{},i=o=>t[o]?t[o].total-t[o].skip:0;return[{id:"page",label:"Pages",value:i("page"),of:t.page?.total||0},{id:"post",label:"Posts",value:i("post"),of:t.post?.total||0},{id:"media",label:"Media",value:i("media"),of:t.media?.total||0},{id:"menu",label:"Menus",value:i("menu"),of:t.menu?.total||0},{id:"comments",label:"Comments",value:e?.summary?.comments||0,of:0},{id:"redirects",label:"Redirects",value:e?.summary?.redirects||0,of:0}].map(o=>({...o,sub:o.of&&o.of!==o.value?`of ${o.of}`:""}))}export function historyRow(e,t=i=>i){const i=e.summary||{},o=Object.values(i.kinds||{}).reduce((a,l)=>a+(l.created||0),0),n=Object.values(i.kinds||{}).reduce((a,l)=>a+(l.updated||0),0),s=[];return o&&s.push(`${o} made`),n&&s.push(`${n} updated`),i.redirects?.created&&s.push(`${i.redirects.created} redirect${i.redirects.created===1?"":"s"}`),i.rebuild&&s.push(`${i.rebuild} to rebuild`),i.failed&&s.push(`${i.failed} failed`),e.status==="failed"&&s.splice(0,s.length,"Stopped before the end - run it again to finish"),{id:e.id,title:e.siteTitle||e.source||"WordPress site",meta:[t(e.at),e.by,e.file].filter(Boolean).join(" \xB7 "),summary:s.join(", ")||"Nothing changed",pill:e.status==="failed"?"Stopped":e.status==="partial"?"Some failed":"Done",pillClass:e.status==="failed"||e.status==="partial"?"is-bad":"is-ok"}}export function stagedRow(e,t=i=>i){const i=e.counts||{},o=[i.page&&`${i.page} pages`,i.post&&`${i.post} posts`,i.attachment&&`${i.attachment} media`].filter(Boolean);return{id:e.id,title:e.siteTitle||e.fileName||"WordPress export",meta:[e.fileName,t(e.at),o.join(", ")].filter(Boolean).join(" \xB7 "),pill:e.uploads?"Uploads zip added":"Waiting",pillClass:e.uploads?"is-ok":"is-muted"}}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<div class="col-12">
|
|
8
8
|
<div class="docs-body">
|
|
9
9
|
|
|
10
|
-
<p>Contacts, Notes, Todo, Calculator, Analytics and
|
|
10
|
+
<p>Contacts, Notes, Todo, Calculator, Analytics, SEO and Import from WordPress are part of the CMS. In the sidebar's Tools folder
|
|
11
11
|
they start in groups by what they are for, alongside the Marketplace Tools:
|
|
12
12
|
<strong>Productivity</strong> (Notes, Todo, Calculator, Calendar), <strong>Communication</strong>
|
|
13
13
|
(Contacts, email, Messages), <strong>Marketing</strong> (Analytics, SEO, Feedback),
|
|
@@ -140,6 +140,18 @@
|
|
|
140
140
|
IndexNow, page speed, rich results, sitemap rules, a not-found log, a link monitor and SEO
|
|
141
141
|
history. Its own guide is under <a href="#/docs/plugins">Plugin guides</a>.</p>
|
|
142
142
|
|
|
143
|
+
<h3>Import from WordPress</h3>
|
|
144
|
+
<p>Brings a WordPress site across: <strong>Tools > Maintenance > Import from WordPress</strong>.
|
|
145
|
+
In WordPress, export everything (<strong>Tools > Export > All content</strong>) and upload the
|
|
146
|
+
.xml file. The preview shows what each page, post, file and menu will become before anything
|
|
147
|
+
changes: pages keep their WordPress addresses where they are free (a taken one gets the next free
|
|
148
|
+
address), posts go to the Blog (or become pages), media comes from the old site while it is still
|
|
149
|
+
online or from a zip of its <code>wp-content/uploads</code> folder, and the old addresses -
|
|
150
|
+
including <code>?p=123</code> links - redirect to the new ones. Yoast and Rank Math titles and
|
|
151
|
+
descriptions carry over. Shortcodes and page-builder layouts this site has no equivalent for are
|
|
152
|
+
listed as <em>needs rebuilding</em>. Run it again later and it updates what it made, leaving alone
|
|
153
|
+
anything you have edited here since unless you choose Overwrite. Each run's report is kept.</p>
|
|
154
|
+
|
|
143
155
|
<h3>Notifications</h3>
|
|
144
156
|
<p>The bell in the admin, and <strong>System > Notifications</strong>. Opening the screen marks
|
|
145
157
|
everything read. Its settings choose which <strong>sources</strong> notify which roles, and
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
<!-- Tools › Import from WordPress. Bound with M.applyBindings - see admin/js/views/wordpress-import.js, which also
|
|
2
|
+
inserts the row templates (the router renders a templateUrl through _.render, eating any {{…}}).
|
|
3
|
+
No page heading: the Tool banner above is the heading. -->
|
|
4
|
+
<div class="wpx">
|
|
5
|
+
<div class="wpx-note dm-loading-slot wpx-loading">Loading…</div>
|
|
6
|
+
<p class="wpx-alert is-bad wpx-failed" role="alert" hidden></p>
|
|
7
|
+
<div class="wpx-body" hidden>
|
|
8
|
+
|
|
9
|
+
<!-- A run in progress -->
|
|
10
|
+
<div class="wpx-card wpx-running" hidden data-bind-hidden="!job.value">
|
|
11
|
+
<div class="wpx-card-title"><span data-icon="download" data-icon-size="16"></span>
|
|
12
|
+
<span data-bind-text="jobTitle.value"></span></div>
|
|
13
|
+
<div class="wpx-bar" role="progressbar" aria-label="Import progress"><span class="wpx-bar-fill"></span></div>
|
|
14
|
+
<p class="wpx-note" data-bind-text="jobText.value"></p>
|
|
15
|
+
<p class="wpx-note">You can leave this screen - the import carries on, and its report is kept under Past imports.</p>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<!-- Start: upload, and uploads waiting -->
|
|
19
|
+
<div class="wpx-start" hidden data-bind-hidden="mode.value !== 'start'">
|
|
20
|
+
<div class="wpx-card">
|
|
21
|
+
<div class="wpx-card-title">Upload a WordPress export
|
|
22
|
+
<span data-help-title="Where the export comes from" data-help="In WordPress, go to Tools › Export, choose All content and press Download Export File. That gives you an .xml file (some hosts zip it - a .zip holding it works too). It holds your pages, posts, comments, menus and the addresses of your media - not the media files themselves; those are fetched from your old site, or from a zip of its wp-content/uploads folder, on the next screen."></span></div>
|
|
23
|
+
<p class="wpx-note">Nothing on this site changes until you have seen the preview and pressed <strong>Run import</strong>. Up to <span data-bind-text="wxrLimit.value"></span>.</p>
|
|
24
|
+
<label class="wpx-drop" data-bind-class="dropping.value && 'is-over'">
|
|
25
|
+
<input type="file" class="wpx-file" accept=".xml,.zip,application/xml,text/xml,application/zip">
|
|
26
|
+
<span data-icon="upload" data-icon-size="22"></span>
|
|
27
|
+
<span><strong>Choose the export file</strong> or drop it here</span>
|
|
28
|
+
</label>
|
|
29
|
+
<div class="wpx-upload" hidden data-bind-hidden="!uploadText.value">
|
|
30
|
+
<div class="wpx-bar"><span class="wpx-bar-fill wpx-upload-fill"></span></div>
|
|
31
|
+
<p class="wpx-note" data-bind-text="uploadText.value"></p>
|
|
32
|
+
</div>
|
|
33
|
+
<p class="wpx-note is-bad" hidden data-bind-hidden="!uploadError.value" data-bind-text="uploadError.value"></p>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="wpx-card" hidden data-bind-hidden="!stagedRows.value.length">
|
|
37
|
+
<div class="wpx-card-title">Waiting to run
|
|
38
|
+
<span data-help="Exports you uploaded but have not imported yet. Click one to see its preview. Right-click (or ⋮, or Shift+F10) to discard it. An upload not run within a day is removed."></span></div>
|
|
39
|
+
<div class="wpx-list wpx-staged" data-each="stagedRows.value key=id"></div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<!-- Preview -->
|
|
44
|
+
<div class="wpx-preview" hidden data-bind-hidden="mode.value !== 'preview'">
|
|
45
|
+
<div class="wpx-card wpx-head">
|
|
46
|
+
<div class="wpx-head-main">
|
|
47
|
+
<strong class="wpx-site" data-bind-text="siteTitle.value"></strong>
|
|
48
|
+
<small class="wpx-note" data-bind-text="siteMeta.value"></small>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="wpx-head-actions">
|
|
51
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="back"><span data-icon="arrow-left" data-icon-size="14"></span> Back</button>
|
|
52
|
+
<button type="button" class="btn btn-sm btn-outline" data-on-click="discard">Discard</button>
|
|
53
|
+
<button type="button" class="btn btn-sm btn-primary wpx-run" data-on-click="run" data-bind-disabled="!canRun.value"><span data-icon="play" data-icon-size="14"></span> Run import</button>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<p class="wpx-alert is-dirty" hidden data-bind-hidden="!dirty.value">
|
|
57
|
+
<span data-icon="edit-3" data-icon-size="16"></span>
|
|
58
|
+
<span>Your choices are kept for this upload if you leave before running it.</span>
|
|
59
|
+
<span class="wpx-spacer"></span>
|
|
60
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="resetChoices">Back to the defaults</button></p>
|
|
61
|
+
|
|
62
|
+
<div class="wpx-card">
|
|
63
|
+
<div class="wpx-card-title">What to import</div>
|
|
64
|
+
<div class="wpx-options">
|
|
65
|
+
<div class="wpx-option">
|
|
66
|
+
<span class="form-label">Posts
|
|
67
|
+
<span data-help-title="Posts" data-help="To the Blog: each post becomes a Blog post, with its categories, tags, featured image, author (matched by email to a user here, otherwise you) and approved comments. As pages: each post becomes a page - under /blog when the site has no Blog switched on, under /posts when it has (the Blog answers at its own address). A post scheduled in WordPress stays scheduled in the Blog; drafts, pending and private posts arrive as drafts."></span></span>
|
|
68
|
+
<div class="wpx-seg" role="group" aria-label="Posts">
|
|
69
|
+
<button type="button" data-on-click="postsBlog" data-bind-class="opt.value.posts === 'blog' && 'is-on'" data-bind-disabled="!blogAvailable.value">To the Blog</button>
|
|
70
|
+
<button type="button" data-on-click="postsPages" data-bind-class="opt.value.posts === 'pages' && 'is-on'">As pages</button>
|
|
71
|
+
<button type="button" data-on-click="postsSkip" data-bind-class="opt.value.posts === 'skip' && 'is-on'">Leave out</button>
|
|
72
|
+
</div>
|
|
73
|
+
<small class="wpx-note" hidden data-bind-hidden="!blogNote.value" data-bind-text="blogNote.value"></small>
|
|
74
|
+
</div>
|
|
75
|
+
<div class="wpx-option">
|
|
76
|
+
<span class="form-label">Media files
|
|
77
|
+
<span data-help-title="Media files" data-help="From the old site: each file is downloaded from the WordPress site's own address while it is still online (only that site - never anywhere else). From a zip: zip the wp-content/uploads folder (your host's file manager or FTP) and upload it below - use this when the old site is offline. Leave out: pages keep pointing at the old site's files. SVG files are never imported (they can carry scripts)."></span></span>
|
|
78
|
+
<div class="wpx-seg" role="group" aria-label="Media files">
|
|
79
|
+
<button type="button" data-on-click="mediaDownload" data-bind-class="opt.value.media === 'download' && 'is-on'">From the old site</button>
|
|
80
|
+
<button type="button" data-on-click="mediaZip" data-bind-class="opt.value.media === 'zip' && 'is-on'">From a zip</button>
|
|
81
|
+
<button type="button" data-on-click="mediaSkip" data-bind-class="opt.value.media === 'skip' && 'is-on'">Leave out</button>
|
|
82
|
+
</div>
|
|
83
|
+
<div class="wpx-zip" hidden data-bind-hidden="opt.value.media !== 'zip'">
|
|
84
|
+
<small class="wpx-note" data-bind-text="zipText.value"></small>
|
|
85
|
+
<div class="wpx-zip-actions">
|
|
86
|
+
<label class="btn btn-sm btn-outline wpx-zip-pick"><input type="file" class="wpx-zip-file" accept=".zip,application/zip" hidden>
|
|
87
|
+
<span data-bind-text="zipButton.value"></span></label>
|
|
88
|
+
<button type="button" class="btn btn-sm btn-ghost" hidden data-bind-hidden="!zipInfo.value" data-on-click="removeZip">Remove</button>
|
|
89
|
+
</div>
|
|
90
|
+
<div class="wpx-upload" hidden data-bind-hidden="!zipUploadText.value">
|
|
91
|
+
<div class="wpx-bar"><span class="wpx-bar-fill wpx-zip-fill"></span></div>
|
|
92
|
+
<small class="wpx-note" data-bind-text="zipUploadText.value"></small>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
<div class="wpx-toggles">
|
|
97
|
+
<label class="wpx-toggle"><input type="checkbox" class="form-switch" data-model="optComments.value" data-bind-disabled="opt.value.posts !== 'blog'"> Approved comments
|
|
98
|
+
<span data-help="Approved comments go to the Blog's comments, replies under the comment they answer. Spam, unapproved comments, pingbacks and trackbacks are never imported."></span></label>
|
|
99
|
+
<label class="wpx-toggle"><input type="checkbox" class="form-switch" data-model="optMenus.value"> Menus
|
|
100
|
+
<span data-help="Each WordPress menu becomes a menu here (wp-…), pointing at the new addresses. It is not put on the site until you choose it for the navbar or a footer in Menus › Locations."></span></label>
|
|
101
|
+
<label class="wpx-toggle"><input type="checkbox" class="form-switch" data-model="optRedirects.value"> Redirects from the old addresses
|
|
102
|
+
<span data-help-title="Redirects" data-help="Links and search results that point at the old addresses keep working: each old page, post, category and tag address answers with a permanent (301) redirect to its new one, in SEO › Redirects. ?p=123 and ?page_id=45 addresses are answered too. An address a page on this site already uses is never redirected."></span></label>
|
|
103
|
+
<label class="wpx-toggle"><input type="checkbox" class="form-switch" data-model="optDrafts.value"> Drafts and private items
|
|
104
|
+
<span data-help="Drafts, pending, private and password-protected pages and posts - imported as drafts, so nobody sees them until you publish them. Items in the WordPress bin are never imported."></span></label>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<div class="wpx-note dm-loading-slot wpx-plan-loading" data-bind-hidden="!planLoading.value">Reading the export…</div>
|
|
110
|
+
<p class="wpx-note is-bad" hidden data-bind-hidden="!planError.value" data-bind-text="planError.value"></p>
|
|
111
|
+
|
|
112
|
+
<div class="wpx-plan" hidden data-bind-hidden="!plan.value">
|
|
113
|
+
<div class="wpx-tiles" data-each="tiles.value key=id"></div>
|
|
114
|
+
<div class="wpx-notes" hidden data-bind-hidden="!notes.value.length">
|
|
115
|
+
<div class="wpx-note-list" data-each="notes.value key=text"></div>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div class="wpx-card">
|
|
119
|
+
<div class="wpx-card-title">Item by item
|
|
120
|
+
<span data-help-title="Item by item" data-help="What happens to each page, post, file and menu. New: made here. Renamed: its address is taken here, so it gets the next free one (the old address redirects to it). Update: made by an earlier import and unchanged here since - refreshed. Left as is: made by an earlier import but edited here since - not touched unless you choose Overwrite. Right-click (or ⋮, or Shift+F10) an item to skip it or change what happens. Needs rebuilding: shortcodes and page builders this site has no equivalent for - the text stays, the layout is yours to rebuild."></span>
|
|
121
|
+
<span class="wpx-spacer"></span>
|
|
122
|
+
<small class="wpx-note" hidden data-bind-hidden="!refreshing.value">Updating…</small></div>
|
|
123
|
+
<div class="wpx-bar-row">
|
|
124
|
+
<div class="wpx-seg wpx-kinds" role="group" aria-label="Kind" data-each="kinds.value key=id"></div>
|
|
125
|
+
</div>
|
|
126
|
+
<div class="wpx-bar-row">
|
|
127
|
+
<div class="wpx-seg wpx-filters" role="group" aria-label="Show" data-each="filters.value key=id"></div>
|
|
128
|
+
<input type="search" class="form-input wpx-search" placeholder="Search titles and addresses…" aria-label="Search items" data-model="query.value">
|
|
129
|
+
</div>
|
|
130
|
+
<p class="wpx-note" hidden data-bind-hidden="rows.value.length" data-bind-text="emptyText.value"></p>
|
|
131
|
+
<div class="wpx-list wpx-items" data-each="rows.value key=key"></div>
|
|
132
|
+
<p class="wpx-note" hidden data-bind-hidden="!moreText.value" data-bind-text="moreText.value"></p>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
<div class="wpx-card" hidden data-bind-hidden="!redirectRows.value.length">
|
|
136
|
+
<div class="wpx-card-title">Redirects
|
|
137
|
+
<span data-bind-text="redirectCount.value" class="wpx-chip"></span>
|
|
138
|
+
<span data-help="The old addresses that will send visitors (and search engines) on to the new ones. Skipped ones say why."></span></div>
|
|
139
|
+
<div class="wpx-list wpx-redirects" data-each="redirectRows.value key=from"></div>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
<!-- History -->
|
|
145
|
+
<div class="wpx-card" hidden data-bind-hidden="mode.value === 'preview'">
|
|
146
|
+
<div class="wpx-card-title">Past imports
|
|
147
|
+
<span data-help="Every import run on this site, with its report: what was made, the redirects added, the shortcodes and layouts to rebuild, and anything that failed. Click one to read its report. Removing one from this list keeps everything it imported."></span></div>
|
|
148
|
+
<p class="wpx-note" hidden data-bind-hidden="historyRows.value.length">Nothing imported yet.</p>
|
|
149
|
+
<div class="wpx-list wpx-history" data-each="historyRows.value key=id"></div>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<style>
|
|
155
|
+
.wpx, .wpx-body, .wpx-start, .wpx-preview, .wpx-plan { display: flex; flex-direction: column; gap: .75rem; }
|
|
156
|
+
.wpx [hidden] { display: none !important; }
|
|
157
|
+
.wpx-note { margin: 0; color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
158
|
+
.wpx-note.is-bad { color: var(--dm-danger); }
|
|
159
|
+
.wpx-alert { margin: 0; display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; padding: .6rem .8rem; border-radius: var(--dm-radius-md);
|
|
160
|
+
background: color-mix(in srgb, var(--dm-warning) 16%, transparent); color: var(--dm-text); }
|
|
161
|
+
.wpx-alert.is-bad { background: color-mix(in srgb, var(--dm-danger) 14%, transparent); color: var(--dm-danger); }
|
|
162
|
+
.wpx-alert.is-dirty { background: color-mix(in srgb, var(--dm-primary) 12%, transparent); }
|
|
163
|
+
.wpx-spacer { flex: 1; }
|
|
164
|
+
.wpx-card { border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); padding: .75rem .9rem; display: flex; flex-direction: column; gap: .65rem; background: var(--dm-surface); }
|
|
165
|
+
.wpx-card-title { display: flex; align-items: center; gap: .35rem; font-weight: 600; }
|
|
166
|
+
.wpx .form-label { display: inline-flex; align-items: center; gap: .3rem; margin: 0; font-weight: 600; }
|
|
167
|
+
.wpx-drop { display: flex; align-items: center; justify-content: center; gap: .6rem; flex-wrap: wrap; text-align: center; min-height: 6rem; padding: 1rem;
|
|
168
|
+
border: 2px dashed var(--dm-border); border-radius: var(--dm-radius-md); cursor: pointer; color: var(--dm-text-muted); }
|
|
169
|
+
.wpx-drop:hover, .wpx-drop.is-over, .wpx-drop:focus-within { border-color: var(--dm-primary); color: var(--dm-text); background: color-mix(in srgb, var(--dm-primary) 6%, transparent); }
|
|
170
|
+
.wpx-drop input { position: absolute; width: 1px; height: 1px; opacity: 0; }
|
|
171
|
+
.wpx-bar { height: .5rem; border-radius: 999px; background: color-mix(in srgb, var(--dm-text) 10%, transparent); overflow: hidden; }
|
|
172
|
+
.wpx-bar-fill { display: block; height: 100%; width: 0; background: var(--dm-primary); transition: width .3s; }
|
|
173
|
+
.wpx-upload { display: flex; flex-direction: column; gap: .35rem; }
|
|
174
|
+
.wpx-head { flex-direction: row; align-items: center; flex-wrap: wrap; }
|
|
175
|
+
.wpx-head-main { flex: 1 1 16rem; display: flex; flex-direction: column; min-width: 0; }
|
|
176
|
+
.wpx-site { font-size: var(--dm-text-lg); overflow-wrap: anywhere; }
|
|
177
|
+
.wpx-head-actions { display: flex; gap: .4rem; flex-wrap: wrap; }
|
|
178
|
+
.wpx-options { display: flex; flex-direction: column; gap: .9rem; }
|
|
179
|
+
.wpx-option { display: flex; flex-direction: column; gap: .4rem; }
|
|
180
|
+
.wpx-toggles { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem 1rem; }
|
|
181
|
+
.wpx-toggle { display: flex; align-items: center; gap: .5rem; font-size: var(--dm-text-sm); }
|
|
182
|
+
.wpx-zip { display: flex; flex-direction: column; gap: .4rem; padding: .5rem .65rem; border: 1px dashed var(--dm-border); border-radius: var(--dm-radius-md); }
|
|
183
|
+
.wpx-zip-actions { display: flex; gap: .4rem; align-items: center; }
|
|
184
|
+
.wpx-zip-pick { cursor: pointer; }
|
|
185
|
+
.wpx-seg { display: inline-flex; flex-wrap: wrap; border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); overflow: hidden; align-self: flex-start; }
|
|
186
|
+
.wpx-seg button { display: inline-flex; align-items: center; gap: .35rem; border: 0; background: none; color: var(--dm-text); padding: .35rem .75rem; cursor: pointer; font: inherit; font-size: var(--dm-text-sm); }
|
|
187
|
+
.wpx-seg button + button { border-left: 1px solid var(--dm-border); }
|
|
188
|
+
.wpx-seg button:hover:not(:disabled) { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 6%, transparent)); }
|
|
189
|
+
.wpx-seg button.is-on { background: var(--dm-primary); color: var(--dm-primary-text); }
|
|
190
|
+
.wpx-seg button:disabled { opacity: .45; cursor: not-allowed; }
|
|
191
|
+
.wpx-seg b { font-weight: 600; opacity: .8; }
|
|
192
|
+
.wpx-bar-row { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
|
|
193
|
+
.wpx-search { max-width: 18rem; }
|
|
194
|
+
.wpx-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr)); gap: .6rem; }
|
|
195
|
+
.wpx-tile { border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); padding: .6rem .75rem; background: var(--dm-surface); display: flex; flex-direction: column; }
|
|
196
|
+
.wpx-tile strong { font-size: var(--dm-text-xl, 1.4rem); font-variant-numeric: tabular-nums; }
|
|
197
|
+
.wpx-tile small { color: var(--dm-text-muted); font-size: var(--dm-text-xs); }
|
|
198
|
+
.wpx-notes { display: flex; flex-direction: column; gap: .35rem; }
|
|
199
|
+
.wpx-note-list { display: flex; flex-direction: column; gap: .35rem; }
|
|
200
|
+
.wpx-list { display: flex; flex-direction: column; }
|
|
201
|
+
.wpx-row { display: flex; align-items: flex-start; gap: .65rem; padding: .55rem .35rem; border-bottom: 1px solid var(--dm-border); cursor: pointer; }
|
|
202
|
+
.wpx-row:last-child { border-bottom: 0; }
|
|
203
|
+
.wpx-row:hover, .wpx-row:focus-visible { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 6%, transparent)); outline: none; }
|
|
204
|
+
.wpx-row-icon { color: var(--dm-text-muted); padding-top: .15rem; display: inline-flex; }
|
|
205
|
+
.wpx-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .1rem; }
|
|
206
|
+
.wpx-main strong { overflow-wrap: anywhere; }
|
|
207
|
+
.wpx-main small { color: var(--dm-text-muted); font-size: var(--dm-text-xs); overflow-wrap: anywhere; }
|
|
208
|
+
.wpx-where { font-family: var(--dm-font-mono, monospace); font-size: var(--dm-text-xs); color: var(--dm-text); }
|
|
209
|
+
.wpx-reason { color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
210
|
+
.wpx-rebuild { color: var(--dm-warning); font-size: var(--dm-text-xs); font-family: var(--dm-font-mono, monospace); overflow-wrap: anywhere; }
|
|
211
|
+
.wpx-chips { display: flex; gap: .35rem; flex-wrap: wrap; justify-content: flex-end; }
|
|
212
|
+
.wpx-chip { display: inline-flex; align-items: center; font-size: var(--dm-text-xs); font-weight: 600; padding: .15rem .55rem; border-radius: 999px; white-space: nowrap;
|
|
213
|
+
background: color-mix(in srgb, var(--dm-text) 10%, transparent); color: var(--dm-text-muted); }
|
|
214
|
+
.wpx-chip.is-ok { background: color-mix(in srgb, var(--dm-success) 16%, transparent); color: var(--dm-success); }
|
|
215
|
+
.wpx-chip.is-info { background: color-mix(in srgb, var(--dm-info, var(--dm-primary)) 16%, transparent); color: var(--dm-info, var(--dm-primary)); }
|
|
216
|
+
.wpx-chip.is-warn { background: color-mix(in srgb, var(--dm-warning) 18%, transparent); color: var(--dm-warning); }
|
|
217
|
+
.wpx-chip.is-bad { background: color-mix(in srgb, var(--dm-danger) 16%, transparent); color: var(--dm-danger); }
|
|
218
|
+
.wpx-chip.is-chosen { box-shadow: inset 0 0 0 1px var(--dm-primary); }
|
|
219
|
+
.wpx-kebab { border: 0; background: none; cursor: pointer; font-size: var(--dm-text-lg); color: var(--dm-text-muted); border-radius: var(--dm-radius-sm); padding: 0 .3rem; }
|
|
220
|
+
.wpx-kebab:hover { color: var(--dm-primary); }
|
|
221
|
+
.wpx-report { display: flex; flex-direction: column; gap: .75rem; padding: .25rem 0; }
|
|
222
|
+
@media (max-width: 720px) { .wpx-toggles { grid-template-columns: 1fr; } .wpx-row { flex-wrap: wrap; } .wpx-chips { justify-content: flex-start; } }
|
|
223
|
+
</style>
|
package/admin/js/views/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dashboardView as o}from"./dashboard.js";import{dashboardsView as i}from"./dashboards.js";import{pagesView as r}from"./pages.js";import{pageEditorView as t}from"./page-editor.js";import{settingsView as e}from"./settings.js";import{themeView as m}from"./theme.js";import{notificationsView as p}from"./notifications.js";import{layoutsView as
|
|
1
|
+
import{dashboardView as o}from"./dashboard.js";import{dashboardsView as i}from"./dashboards.js";import{pagesView as r}from"./pages.js";import{pageEditorView as t}from"./page-editor.js";import{settingsView as e}from"./settings.js";import{themeView as m}from"./theme.js";import{notificationsView as p}from"./notifications.js";import{layoutsView as s}from"./layouts.js";import{mediaView as n}from"./media.js";import{loginView as f}from"./login.js";import{usersView as w}from"./users.js";import{userEditorView as c}from"./user-editor.js";import{pluginsView as V}from"./plugins.js";import{pluginCodeView as a}from"./plugin-code.js";import{documentationView as d}from"./documentation.js";import{tutorialsView as l}from"./tutorials.js";import{docViews as u}from"./doc-pages.js";import{pluginGuidesView as E,pluginGuideView as g}from"./plugin-guides.js";import{apiReferenceView as b}from"./api-reference.js";import{collectionsView as h}from"./collections.js";import{collectionEditorView as v}from"./collection-editor.js";import{collectionEntriesView as y}from"./collection-entries.js";import{formsView as j}from"./forms.js";import{formEditorView as k}from"./form-editor.js";import{formSubmissionsView as L}from"./form-submissions.js";import{viewsListView as x}from"./views-list.js";import{viewEditorView as M}from"./view-editor.js";import{viewPreviewView as D}from"./view-preview.js";import{actionsListView as G}from"./actions-list.js";import{actionEditorView as P}from"./action-editor.js";import{proDocsView as R}from"./pro-docs.js";import{blocksView as S}from"./blocks.js";import{blockEditorView as A}from"./block-editor.js";import{componentsView as C}from"./components.js";import{componentEditorView as I}from"./component-editor.js";import{myProfileView as N}from"./my-profile.js";import{rolesView as T}from"./roles.js";import{roleEditorView as U}from"./role-editor.js";import{effectsView as q}from"./effects.js";import{searchView as z}from"./search.js";import{contentApiView as B}from"./content-api.js";import{notesView as F}from"./notes.js";import{todoView as H}from"./todo.js";import{calculatorView as J}from"../lib/calculator.js";import{analyticsView as K}from"./analytics.js";import{seoView as O}from"./seo.js";import{wordpressImportView as Q}from"./wordpress-import.js";import{contactsView as W}from"./contacts.js";import{callNewView as X}from"./call-new.js";import{menusView as Y}from"./menus.js";import{contextMenusView as Z}from"./context-menus.js";import{contextMenuEditorView as _}from"./context-menu-editor.js";import{menuEditorView as $}from"./menu-editor.js";import{menuLocationsView as oo}from"./menu-locations.js";import{projectsView as io}from"./projects.js";import{projectDetailView as ro}from"./project-detail.js";import{projectSettingsView as to}from"./project-settings.js";import{apiTokensView as eo}from"./api-tokens.js";import{apiEndpointsView as mo}from"./api-endpoints.js";import{apiEndpointEditorView as po}from"./api-endpoint-editor.js";const so={templateUrl:"",async onMount(){location.hash="#/menus"}};export const views={projects:io,projectDetail:ro,projectSettings:to,apiTokens:eo,apiEndpoints:mo,apiEndpointEditor:po,dashboard:o,dashboards:i,pages:r,pageEditor:t,settings:e,theme:m,layouts:s,media:n,login:f,users:w,userEditor:c,plugins:V,pluginCode:a,documentation:d,tutorials:l,apiReference:b,collections:h,collectionEditor:v,collectionEntries:y,forms:j,formEditor:k,formSubmissions:L,viewsList:x,viewEditor:M,viewPreview:D,actionsList:G,actionEditor:P,proDocs:R,blocks:S,blockEditor:A,components:C,componentEditor:I,myProfile:N,roles:T,roleEditor:U,effects:q,search:z,contentApi:B,notes:F,todo:H,calculator:J,analytics:K,seo:O,wordpressImport:Q,contacts:W,callNew:X,notifications:p,menus:Y,contextMenus:Z,contextMenuEditor:_,menuEditor:$,menuLocations:oo,menusRedirect:so,pluginGuides:E,pluginGuide:g,...u};
|