domma-cms 1.8.10 → 1.8.12
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 +10 -0
- package/CLAUDE.md +27 -0
- package/admin/js/lib/seo-redirects.js +1 -1
- package/admin/js/lib/wordpress-import-arrange.js +1 -1
- package/admin/js/templates/docs/usage-tools.html +8 -0
- package/admin/js/templates/wordpress-import.html +27 -0
- package/admin/js/views/wordpress-import.js +12 -10
- package/package.json +1 -1
- package/server/routes/api/wordpress-import.js +4 -1
- package/server/services/content.js +6 -2
- package/server/services/seo/index.js +38 -4
- package/server/services/wpImport/front.js +82 -0
- package/server/services/wpImport/index.js +199 -17
- package/server/services/wpImport/plan.js +188 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.8.12] - 2026-10-16
|
|
4
|
+
|
|
5
|
+
- **Import from WordPress asks before changing a home page an earlier import set.** Until now the home page was set by the first import only, and a later import - of another WordPress site, or of the same one after its home page changed - quietly left it alone. Now, when an earlier import set the home page and this export's home page is a different page, the preview's Home page card asks, for example, "Make 'Welcome' the home page instead of 'Home'?". There is no default: Run import stays greyed out, with the reason beside it, until you choose. Yes does what the first import did - the current home page moves to /previous-home (or -2, -3…) as a draft, nothing is deleted, and the new page's old addresses lead to /. No imports the page at its own address and leaves the home page as it is. Running the same export again with the same home page asks nothing. A run started without the answer (from the API, say) is refused with a plain message.
|
|
6
|
+
- **Moving the home page no longer hides the next one.** Moving the home page to another address in the page editor made SEO add a redirect from / to the new address, so any page later put at / was never shown - visitors were sent to the old one. / is now never the source of an automatic redirect, and a published page at / (made there, moved there, or published there) removes any redirect from / - the same way a page moved to any address removes a redirect from that address. A redirect from / that an earlier version added this way is removed when the site starts, if there is a page at /; one you set up yourself is left until a published page is put at / (a draft there does not count, since visitors cannot see it).
|
|
7
|
+
|
|
8
|
+
## [1.8.11] - 2026-10-16
|
|
9
|
+
|
|
10
|
+
- **Import from WordPress sets the home page.** A WordPress export does not say which page was the home page, but it gives each page's address, and the home page's address is the site's own - so that page is found, and only that one (a page merely called "Home" is just a page). The preview's new Home page card says which page WordPress showed at its home address, what this site's home page is now, and what will happen. By default the WordPress home page becomes this site's home page; the page that was there is never deleted or overwritten - it moves to /previous-home as a draft, and the preview and the report say so, with a link to it. Menus that lead to / still do, nothing redirects to the old page, and the WordPress home page's own old address (/home/, say) and its ?page_id= links lead to /. This happens once: run the import again and the home page is updated where it is, left as it is if you edited it here (unless you choose Overwrite), and left alone altogether if you have changed the home page yourself since - the report says so.
|
|
11
|
+
- The posts page cannot be read from the export either, so an empty page called Blog, News, Posts, Articles or Journal (or named like the Blog's address) is offered as a suggestion. Confirm it and no empty page is made: its old address, links and menu items lead to the Blog - or, when posts become pages, it becomes the list of those posts. When WordPress showed its latest posts on the home page, the card says so and, with a Blog switched on, offers to show the latest posts on this site's home page too (off unless you choose it).
|
|
12
|
+
|
|
3
13
|
## [1.8.10] - 2026-10-16
|
|
4
14
|
|
|
5
15
|
- Domma Docs pages now show signed-in visitors their own menus. They were always drawn as for an anonymous visitor and cached as one copy for everybody; they now recognise who is looking, like every other page, and keep one cached copy per set of roles, so a menu item meant for admins is never shown to the public.
|
package/CLAUDE.md
CHANGED
|
@@ -351,6 +351,11 @@ A built-in Tool (`wordpress-import` in `services/tools.js`, permission `import.w
|
|
|
351
351
|
- **Posts go to a Blog by feature, not by name** (`blogTarget()`): a switched-on plugin that ships `blog-posts`,
|
|
352
352
|
with the fields a post needs; comments only when `blog-comments` has the Blog's shape. Otherwise posts become
|
|
353
353
|
pages (under /blog, or /posts when a Blog is on).
|
|
354
|
+
- **"/" is never a redirect source**: `onMoved()` (seo-redirects.js) adds nothing when a page leaves "/" (the page
|
|
355
|
+
editor's move, any `renamePage`), and SEO drops an exact rule from "/" when a PUBLISHED page is created, saved or renamed
|
|
356
|
+
to "/" (even with `redirect: false` or onRename off; a draft there 404s for the public, so the rule stays) - a page wins at its address, as `onMoved` already did for the
|
|
357
|
+
address a page moves to. At start an `auto` rule from "/" is removed if a published page is there (older versions made
|
|
358
|
+
them); a hand-made one stays until a page is put at "/".
|
|
354
359
|
- **Redirects**: path ones go into SEO's store (`seoEngine().addRule`); `/?p=`, `/?page_id=`, `/?attachment_id=`
|
|
355
360
|
are answered by the importer's own `onRequest` hook from `map.json`, because SEO's rules match paths only. That
|
|
356
361
|
hook is registered whatever the Tool switch says (the redirects belong to the migrated site) and re-reads
|
|
@@ -416,6 +421,28 @@ A built-in Tool (`wordpress-import` in `services/tools.js`, permission `import.w
|
|
|
416
421
|
choice; `removed` = an earlier run placed it and it is gone now - not put back; `full` = the footer already has
|
|
417
422
|
`FOOTER_BLOCKS_MAX` (8), which Site Settings also refuses to exceed). A widget that comes out empty is listed, never dropped. `map.json` keeps `{block, hash,
|
|
418
423
|
placed}`; an edited block is "Left as is" unless Overwrite.
|
|
424
|
+
- **The home page** (`front.js`, pure; `plan.home`): a WXR has no options, so the front page is the ONE published page whose
|
|
425
|
+
`<link>` is the home address (`homeKeys()`: channel link / base_blog_url; scheme, www and trailing slash ignored) - never
|
|
426
|
+
by title; two such pages = none. `options.home` (default on) gives it `/`; the first run that does so moves the page at
|
|
427
|
+
`/` to `/previous-home` (`freePath`, so `-2`…) as a draft (`runHome()` in index.js, before the Pages phase) via
|
|
428
|
+
`renamePage(…, {redirect: false, source: 'wordpress-import'})` - `redirect: false` stops SEO's onRename rule (it would
|
|
429
|
+
redirect `/` itself) and menus are NOT relinked (`/` stays `/`). `mapping.items.home` records it; while it exists -
|
|
430
|
+
in ANY source's mapping (`site.homeSetBy`, the latest by `at`; the newer of it and this source's own is `homeRec`) -
|
|
431
|
+
nothing moves again without asking (`claimHome()` is the one place that decides a move). **The question**: when
|
|
432
|
+
`homeRec` exists, "/" has a page, and this export's front page is not the page `homeRec` names (another source, or
|
|
433
|
+
this source's record has another `wpId`), `plan.home.question` = `{title, current, answer}` and nothing moves until
|
|
434
|
+
`options.homeReplace` answers it - no default; `startRun()` refuses an unanswered one with 400 and the screen
|
|
435
|
+
disables Run (`runWhy`). Yes = `claimHome(true)` BEFORE the pages loop (so this source's own page at "/" is planned
|
|
436
|
+
as a `keep` row with `movedAside` at the new address, never over "/"), and `runHome()` moves again despite the
|
|
437
|
+
record; the record it replaces is put back if the run cannot make the new home (`priorHome`). No = the old
|
|
438
|
+
behaviour, the page at its own address, `plan.home.changed` says so. If the new home page is not made, `putHomeBack()` returns the old one to `/`. A
|
|
439
|
+
password-protected front page is not offered (it would arrive as a draft); a posts page an earlier run imported as a
|
|
440
|
+
page is not offered either (a redirect would hide it). A home page changed by hand since is left
|
|
441
|
+
and `plan.home.changed` says so. The front page's slug address and `?page_id=` lead to `/`. The posts page is only a
|
|
442
|
+
suggestion (`suggestPostsPage()`: empty, published, slug in `POSTS_PAGE_SLUGS` or the Blog's base) confirmed by
|
|
443
|
+
`options.postsPage` = its id: with the Blog it is a skip row (`postsPage`) whose address/query/menu items lead to the
|
|
444
|
+
Blog; posts-as-pages, it becomes their index (`postsIndex`, `postsIndexBody()`). No front page: `options.latestPosts`
|
|
445
|
+
(off) makes a `home:latest` page holding `[blog-list]`, through the same claim.
|
|
419
446
|
- **Footer blocks** (`site.json` footer.blocks, Site Settings > Footer): `buildFooterBlocks()` in `renderer.js` renders
|
|
420
447
|
each as `[block template="…" /]` through `parseMarkdown` into `<div class="cms-footer-blocks">` INSIDE
|
|
421
448
|
`#site-footer` - on BOTH render paths (`footerBlocksHtml`). site.js lifts that node out before `$footer.html()` (which
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CODES=[301,302,307,308,410],MAX_RULES=5e3;export function normalisePath(
|
|
1
|
+
export const CODES=[301,302,307,308,410],MAX_RULES=5e3;export function normalisePath(i){let e=String(i??"").trim();if(!e)return"";try{e=decodeURI(e)}catch{}return e=e.split("#")[0].split("?")[0],e.startsWith("/")||(e=`/${e}`),e=e.replace(/\/{2,}/g,"/"),e.length>1&&(e=e.replace(/\/+$/,"")),e.toLowerCase()}const u=i=>String(i).endsWith("/*"),f=i=>/^https?:\/\//i.test(String(i));export function checkRule(i={},e=[]){const t={},l=Number(i.code??301),c=String(i.from??"").trim(),o=u(c),r=o?`${normalisePath(c.slice(0,-2))==="/"?"":normalisePath(c.slice(0,-2))}/*`:normalisePath(c);let n=String(i.to??"").trim();if(CODES.includes(l)||(t.code="Choose 301, 302, 307, 308 or 410."),c?/^https?:\/\//i.test(c)?t.from="The address to redirect is a path on this site, like /old-page.":/^\/(admin|api)(\/|$)/.test(r)?t.from="The admin and the API cannot be redirected.":r==="/*"&&(t.from="That would redirect the whole site."):t.from="Say which address to redirect.",l===410)n="";else if(!n)t.to="Say where it goes.";else if(f(n))try{new URL(n.replace("*","x"))}catch{t.to="Not a web address."}else if(/^[a-z][a-z0-9+.-]*:/i.test(n)||n.startsWith("//"))t.to="A path on this site (/new-page) or an http(s) address.";else{const[a,s]=n.split("?");n=normalisePath(a)+(s?`?${s}`:""),n.includes("*")&&!o&&(t.to='A "*" in the target needs a "/*" rule to fill it.')}if(!t.from&&!t.to&&l!==410&&!f(n)){const a=normalisePath(n.split("?")[0]);!o&&a===r?t.to="It would redirect to itself.":!o&&h(r,a,e)&&(t.to="That makes a loop with another redirect.")}return!t.from&&e.some(a=>a.from===r)&&(t.from=`There is already a redirect from ${r}.`),{errors:t,rule:{from:r,to:n,code:l,note:String(i.note??"").trim().slice(0,200),...i.auto===!0&&{auto:!0}}}}function h(i,e,t){const l=new Set([i]);let c=e;for(let o=0;o<20;o++){if(l.has(c))return!0;l.add(c);const r=matchRedirect(t,c);if(!r||!r.location||f(r.location))return!1;c=normalisePath(r.location.split("?")[0])}return!0}export function matchRedirect(i,e){const[t,l]=String(e??"").split("?"),c=normalisePath(t);if(!c)return null;let o=null,r="";for(const a of i)if(a.from===c){o=a,r="";break}if(!o){let a=-1;for(const s of i){if(!u(s.from))continue;const d=s.from.slice(0,-2);(c===d||c.startsWith(`${d}/`))&&d.length>a&&(a=d.length,o=s,r=c.slice(d.length+1))}}if(!o)return null;if(o.code===410)return{rule:o,location:"",code:410};let n=o.to.includes("*")?o.to.replace("*",r):o.to;return f(n)||(n=n.replace(/\/{2,}/g,"/").replace(/(.)\/$/,"$1")),l&&!n.includes("?")&&(n+=`?${l}`),{rule:o,location:n,code:o.code}}export function onMoved(i,e,t,{now:l=new Date().toISOString(),id:c}={}){const o=normalisePath(e),r=normalisePath(t);if(!o||!r||o===r)return i;if(o==="/")return i.filter(s=>s.from!==r);const n=i.filter(s=>s.from!==r).map(s=>normalisePath(String(s.to).split("?")[0])===o&&!f(s.to)?{...s,to:r}:s),a=n.find(s=>s.from===o);return a?n.map(s=>s===a?{...s,to:r,code:301}:s):[...n,{id:c||`r${Date.now().toString(36)}`,from:o,to:r,code:301,note:"The page moved",auto:!0,hits:0,lastHit:null,at:l}]}export function chains(i){const e=[];for(const t of i){if(t.code===410||f(t.to)||u(t.from))continue;const l=matchRedirect(i,t.to);l&&l.rule!==t&&e.push({rule:t,via:l.rule})}return e}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const KIND_LABEL={page:"Page",post:"Post",product:"Product",custom:"Custom item",collection:"Collection",media:"Media",menu:"Menu",category:"Category",widgets:"Widget area"},KIND_PLURAL={page:"Pages",post:"Posts",product:"Products",custom:"Custom items",collection:"Collections",media:"Media",menu:"Menus",category:"Categories",widgets:"Widgets"},KIND_ICON={page:"file-text",post:"edit-3",product:"shopping-bag",custom:"box",collection:"database",media:"image",menu:"menu",category:"tag",widgets:"layout"},PLACE_TEXT={add:"Goes in the footer, after what is there now",there:"Already in the footer",off:"Not put in the footer (you chose this)",removed:"Not put back in the footer - it was taken out here since the last import",full:"Not put in the footer - it already has 8 blocks; make room in Site Settings \u203A Footer"},TYPE_AS={collection:{text:"Collection",tone:"ok"},pages:{text:"Pages",tone:"info"},skip:{text:"Skipped",tone:"muted"}},PRODUCT_TYPE_LABEL={simple:"Simple",variable:"With options",grouped:"Grouped",external:"External"},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 p=e=>!!(e.builder||e.needs||e.shortcodes?.length),u=e=>[e.builder?`Built with ${e.builder}`:"",e.needs||"",...(e.shortcodes||[]).map(t=>`[${t}]`)].filter(Boolean).join(" ");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 p(e);default:return!0}}export function reportMatches(e,t){return t==="rebuild"?p(e):t==="all"||!t||e.result===t}export function counts(e,t,o,i=""){const n=e.filter(s=>!i||s.kind===i);return Object.fromEntries(t.map(s=>[s.id,n.filter(a=>o(a,s.id)).length]))}export function kindTabs(e){const t=["page","post","product","custom","collection","media","menu","category","widgets"],o={};for(const i of e)o[i.kind]=(o[i.kind]||0)+1;return[{id:"",label:"Everything",count:e.length},...t.filter(i=>o[i]).map(i=>({id:i,label:KIND_PLURAL[i],count:o[i]}))]}export function planRow(e){const t=ACTION[e.action]||ACTION.skip;let o=e.target?e.kind==="menu"?`Menu "${e.target}"`:e.kind==="collection"?`Collection "${e.target}"`:e.kind==="widgets"?`Block "${e.target}"`:e.target:"";e.kind==="widgets"&&e.place&&e.action!=="skip"&&(o=`${o}${o?" \xB7 ":""}${PLACE_TEXT[e.place]||""}`),e.kind==="custom"&&e.as==="collection"&&e.collection&&e.action!=="skip"&&(o=`In the collection "${e.collection}"${e.listAt?`, listed at ${e.listAt}`:""}`);const i=[e.kind==="custom"&&e.postType?`${KIND_LABEL.custom} (${e.postType})`:KIND_LABEL[e.kind]||e.kind];return e.listFor&&i.push("list page"),e.status&&(e.kind==="page"||e.kind==="post"||e.kind==="custom")&&i.push(e.status),e.kind==="collection"&&e.fields&&i.push(`${e.fields} fields`),e.kind==="product"&&(e.productType&&i.push(PRODUCT_TYPE_LABEL[e.productType]||e.productType),e.variants&&i.push(`${e.variants} option${e.variants===1?"":"s"}`),e.action!=="skip"&&e.status&&i.push(e.status==="active"?"on sale":"draft")),e.comments&&i.push(`${e.comments} comment${e.comments===1?"":"s"}`),e.count&&i.push(e.kind==="widgets"?`${e.count} widget${e.count===1?"":"s"}`:`${e.count} item${e.count===1?"":"s"}`),e.kind==="widgets"&&e.widgetTypes?.length&&i.push(e.widgetTypes.join(", ")),{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:o,meta:i.join(" \xB7 "),reason:e.reason||"",rebuild:u(e),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":"",e.kind==="widgets"&&e.placed?"added to the footer":""].filter(Boolean).join(" \xB7 "),reason:[e.reason,...e.notes||[]].filter(Boolean).join(" "),rebuild:u(e)}}export function choiceItems(e,t){const o=[];return t&&o.push({id:"reset",label:"Undo my choice",icon:"rotate-ccw"}),t!=="skip"&&e.action!=="skip"&&e.action!=="keep"&&o.push({id:"skip",label:"Skip this",icon:"x-circle"}),t!=="overwrite"&&e.action==="keep"&&o.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"&&o.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|from the Shop|from the collection)/.test(e.reason||"")&&o.push({id:"import",label:"Import again",icon:"download"}),o}export function applyChoice(e,t,o){const i={...e||{}};return!o||o==="reset"?delete i[t]:i[t]=o,i}export function defaultOptions(e=!1){return{posts:e?"blog":"pages",media:"download",comments:!0,menus:!0,redirects:!0,drafts:!0,products:!0,types:{},listPages:{},choices:{},users:{},userRole:"",invite:!1,footer:{}}}export function cleanOptions(e={},t=!1){const o=defaultOptions(t),i=(n,s,a)=>s.includes(n)?n:a;return{posts:i(e.posts,t?["blog","pages","skip"]:["pages","skip"],o.posts),media:i(e.media,["download","zip","skip"],o.media),comments:e.comments!==!1,menus:e.menus!==!1,redirects:e.redirects!==!1,drafts:e.drafts!==!1,products:e.products!==!1,types:Object.fromEntries(Object.entries(e.types||{}).filter(([n,s])=>f.test(n)&&(s==="pages"||s==="skip"))),listPages:Object.fromEntries(Object.entries(e.listPages||{}).filter(([n,s])=>f.test(n)&&s===!1)),choices:Object.fromEntries(Object.entries(e.choices||{}).filter(([n,s])=>typeof n=="string"&&["skip","overwrite","import"].includes(s))),users:Object.fromEntries(Object.entries(e.users||{}).filter(([n,s])=>g.test(n)&&(s==="create"||s==="skip"))),userRole:typeof e.userRole=="string"&&b.test(e.userRole)?e.userRole:"",invite:e.invite===!0,footer:Object.fromEntries(Object.entries(e.footer||{}).filter(([n,s])=>h.test(n)&&s===!1))}}const h=/^[A-Za-z0-9_-]{1,100}$/;export function withFooterChoice(e,t,o){const i={...e.footer||{}};return o?delete i[t]:i[t]=!1,{...e,footer:i}}export function optionsSnapshot(e){const t=cleanOptions(e,!0),o=Object.keys(t.choices).sort().map(l=>`${l}=${t.choices[l]}`).join(","),i=Object.keys(t.types).sort().map(l=>`${l}=${t.types[l]}`).join(","),n=Object.keys(t.listPages).sort().join(","),s=Object.keys(t.users).sort().map(l=>`${l}=${t.users[l]}`).join(","),a=Object.keys(t.footer).sort().join(",");return[t.posts,t.media,t.comments,t.menus,t.redirects,t.drafts,t.products,o,i,n,s,t.userRole,t.invite,a].join("|")}const f=/^[a-z0-9_-]{1,40}$/;export function withTypeChoice(e,t,o){const i={...e.types||{}};return o==="pages"||o==="skip"?i[t]=o:delete i[t],{...e,types:i}}export function withListPage(e,t,o){const i={...e.listPages||{}};return o?delete i[t]:i[t]=!1,{...e,listPages:i}}export const isDirty=(e,t)=>optionsSnapshot(e)!==optionsSnapshot(defaultOptions(t)),draftKey=e=>e?`wordpress-import.draft.${e}`:"";export function liveDrafts(e,t,o){if(!e||typeof e!="object"||!e.items||typeof e.items!="object")return{items:{},pruned:!1};if(e.owner&&o&&e.owner!==o)return{items:{},pruned:!1};const i={};let n=!1;for(const[s,a]of Object.entries(e.items))t.includes(s)&&a?.options&&a.was===s?i[s]=a:n=!0;return{items:i,pruned:n}}export function withDraft(e,t,o,i){const n={...e&&e.owner===t&&e.items||{}};return i?n[o]=i:delete n[o],{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||{},o=i=>t[i]?t[i].total-t[i].skip:0;return[{id:"page",label:"Pages",value:o("page"),of:t.page?.total||0},{id:"post",label:"Posts",value:o("post"),of:t.post?.total||0},...t.product?[{id:"product",label:"Products",value:o("product"),of:t.product.total}]:[],...t.custom?[{id:"custom",label:"Custom items",value:o("custom"),of:t.custom.total}]:[],{id:"media",label:"Media",value:o("media"),of:t.media?.total||0},{id:"menu",label:"Menus",value:o("menu"),of:t.menu?.total||0},...e?.people?.rows?.length?[{id:"people",label:"New accounts",value:e.people.counts?.create||0,of:0}]:[],...t.widgets?[{id:"widgets",label:"Widget areas",value:o("widgets"),of:t.widgets.total}]:[],{id:"comments",label:"Comments",value:e?.summary?.comments||0,of:0},{id:"redirects",label:"Redirects",value:e?.summary?.redirects||0,of:0}].map(i=>({...i,sub:i.of&&i.of!==i.value?`of ${i.of}`:""}))}const g=/^author:(\d{1,12}|login-[\w.-]{1,60})$/,b=/^[a-z0-9][a-z0-9_-]{0,59}$/i;export const PERSON={create:{text:"New account",tone:"ok"},match:{text:"Matched",tone:"info"},linked:{text:"Linked before",tone:"info"},same:{text:"Same email",tone:"muted"},skip:{text:"No account",tone:"muted"}};export function creditText(e={}){const t=(o,i,n)=>e[o]?`${e[o]} ${e[o]===1?i:n}`:"";return[t("post","post","posts"),t("page","page","pages"),t("product","product","products"),t("custom","item","items")].filter(Boolean).join(", ")||"nothing in this import"}export function personRow(e){const t=PERSON[e.action]||PERSON.skip,o=e.problem==="email";return{key:e.key,name:e.name||"Author",meta:[e.email||(o?"no usable email":""),creditText(e.items)].filter(Boolean).join(" \xB7 "),reason:e.reason||"",pill:o?"No email":t.text,pillClass:`is-${o?"warn":t.tone}${e.choice?" is-chosen":""}`,choosable:!!e.choosable,segCreate:e.action==="create"?"is-on":"",segSkip:e.action==="skip"?"is-on":""}}export function chooseAllPeople(e,t){const o={};for(const i of e?.rows||[])i.choosable&&(o[i.key]=t);return o}export function choosePerson(e,t,o){const i={...e||{}},n=t.total?"create":"skip";return!o||o==="reset"||o===n?delete i[t.key]:i[t.key]=o,i}export function personMenuItems(e){const t=[];return e.choosable&&e.action!=="create"&&t.push({id:"create",label:"Make a new account",icon:"user-plus"}),e.choosable&&e.action!=="skip"&&t.push({id:"skip",label:"Do not make an account",icon:"user-x"}),e.choice&&t.push({id:"reset",label:"Undo my choice",icon:"rotate-ccw"}),e.email&&e.problem!=="email"&&t.push({id:"copy",label:"Copy the email address",icon:"copy"}),t.length||t.push({id:"none",label:"Nothing to choose for them",icon:"info",disabled:!0}),t}export function peopleSummary(e){const t=e?.counts||{};if(!e?.rows?.length)return{text:"This export names no authors.",tone:"info"};const o=[];t.create&&o.push(`${t.create} new account${t.create===1?"":"s"}`),t.match+t.linked&&o.push(`${t.match+t.linked} matched to ${t.match+t.linked===1?"a user":"users"} here`),t.skip&&o.push(`${t.skip} without an account`);let i=`${e.rows.length} author${e.rows.length===1?"":"s"}: ${o.join(", ")||"nothing to do"}.`;return t.create&&(i+=" New accounts have no password - nobody can sign in to one until a password is set."),!e.canCreate&&e.why&&(i+=` ${e.why}`),{text:i,tone:t.problems||!e.canCreate?"warn":"info"}}export function inviteNote(e){return e?.canCreate?e.mailReady?e.counts?.create?"Sent once the import has finished: an invitation saying an account has been made for them, with a link to set their password that works for 7 days.":"Nobody new to email.":"No mail server is set up (Settings \u203A Email), so this cannot be sent. After the import, use Users \u203A \u22EE \u203A Copy a reset link instead.":""}export function reportPersonRow(e){const t={created:{text:"Account made",tone:"ok"},matched:{text:"Matched",tone:"info"},linked:{text:"Linked before",tone:"info"},same:{text:"Same email",tone:"muted"},skipped:{text:"No account",tone:"muted"},failed:{text:"Failed",tone:"bad"}},o=t[e.result]||t.skipped,i=[creditText(e.items)];return e.result==="created"&&i.push(e.invited?"invited by email":e.inviteFailed?"the invitation was not sent":"no password set yet"),{key:e.key,name:e.name||"Author",meta:i.join(" \xB7 "),reason:e.reason||"",pill:o.text,pillClass:`is-${o.tone}`,userId:e.userId||""}}export function historyRow(e,t=o=>o){const o=e.summary||{},i=Object.values(o.kinds||{}).reduce((a,l)=>a+(l.created||0),0),n=Object.values(o.kinds||{}).reduce((a,l)=>a+(l.updated||0),0),s=[];return i&&s.push(`${i} made`),o.people?.created&&s.push(`${o.people.created} account${o.people.created===1?"":"s"}`),n&&s.push(`${n} updated`),o.redirects?.created&&s.push(`${o.redirects.created} redirect${o.redirects.created===1?"":"s"}`),o.rebuild&&s.push(`${o.rebuild} to rebuild`),o.failed&&s.push(`${o.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=o=>o){const o=e.counts||{},i=[o.page&&`${o.page} pages`,o.post&&`${o.post} posts`,o.product&&`${o.product} products`,o.attachment&&`${o.attachment} media`,e.widgets&&`${e.widgets.widgets} widget${e.widgets.widgets===1?"":"s"}`].filter(Boolean);return{id:e.id,title:e.siteTitle||e.fileName||"WordPress export",meta:[e.fileName,t(e.at),i.join(", ")].filter(Boolean).join(" \xB7 "),pill:e.uploads?"Uploads zip added":e.widgets?"Widgets added":"Waiting",pillClass:e.uploads||e.widgets?"is-ok":"is-muted"}}export function productSummary(e){const t=e?.summary?.products;if(!t?.total)return null;const o=t.shop||e.shop||{},i=e.options?.products!==!1,n=Object.entries(t.types||{}).map(([d,m])=>`${m} ${(PRODUCT_TYPE_LABEL[d]||d).toLowerCase()}`).join(", "),s=e.summary.counts?.product||{},a=[{label:"In the export",value:`${t.total}${n?` (${n})`:""}`}];o.available&&i&&(a.push({label:"On sale in the Shop",value:String(t.onSale||0)}),a.push({label:"As drafts",value:String(t.drafts||0)}),s.keep&&a.push({label:"Left as is",value:String(s.keep)}),a.push({label:"Skipped",value:String(s.skip||0)})),t.rebuild&&a.push({label:"Need rebuilding",value:String(t.rebuild)});let l,r="info";return o.available?i?l=`Products go to the Shop at ${o.basePath||"/shop"}.`:l='Products are not being imported - switch on "WooCommerce products" above to bring them in.':(l=o.reason||"Switch on the Shop to bring these in.",r="warn"),{note:l,tone:r,rows:a,notes:Array.isArray(t.notes)?t.notes:[]}}const c=(e,t,o=`${t}s`)=>`${e} ${e===1?t:o}`;export function customTypeRows(e){return(e?.summary?.customTypes||[]).map(t=>{const o=TYPE_AS[t.as]?t.as:"collection",i=TYPE_AS[o],n=t.rewrite?`was at /${t.rewrite}/\u2026`:"its old addresses are not in the export";let s;if(o==="skip")s="Nothing - left out.";else if(o==="pages")s=`${c(t.importing||0,"page")} under ${t.prefix}${t.drafts?` (${t.drafts} as draft${t.drafts===1?"":"s"})`:""}.`;else{const a=t.collection||{},l=a.action==="skip"?`The collection "${a.slug}" was deleted here - choose Import again on it below.`:`${a.action==="update"?"The collection":"A new collection"} "${a.slug}" with ${c(t.fields?.length||0,"field")}: ${c(t.importing||0,"entry","entries")}${t.drafts?` (${t.drafts} draft${t.drafts===1?"":"s"}, not shown on the site)`:""}.`,r=t.listPage?t.listAt?` A list page at ${t.listAt}${t.listAction==="keep"?" (edited here - left as it is)":""}; the old addresses lead there.`:"":" No list page - the old addresses are not redirected.";s=`${l}${r}`}return{type:t.type,label:t.label||t.type,meta:[c(t.count||0,"item"),`"${t.type}"`,n].join(" \xB7 "),samples:(t.samples||[]).length?`For example: ${t.samples.join(", ")}`:"",creates:s,pill:i.text,pillClass:`is-${i.tone}`,as:o,listOn:o==="collection"&&t.listPage!==!1,canList:o==="collection",listLabel:`List page at ${t.prefix||`/${t.type}`}`,segCollection:o==="collection"?"is-on":"",segPages:o==="pages"?"is-on":"",segSkip:o==="skip"?"is-on":""}})}export function internalTypeRows(e){return(e?.summary?.internalTypes||[]).map(t=>({type:t.type,text:`${t.type} (${t.count}) - ${t.reason}`}))}export function typeMenuItems(e){if(!e)return[];const t=[];return e.as!=="collection"&&t.push({id:"collection",label:"Import as a collection",icon:"database"}),e.as!=="pages"&&t.push({id:"pages",label:"Import as pages",icon:"file-text"}),e.as!=="skip"&&t.push({id:"skip",label:"Leave this type out",icon:"x-circle"}),e.as==="collection"&&t.push(e.listOn?{id:"nolist",label:"No list page",icon:"eye-off"}:{id:"list",label:"Make a list page",icon:"list"}),t.push({id:"show",label:"Show its items",icon:"filter"}),t}export function widgetAreaRows(e){return(e?.summary?.widgets?.areas||[]).map(t=>{const o=ACTION[t.action]||ACTION.skip,i=t.action==="skip"?"Not imported.":`${t.action==="update"?"Updates the block":t.action==="keep"?"The block (edited here - left as it is)":"A new block"} "${t.block}"${t.coming<t.count?` with ${c(t.coming,"widget")}`:""}.`;return{area:t.id,label:t.label||t.id,meta:[c(t.count||0,"widget"),`"${t.id}"`,(t.types||[]).join(", ")].filter(Boolean).join(" \xB7 "),creates:i,placeText:t.footer?PLACE_TEXT[t.place]||"":t.action==="skip"?"":"A sidebar - a block only; put it on a page with [block].",rebuild:(t.rebuild||[]).length?`Needs rebuilding: ${t.rebuild.join("; ")}`:"",pill:o.text,pillClass:`is-${o.tone}`,canPlace:!!t.footer&&t.action!=="skip"&&t.place!=="there"&&t.place!=="removed",placeOn:t.place==="add"}})}export function widgetsFileText(e,t=0){const o=e?.widgets;return o?`${o.fileName} - ${c(o.areas||0,"widget area")}, ${c(o.widgets||0,"widget")}.`:`Optional: the widgets, as the .wie file the free "Widget Importer & Exporter" WordPress plugin exports${t?` (up to ${Math.max(1,Math.round(t/1048576))} MB)`:""}.`}
|
|
1
|
+
export const KIND_LABEL={page:"Page",post:"Post",product:"Product",custom:"Custom item",collection:"Collection",media:"Media",menu:"Menu",category:"Category",widgets:"Widget area"},KIND_PLURAL={page:"Pages",post:"Posts",product:"Products",custom:"Custom items",collection:"Collections",media:"Media",menu:"Menus",category:"Categories",widgets:"Widgets"},KIND_ICON={page:"file-text",post:"edit-3",product:"shopping-bag",custom:"box",collection:"database",media:"image",menu:"menu",category:"tag",widgets:"layout"},PLACE_TEXT={add:"Goes in the footer, after what is there now",there:"Already in the footer",off:"Not put in the footer (you chose this)",removed:"Not put back in the footer - it was taken out here since the last import",full:"Not put in the footer - it already has 8 blocks; make room in Site Settings \u203A Footer"},TYPE_AS={collection:{text:"Collection",tone:"ok"},pages:{text:"Pages",tone:"info"},skip:{text:"Skipped",tone:"muted"}},PRODUCT_TYPE_LABEL={simple:"Simple",variable:"With options",grouped:"Grouped",external:"External"},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 h=e=>!!(e.builder||e.needs||e.shortcodes?.length),m=e=>[e.builder?`Built with ${e.builder}`:"",e.needs||"",...(e.shortcodes||[]).map(t=>`[${t}]`)].filter(Boolean).join(" ");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 h(e);default:return!0}}export function reportMatches(e,t){return t==="rebuild"?h(e):t==="all"||!t||e.result===t}export function counts(e,t,o,s=""){const n=e.filter(i=>!s||i.kind===s);return Object.fromEntries(t.map(i=>[i.id,n.filter(a=>o(a,i.id)).length]))}export function kindTabs(e){const t=["page","post","product","custom","collection","media","menu","category","widgets"],o={};for(const s of e)o[s.kind]=(o[s.kind]||0)+1;return[{id:"",label:"Everything",count:e.length},...t.filter(s=>o[s]).map(s=>({id:s,label:KIND_PLURAL[s],count:o[s]}))]}export function planRow(e){const t=ACTION[e.action]||ACTION.skip;let o=e.target?e.kind==="menu"?`Menu "${e.target}"`:e.kind==="collection"?`Collection "${e.target}"`:e.kind==="widgets"?`Block "${e.target}"`:e.target:"";e.kind==="widgets"&&e.place&&e.action!=="skip"&&(o=`${o}${o?" \xB7 ":""}${PLACE_TEXT[e.place]||""}`),e.kind==="custom"&&e.as==="collection"&&e.collection&&e.action!=="skip"&&(o=`In the collection "${e.collection}"${e.listAt?`, listed at ${e.listAt}`:""}`);const s=[e.kind==="custom"&&e.postType?`${KIND_LABEL.custom} (${e.postType})`:KIND_LABEL[e.kind]||e.kind];return e.listFor&&s.push("list page"),e.status&&(e.kind==="page"||e.kind==="post"||e.kind==="custom")&&s.push(e.status),e.kind==="collection"&&e.fields&&s.push(`${e.fields} fields`),e.kind==="product"&&(e.productType&&s.push(PRODUCT_TYPE_LABEL[e.productType]||e.productType),e.variants&&s.push(`${e.variants} option${e.variants===1?"":"s"}`),e.action!=="skip"&&e.status&&s.push(e.status==="active"?"on sale":"draft")),e.comments&&s.push(`${e.comments} comment${e.comments===1?"":"s"}`),e.count&&s.push(e.kind==="widgets"?`${e.count} widget${e.count===1?"":"s"}`:`${e.count} item${e.count===1?"":"s"}`),e.kind==="widgets"&&e.widgetTypes?.length&&s.push(e.widgetTypes.join(", ")),{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:o,meta:s.join(" \xB7 "),reason:e.reason||"",rebuild:m(e),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":"",e.kind==="widgets"&&e.placed?"added to the footer":""].filter(Boolean).join(" \xB7 "),reason:[e.reason,...e.notes||[]].filter(Boolean).join(" "),rebuild:m(e)}}export function choiceItems(e,t){const o=[];return t&&o.push({id:"reset",label:"Undo my choice",icon:"rotate-ccw"}),t!=="skip"&&e.action!=="skip"&&e.action!=="keep"&&o.push({id:"skip",label:"Skip this",icon:"x-circle"}),t!=="overwrite"&&e.action==="keep"&&o.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"&&o.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|from the Shop|from the collection)/.test(e.reason||"")&&o.push({id:"import",label:"Import again",icon:"download"}),o}export function applyChoice(e,t,o){const s={...e||{}};return!o||o==="reset"?delete s[t]:s[t]=o,s}export function defaultOptions(e=!1){return{posts:e?"blog":"pages",media:"download",comments:!0,menus:!0,redirects:!0,drafts:!0,products:!0,types:{},listPages:{},choices:{},users:{},userRole:"",invite:!1,footer:{},home:!0,postsPage:0,latestPosts:!1,homeReplace:null}}export function cleanOptions(e={},t=!1){const o=defaultOptions(t),s=(n,i,a)=>i.includes(n)?n:a;return{posts:s(e.posts,t?["blog","pages","skip"]:["pages","skip"],o.posts),media:s(e.media,["download","zip","skip"],o.media),comments:e.comments!==!1,menus:e.menus!==!1,redirects:e.redirects!==!1,drafts:e.drafts!==!1,products:e.products!==!1,types:Object.fromEntries(Object.entries(e.types||{}).filter(([n,i])=>g.test(n)&&(i==="pages"||i==="skip"))),listPages:Object.fromEntries(Object.entries(e.listPages||{}).filter(([n,i])=>g.test(n)&&i===!1)),choices:Object.fromEntries(Object.entries(e.choices||{}).filter(([n,i])=>typeof n=="string"&&["skip","overwrite","import"].includes(i))),users:Object.fromEntries(Object.entries(e.users||{}).filter(([n,i])=>b.test(n)&&(i==="create"||i==="skip"))),userRole:typeof e.userRole=="string"&&$.test(e.userRole)?e.userRole:"",invite:e.invite===!0,footer:Object.fromEntries(Object.entries(e.footer||{}).filter(([n,i])=>w.test(n)&&i===!1)),home:e.home!==!1,postsPage:Number.isInteger(e.postsPage)&&e.postsPage>0?e.postsPage:0,latestPosts:e.latestPosts===!0,homeReplace:typeof e.homeReplace=="boolean"?e.homeReplace:null}}const w=/^[A-Za-z0-9_-]{1,100}$/;export function withFooterChoice(e,t,o){const s={...e.footer||{}};return o?delete s[t]:s[t]=!1,{...e,footer:s}}export function optionsSnapshot(e){const t=cleanOptions(e,!0),o=Object.keys(t.choices).sort().map(l=>`${l}=${t.choices[l]}`).join(","),s=Object.keys(t.types).sort().map(l=>`${l}=${t.types[l]}`).join(","),n=Object.keys(t.listPages).sort().join(","),i=Object.keys(t.users).sort().map(l=>`${l}=${t.users[l]}`).join(","),a=Object.keys(t.footer).sort().join(",");return[t.posts,t.media,t.comments,t.menus,t.redirects,t.drafts,t.products,o,s,n,i,t.userRole,t.invite,a,t.home,t.postsPage,t.latestPosts,t.homeReplace].join("|")}const g=/^[a-z0-9_-]{1,40}$/;export function withTypeChoice(e,t,o){const s={...e.types||{}};return o==="pages"||o==="skip"?s[t]=o:delete s[t],{...e,types:s}}export function withListPage(e,t,o){const s={...e.listPages||{}};return o?delete s[t]:s[t]=!1,{...e,listPages:s}}export const isDirty=(e,t)=>optionsSnapshot(e)!==optionsSnapshot(defaultOptions(t)),draftKey=e=>e?`wordpress-import.draft.${e}`:"";export function liveDrafts(e,t,o){if(!e||typeof e!="object"||!e.items||typeof e.items!="object")return{items:{},pruned:!1};if(e.owner&&o&&e.owner!==o)return{items:{},pruned:!1};const s={};let n=!1;for(const[i,a]of Object.entries(e.items))t.includes(i)&&a?.options&&a.was===i?s[i]=a:n=!0;return{items:s,pruned:n}}export function withDraft(e,t,o,s){const n={...e&&e.owner===t&&e.items||{}};return s?n[o]=s:delete n[o],{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||{},o=s=>t[s]?t[s].total-t[s].skip:0;return[{id:"page",label:"Pages",value:o("page"),of:t.page?.total||0},{id:"post",label:"Posts",value:o("post"),of:t.post?.total||0},...t.product?[{id:"product",label:"Products",value:o("product"),of:t.product.total}]:[],...t.custom?[{id:"custom",label:"Custom items",value:o("custom"),of:t.custom.total}]:[],{id:"media",label:"Media",value:o("media"),of:t.media?.total||0},{id:"menu",label:"Menus",value:o("menu"),of:t.menu?.total||0},...e?.people?.rows?.length?[{id:"people",label:"New accounts",value:e.people.counts?.create||0,of:0}]:[],...t.widgets?[{id:"widgets",label:"Widget areas",value:o("widgets"),of:t.widgets.total}]:[],{id:"comments",label:"Comments",value:e?.summary?.comments||0,of:0},{id:"redirects",label:"Redirects",value:e?.summary?.redirects||0,of:0}].map(s=>({...s,sub:s.of&&s.of!==s.value?`of ${s.of}`:""}))}const b=/^author:(\d{1,12}|login-[\w.-]{1,60})$/,$=/^[a-z0-9][a-z0-9_-]{0,59}$/i;export const PERSON={create:{text:"New account",tone:"ok"},match:{text:"Matched",tone:"info"},linked:{text:"Linked before",tone:"info"},same:{text:"Same email",tone:"muted"},skip:{text:"No account",tone:"muted"}};export function creditText(e={}){const t=(o,s,n)=>e[o]?`${e[o]} ${e[o]===1?s:n}`:"";return[t("post","post","posts"),t("page","page","pages"),t("product","product","products"),t("custom","item","items")].filter(Boolean).join(", ")||"nothing in this import"}export function personRow(e){const t=PERSON[e.action]||PERSON.skip,o=e.problem==="email";return{key:e.key,name:e.name||"Author",meta:[e.email||(o?"no usable email":""),creditText(e.items)].filter(Boolean).join(" \xB7 "),reason:e.reason||"",pill:o?"No email":t.text,pillClass:`is-${o?"warn":t.tone}${e.choice?" is-chosen":""}`,choosable:!!e.choosable,segCreate:e.action==="create"?"is-on":"",segSkip:e.action==="skip"?"is-on":""}}export function chooseAllPeople(e,t){const o={};for(const s of e?.rows||[])s.choosable&&(o[s.key]=t);return o}export function choosePerson(e,t,o){const s={...e||{}},n=t.total?"create":"skip";return!o||o==="reset"||o===n?delete s[t.key]:s[t.key]=o,s}export function personMenuItems(e){const t=[];return e.choosable&&e.action!=="create"&&t.push({id:"create",label:"Make a new account",icon:"user-plus"}),e.choosable&&e.action!=="skip"&&t.push({id:"skip",label:"Do not make an account",icon:"user-x"}),e.choice&&t.push({id:"reset",label:"Undo my choice",icon:"rotate-ccw"}),e.email&&e.problem!=="email"&&t.push({id:"copy",label:"Copy the email address",icon:"copy"}),t.length||t.push({id:"none",label:"Nothing to choose for them",icon:"info",disabled:!0}),t}export function peopleSummary(e){const t=e?.counts||{};if(!e?.rows?.length)return{text:"This export names no authors.",tone:"info"};const o=[];t.create&&o.push(`${t.create} new account${t.create===1?"":"s"}`),t.match+t.linked&&o.push(`${t.match+t.linked} matched to ${t.match+t.linked===1?"a user":"users"} here`),t.skip&&o.push(`${t.skip} without an account`);let s=`${e.rows.length} author${e.rows.length===1?"":"s"}: ${o.join(", ")||"nothing to do"}.`;return t.create&&(s+=" New accounts have no password - nobody can sign in to one until a password is set."),!e.canCreate&&e.why&&(s+=` ${e.why}`),{text:s,tone:t.problems||!e.canCreate?"warn":"info"}}export function inviteNote(e){return e?.canCreate?e.mailReady?e.counts?.create?"Sent once the import has finished: an invitation saying an account has been made for them, with a link to set their password that works for 7 days.":"Nobody new to email.":"No mail server is set up (Settings \u203A Email), so this cannot be sent. After the import, use Users \u203A \u22EE \u203A Copy a reset link instead.":""}export function reportPersonRow(e){const t={created:{text:"Account made",tone:"ok"},matched:{text:"Matched",tone:"info"},linked:{text:"Linked before",tone:"info"},same:{text:"Same email",tone:"muted"},skipped:{text:"No account",tone:"muted"},failed:{text:"Failed",tone:"bad"}},o=t[e.result]||t.skipped,s=[creditText(e.items)];return e.result==="created"&&s.push(e.invited?"invited by email":e.inviteFailed?"the invitation was not sent":"no password set yet"),{key:e.key,name:e.name||"Author",meta:s.join(" \xB7 "),reason:e.reason||"",pill:o.text,pillClass:`is-${o.tone}`,userId:e.userId||""}}export function historyRow(e,t=o=>o){const o=e.summary||{},s=Object.values(o.kinds||{}).reduce((a,l)=>a+(l.created||0),0),n=Object.values(o.kinds||{}).reduce((a,l)=>a+(l.updated||0),0),i=[];return s&&i.push(`${s} made`),o.people?.created&&i.push(`${o.people.created} account${o.people.created===1?"":"s"}`),n&&i.push(`${n} updated`),o.redirects?.created&&i.push(`${o.redirects.created} redirect${o.redirects.created===1?"":"s"}`),o.rebuild&&i.push(`${o.rebuild} to rebuild`),o.failed&&i.push(`${o.failed} failed`),e.status==="failed"&&i.splice(0,i.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:i.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=o=>o){const o=e.counts||{},s=[o.page&&`${o.page} pages`,o.post&&`${o.post} posts`,o.product&&`${o.product} products`,o.attachment&&`${o.attachment} media`,e.widgets&&`${e.widgets.widgets} widget${e.widgets.widgets===1?"":"s"}`].filter(Boolean);return{id:e.id,title:e.siteTitle||e.fileName||"WordPress export",meta:[e.fileName,t(e.at),s.join(", ")].filter(Boolean).join(" \xB7 "),pill:e.uploads?"Uploads zip added":e.widgets?"Widgets added":"Waiting",pillClass:e.uploads||e.widgets?"is-ok":"is-muted"}}export function productSummary(e){const t=e?.summary?.products;if(!t?.total)return null;const o=t.shop||e.shop||{},s=e.options?.products!==!1,n=Object.entries(t.types||{}).map(([u,p])=>`${p} ${(PRODUCT_TYPE_LABEL[u]||u).toLowerCase()}`).join(", "),i=e.summary.counts?.product||{},a=[{label:"In the export",value:`${t.total}${n?` (${n})`:""}`}];o.available&&s&&(a.push({label:"On sale in the Shop",value:String(t.onSale||0)}),a.push({label:"As drafts",value:String(t.drafts||0)}),i.keep&&a.push({label:"Left as is",value:String(i.keep)}),a.push({label:"Skipped",value:String(i.skip||0)})),t.rebuild&&a.push({label:"Need rebuilding",value:String(t.rebuild)});let l,r="info";return o.available?s?l=`Products go to the Shop at ${o.basePath||"/shop"}.`:l='Products are not being imported - switch on "WooCommerce products" above to bring them in.':(l=o.reason||"Switch on the Shop to bring these in.",r="warn"),{note:l,tone:r,rows:a,notes:Array.isArray(t.notes)?t.notes:[]}}const d=(e,t,o=`${t}s`)=>`${e} ${e===1?t:o}`;export function customTypeRows(e){return(e?.summary?.customTypes||[]).map(t=>{const o=TYPE_AS[t.as]?t.as:"collection",s=TYPE_AS[o],n=t.rewrite?`was at /${t.rewrite}/\u2026`:"its old addresses are not in the export";let i;if(o==="skip")i="Nothing - left out.";else if(o==="pages")i=`${d(t.importing||0,"page")} under ${t.prefix}${t.drafts?` (${t.drafts} as draft${t.drafts===1?"":"s"})`:""}.`;else{const a=t.collection||{},l=a.action==="skip"?`The collection "${a.slug}" was deleted here - choose Import again on it below.`:`${a.action==="update"?"The collection":"A new collection"} "${a.slug}" with ${d(t.fields?.length||0,"field")}: ${d(t.importing||0,"entry","entries")}${t.drafts?` (${t.drafts} draft${t.drafts===1?"":"s"}, not shown on the site)`:""}.`,r=t.listPage?t.listAt?` A list page at ${t.listAt}${t.listAction==="keep"?" (edited here - left as it is)":""}; the old addresses lead there.`:"":" No list page - the old addresses are not redirected.";i=`${l}${r}`}return{type:t.type,label:t.label||t.type,meta:[d(t.count||0,"item"),`"${t.type}"`,n].join(" \xB7 "),samples:(t.samples||[]).length?`For example: ${t.samples.join(", ")}`:"",creates:i,pill:s.text,pillClass:`is-${s.tone}`,as:o,listOn:o==="collection"&&t.listPage!==!1,canList:o==="collection",listLabel:`List page at ${t.prefix||`/${t.type}`}`,segCollection:o==="collection"?"is-on":"",segPages:o==="pages"?"is-on":"",segSkip:o==="skip"?"is-on":""}})}export function internalTypeRows(e){return(e?.summary?.internalTypes||[]).map(t=>({type:t.type,text:`${t.type} (${t.count}) - ${t.reason}`}))}export function typeMenuItems(e){if(!e)return[];const t=[];return e.as!=="collection"&&t.push({id:"collection",label:"Import as a collection",icon:"database"}),e.as!=="pages"&&t.push({id:"pages",label:"Import as pages",icon:"file-text"}),e.as!=="skip"&&t.push({id:"skip",label:"Leave this type out",icon:"x-circle"}),e.as==="collection"&&t.push(e.listOn?{id:"nolist",label:"No list page",icon:"eye-off"}:{id:"list",label:"Make a list page",icon:"list"}),t.push({id:"show",label:"Show its items",icon:"filter"}),t}export function widgetAreaRows(e){return(e?.summary?.widgets?.areas||[]).map(t=>{const o=ACTION[t.action]||ACTION.skip,s=t.action==="skip"?"Not imported.":`${t.action==="update"?"Updates the block":t.action==="keep"?"The block (edited here - left as it is)":"A new block"} "${t.block}"${t.coming<t.count?` with ${d(t.coming,"widget")}`:""}.`;return{area:t.id,label:t.label||t.id,meta:[d(t.count||0,"widget"),`"${t.id}"`,(t.types||[]).join(", ")].filter(Boolean).join(" \xB7 "),creates:s,placeText:t.footer?PLACE_TEXT[t.place]||"":t.action==="skip"?"":"A sidebar - a block only; put it on a page with [block].",rebuild:(t.rebuild||[]).length?`Needs rebuilding: ${t.rebuild.join("; ")}`:"",pill:o.text,pillClass:`is-${o.tone}`,canPlace:!!t.footer&&t.action!=="skip"&&t.place!=="there"&&t.place!=="removed",placeOn:t.place==="add"}})}export function widgetsFileText(e,t=0){const o=e?.widgets;return o?`${o.fileName} - ${d(o.areas||0,"widget area")}, ${d(o.widgets||0,"widget")}.`:`Optional: the widgets, as the .wie file the free "Widget Importer & Exporter" WordPress plugin exports${t?` (up to ${Math.max(1,Math.round(t/1048576))} MB)`:""}.`}const c=e=>`"${String(e||"").trim()||"Untitled"}"`;export function homeCard(e){const t=e?.home;if(!t)return null;const o=e.options||{},s=[];let n;t.how==="page"&&t.page?n=`WordPress's home page was the page ${c(t.page.title)}${t.page.oldUrl?` (${t.page.oldUrl})`:""}.`:t.how==="unclear"?n=`${t.matches} pages had the home page's address in WordPress, so it cannot be told which one was the home page - none of them is made this site's home page.`:n="WordPress showed its latest posts on the home page (no page was set as the home page).";const i=t.now?`This site's home page now: ${c(t.now.title)}.`:"This site has no home page now.";let a="",l="info";const r=t.question,u=r?`Make ${c(r.title)} the home page instead of ${c(r.current||"the page at /")}?`:"";r?r.answer===!0&&t.move?(a=`${c(r.title)} becomes the home page. ${c(r.current||"The page at /")} moves to ${t.move.to} as a draft - nothing is deleted.`,l="warn"):r.answer===!1&&(a=`${c(r.title)} is imported as an ordinary page${t.page?.target?` at ${t.page.target}`:""} - this site's home page stays as it is.`):t.done?.source?a=`An import of another WordPress site (${t.done.source}) set this site's home page - it is not changed.`:t.done?(a=t.done.how==="latest"?"An earlier import put the latest posts on the home page - it is not moved again.":"An earlier import made it this site's home page - it is not moved again.",t.done.previous&&(a+=` The home page from before is at ${t.done.previous}.`)):t.move?(a=`${t.how==="page"?c(t.page?.title):"A page showing the latest Blog posts"} becomes the home page. ${t.now?c(t.now.title):"The page at /"} moves to ${t.move.to} as a draft - nothing is deleted.`,l="warn"):t.page?.isHome||t.latest?.on?a=`${t.how==="page"?c(t.page?.title):"A page showing the latest Blog posts"} becomes the home page.`:t.how==="page"&&t.page?a=o.home===!1?`It is imported as an ordinary page${t.page.target?` at ${t.page.target}`:""} - this site's home page stays as it is.`:"":t.how==="latest"&&(a=t.latest?.offered?"This site's home page stays as it is unless you choose to show the latest posts on it.":"This site's home page stays as it is."),t.changed&&!t.done?.source&&!r&&(s.push(t.changed),l="warn");const p=t.postsPage;let f="";return p&&(f=p.confirmed?`${c(p.title)} was WordPress's posts page: it is not made, and its old address (and links and menus that pointed to it) lead to ${p.to}.`:`${c(p.title)} has nothing in it and is called like a blog - it was probably WordPress's posts page. If it was, it is not needed here: its address can lead to ${p.to} instead.`),{wp:n,now:i,after:a,tone:l,notes:s,frontSwitch:t.how==="page"&&!!t.page&&!t.done,frontLabel:"Make it this site's home page",latestSwitch:!!t.latest?.offered&&!t.done,postsSwitch:!!p,postsText:f,postsLabel:"It was the posts page - lead its address to the posts",postsId:p?.wpId||0,editNow:t.move&&t.now?"#/pages/edit/":"",question:u,answer:r&&typeof r.answer=="boolean"?r.answer:null}}
|
|
@@ -156,6 +156,14 @@
|
|
|
156
156
|
descriptions carry over. Shortcodes and page-builder layouts this site has no equivalent for are
|
|
157
157
|
listed as <em>needs rebuilding</em>. Run it again later and it updates what it made, leaving alone
|
|
158
158
|
anything you have edited here since unless you choose Overwrite. Each run's report is kept.</p>
|
|
159
|
+
<p>The page WordPress showed as its home page becomes this site's home page (switch that off in the
|
|
160
|
+
preview's Home page card). The page this site had at <code>/</code> is never deleted: it moves to
|
|
161
|
+
<code>/previous-home</code> as a draft, menus that lead to <code>/</code> keep doing so, and the old
|
|
162
|
+
home page's WordPress address leads to <code>/</code>. That happens once - a later run updates the
|
|
163
|
+
home page where it is, and leaves it alone if you changed it. An empty page called Blog, News or
|
|
164
|
+
similar is offered as WordPress's posts page: confirm it and its address leads to the posts instead
|
|
165
|
+
of an empty page being made. When WordPress showed its latest posts on the home page, you can choose
|
|
166
|
+
to do the same here.</p>
|
|
159
167
|
|
|
160
168
|
<h3>Notifications</h3>
|
|
161
169
|
<p>The bell in the admin, and <strong>System > Notifications</strong>. Opening the screen marks
|
|
@@ -51,6 +51,7 @@
|
|
|
51
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
52
|
<button type="button" class="btn btn-sm btn-outline" data-on-click="discard">Discard</button>
|
|
53
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
|
+
<small class="wpx-note wpx-run-why" hidden data-bind-hidden="!runWhy.value" data-bind-text="runWhy.value"></small>
|
|
54
55
|
</div>
|
|
55
56
|
</div>
|
|
56
57
|
<p class="wpx-alert is-dirty" hidden data-bind-hidden="!dirty.value">
|
|
@@ -130,6 +131,28 @@
|
|
|
130
131
|
<div class="wpx-note-list" data-each="notes.value key=text"></div>
|
|
131
132
|
</div>
|
|
132
133
|
|
|
134
|
+
<div class="wpx-card wpx-home" hidden data-bind-hidden="!hasHome.value">
|
|
135
|
+
<div class="wpx-card-title"><span data-icon="home" data-icon-size="16"></span> Home page
|
|
136
|
+
<span data-help-title="The home page" data-help="A WordPress export does not say which page was the home page, but each page's address is in it - and the home page's address is the site's own. That page is the one offered here; a page called "Home" with another address is just a page. Made this site's home page, it goes at / and the page there now moves to /previous-home as a draft - nothing is deleted, menus that lead to / keep doing so, and nothing redirects to the old one. Its WordPress address (/home/, say) and ?page_id= links lead to /. That happens once: run the import again and the home page is updated where it is, left as it is if you edited it here (unless you choose Overwrite), and left alone altogether if you changed the home page yourself since. When an earlier import (of this site or another) set the home page and this export's home page is a different page, you are asked whether it should take over - Yes moves the current home page to /previous-home as a draft in the same way, No imports the page at its own address - and the import waits for your answer. The posts page cannot be told from the export, so an empty page with a blog's name is only suggested: switch it on if it was, and its address leads to the posts instead of an empty page being made. When WordPress showed its latest posts on the home page, you can do the same here with the Blog's list."></span></div>
|
|
137
|
+
<p class="wpx-note" data-bind-text="homeWp.value"></p>
|
|
138
|
+
<p class="wpx-note"><span data-bind-text="homeNow.value"></span> <a class="wpx-home-edit" hidden data-bind-hidden="!homeEdit.value" href="#/pages/edit/">Open it</a></p>
|
|
139
|
+
<label class="wpx-toggle" hidden data-bind-hidden="!homeFrontSwitch.value"><input type="checkbox" class="form-switch" data-model="optHome.value"> Make it this site's home page</label>
|
|
140
|
+
<div class="wpx-home-question" hidden data-bind-hidden="!homeQuestion.value">
|
|
141
|
+
<strong data-bind-text="homeQuestion.value"></strong>
|
|
142
|
+
<div class="wpx-seg" role="group" aria-label="Make it the home page">
|
|
143
|
+
<button type="button" data-on-click="homeYes" data-bind-class="opt.value.homeReplace === true && 'is-on'">Yes</button>
|
|
144
|
+
<button type="button" data-on-click="homeNo" data-bind-class="opt.value.homeReplace === false && 'is-on'">No</button>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
<label class="wpx-toggle" hidden data-bind-hidden="!homeLatestSwitch.value"><input type="checkbox" class="form-switch" data-model="optLatest.value"> Show the latest posts on the home page</label>
|
|
148
|
+
<p class="wpx-alert" hidden data-bind-hidden="!homeAfter.value" data-bind-class="homeAfterCls.value"><span data-bind-text="homeAfter.value"></span></p>
|
|
149
|
+
<div class="wpx-note-list wpx-home-notes" data-each="homeNotes.value key=text"></div>
|
|
150
|
+
<div class="wpx-home-posts" hidden data-bind-hidden="!homePostsSwitch.value">
|
|
151
|
+
<small class="wpx-note" data-bind-text="homePostsText.value"></small>
|
|
152
|
+
<label class="wpx-toggle"><input type="checkbox" class="form-switch" data-model="optPostsPage.value"> It was the posts page - lead its address to the posts</label>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
133
156
|
<div class="wpx-card wpx-products" hidden data-bind-hidden="!hasProducts.value">
|
|
134
157
|
<div class="wpx-card-title"><span data-icon="shopping-bag" data-icon-size="16"></span> Products
|
|
135
158
|
<span data-help-title="WooCommerce products" data-help="What the export's WooCommerce products come to here. The currency is not in a WordPress export: prices are read as the Shop's own currency. Weights are read as kilograms, WooCommerce's usual unit. Orders, customers, coupons, reviews and tax and shipping settings never come across - they hold people's personal details, or settings a person should check; set tax and delivery in the Shop's settings. Product reviews may come across in a later version."></span>
|
|
@@ -291,6 +314,10 @@
|
|
|
291
314
|
.wpx-role-pick { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin: 0; }
|
|
292
315
|
.wpx-role { width: auto; max-width: 100%; }
|
|
293
316
|
.wpx-people-ctl .wpx-note { flex-basis: 100%; }
|
|
317
|
+
.wpx-home-posts { display: flex; flex-direction: column; gap: .4rem; padding-top: .5rem; border-top: 1px solid var(--dm-border); }
|
|
318
|
+
.wpx-home-edit { font-size: var(--dm-text-sm); }
|
|
319
|
+
.wpx-home-question { display: flex; flex-direction: column; gap: .4rem; padding: .6rem .8rem; border-radius: var(--dm-radius-md); background: color-mix(in srgb, var(--dm-warning, var(--dm-primary)) 14%, transparent); }
|
|
320
|
+
.wpx-run-why { flex-basis: 100%; }
|
|
294
321
|
.wpx-report { display: flex; flex-direction: column; gap: .75rem; padding: .25rem 0; }
|
|
295
322
|
@media (max-width: 720px) { .wpx-toggles { grid-template-columns: 1fr; } .wpx-row { flex-wrap: wrap; } .wpx-chips { justify-content: flex-start; } }
|
|
296
323
|
</style>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{apiRequest as
|
|
1
|
+
import{apiRequest as R,getToken as uo}from"../api.js";import{addBannerAction as mo}from"../lib/plugin-chrome.js";import{helpPopovers as Et}from"../lib/help-popover.js";import{onceClosed as ho,openMenuAt as B,sidebarCount as q,viewLifetime as vo}from"../lib/tool-kit.js";import{SHAPES as $t,whileLoading as St}from"../lib/loading.js";import{fmtDateTime as wo}from"../lib/dates.js";import{applyChoice as fo,chooseAllPeople as Lt,choosePerson as bo,choiceItems as Pt,cleanOptions as xe,counts as Ct,customTypeRows as go,homeCard as yo,inviteNote as xo,peopleSummary as ko,personMenuItems as Mo,personRow as To,reportPersonRow as Eo,defaultOptions as _e,draftKey as $o,draftQuestion as So,historyRow as Lo,internalTypeRows as Po,isDirty as Co,kindTabs as Ro,liveDrafts as Rt,optionsSnapshot as qt,PLAN_FILTERS as At,planMatches as It,planRow as qo,planTiles as Nt,productSummary as Ao,progressPercent as Io,progressText as No,REPORT_FILTERS as Ot,reportMatches as Bt,reportRow as Oo,stagedRow as Bo,typeMenuItems as Do,widgetAreaRows as Ho,widgetsFileText as Uo,withDraft as Dt,withFooterChoice as _o,withListPage as zo,withTypeChoice as jo}from"../lib/wordpress-import-arrange.js";const Ht=/^#\/wordpress-import\/?(\?.*)?$/,ie="#/wordpress-import",P="/import/wordpress",ke=400,Wo=`
|
|
2
2
|
<div class="wpx-row" data-id="{{id}}" tabindex="0">
|
|
3
3
|
<span class="wpx-main"><strong>{{title}}</strong><small>{{meta}}</small></span>
|
|
4
4
|
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillClass">{{pill}}</span></span>
|
|
5
5
|
<button type="button" class="wpx-kebab" aria-label="Actions for {{title}}" title="Actions">\u22EE</button>
|
|
6
|
-
</div>`,
|
|
6
|
+
</div>`,Ut=`
|
|
7
7
|
<div class="wpx-row" data-key="{{key}}" tabindex="0">
|
|
8
8
|
<span class="wpx-main">
|
|
9
9
|
<strong>{{title}}</strong>
|
|
@@ -14,17 +14,17 @@ import{apiRequest as C,getToken as Za}from"../api.js";import{addBannerAction as
|
|
|
14
14
|
</span>
|
|
15
15
|
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillCls">{{pill}}</span></span>
|
|
16
16
|
<button type="button" class="wpx-kebab" aria-label="Actions for {{title}}" title="Actions">\u22EE</button>
|
|
17
|
-
</div>`,
|
|
17
|
+
</div>`,_t=`
|
|
18
18
|
<div class="wpx-row" data-from="{{from}}" tabindex="0">
|
|
19
19
|
<span class="wpx-main"><span class="wpx-where">{{from}} \u2192 {{to}}</span><span class="wpx-reason" data-bind-hidden="!reason">{{reason}}</span></span>
|
|
20
20
|
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillClass">{{pill}}</span></span>
|
|
21
21
|
<button type="button" class="wpx-kebab" aria-label="Actions for {{from}}" title="Actions">\u22EE</button>
|
|
22
|
-
</div>`,
|
|
22
|
+
</div>`,Fo=`
|
|
23
23
|
<div class="wpx-row" data-id="{{id}}" tabindex="0">
|
|
24
24
|
<span class="wpx-main"><strong>{{title}}</strong><small>{{meta}}</small><span class="wpx-reason">{{summary}}</span></span>
|
|
25
25
|
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillClass">{{pill}}</span></span>
|
|
26
26
|
<button type="button" class="wpx-kebab" aria-label="Actions for {{title}}" title="Actions">\u22EE</button>
|
|
27
|
-
</div
|
|
27
|
+
</div>`,Ko=`
|
|
28
28
|
<div class="wpx-row wpx-type-row" data-type="{{type}}" tabindex="0">
|
|
29
29
|
<span class="wpx-main">
|
|
30
30
|
<strong>{{label}}</strong>
|
|
@@ -42,7 +42,7 @@ import{apiRequest as C,getToken as Za}from"../api.js";import{addBannerAction as
|
|
|
42
42
|
</span>
|
|
43
43
|
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillClass">{{pill}}</span></span>
|
|
44
44
|
<button type="button" class="wpx-kebab" aria-label="Actions for {{label}}" title="Actions">\u22EE</button>
|
|
45
|
-
</div>`,
|
|
45
|
+
</div>`,Zo=`
|
|
46
46
|
<div class="wpx-row wpx-person" data-key="{{key}}" tabindex="0">
|
|
47
47
|
<span class="wpx-main">
|
|
48
48
|
<strong>{{name}}</strong>
|
|
@@ -57,12 +57,12 @@ import{apiRequest as C,getToken as Za}from"../api.js";import{addBannerAction as
|
|
|
57
57
|
</span>
|
|
58
58
|
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillClass">{{pill}}</span></span>
|
|
59
59
|
<button type="button" class="wpx-kebab" aria-label="Actions for {{name}}" title="Actions">\u22EE</button>
|
|
60
|
-
</div>`,
|
|
60
|
+
</div>`,Vo=`
|
|
61
61
|
<div class="wpx-row" data-key="{{key}}" tabindex="0">
|
|
62
62
|
<span class="wpx-main"><strong>{{name}}</strong><small>{{meta}}</small><span class="wpx-reason" data-bind-hidden="!reason">{{reason}}</span></span>
|
|
63
63
|
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillClass">{{pill}}</span></span>
|
|
64
64
|
<button type="button" class="wpx-kebab" aria-label="Actions for {{name}}" title="Actions">\u22EE</button>
|
|
65
|
-
</div>`,
|
|
65
|
+
</div>`,Yo=`
|
|
66
66
|
<div class="wpx-row wpx-widget-row" data-area="{{area}}" tabindex="0">
|
|
67
67
|
<span class="wpx-main">
|
|
68
68
|
<strong>{{label}}</strong>
|
|
@@ -76,11 +76,13 @@ import{apiRequest as C,getToken as Za}from"../api.js";import{addBannerAction as
|
|
|
76
76
|
</span>
|
|
77
77
|
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillClass">{{pill}}</span></span>
|
|
78
78
|
<button type="button" class="wpx-kebab" aria-label="Actions for {{label}}" title="Actions">\u22EE</button>
|
|
79
|
-
</div>`,Dt='<div class="wpx-tile"><strong>{{value}}</strong><small>{{label}} <span data-bind-hidden="!sub">{{sub}}</span></small></div>',Ut='<p class="wpx-alert"><span>{{text}}</span></p>',Ht="<li>{{text}}</li>",Cs='<div class="wpx-fact"><dt>{{label}}</dt><dd>{{value}}</dd></div>',Be='<button type="button" data-on-click="$root.pickSeg($data)" data-bind-class="cls">{{label}} <b>{{count}}</b></button>',f=Ja(It);function _e(u,l,i){return new Promise((b,k)=>{const w=new XMLHttpRequest,q=new FormData;q.append("file",l),w.open("POST",`/api${u}`);const v=Za();v&&w.setRequestHeader("Authorization",`Bearer ${v}`),w.upload.onprogress=m=>{m.lengthComputable&&i(m.loaded/m.total)},w.onload=()=>{let m=null;try{m=JSON.parse(w.responseText)}catch{}w.status>=200&&w.status<300?b(m):k(new Error(m?.error||`The upload failed (${w.status}).`))},w.onerror=()=>k(new Error("The upload failed - the connection dropped.")),w.send(q),f.add(()=>{w.readyState!==4&&w.abort()})})}const ke=u=>u>=1048576?`${Math.round(u/1048576)} MB`:`${Math.max(1,Math.round(u/1024))} KB`,V=u=>String(u??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");function Rs(u){const l=document.createElement("template");return l.innerHTML=u.trim(),l.content.firstElementChild}async function Me(u,l){const i=E.confirm(u,l);let b=null;try{b=[...document.querySelectorAll(".dm-dialog-overlay")].at(-1)??null}catch{}const k=f.add(()=>{if(!b)return;const w=b;b=null;try{w.querySelector(".dm-dialog-cancel")?.click(),w.remove()}catch{}});try{return await i}finally{b=null,k()}}function ze(u){navigator.clipboard?.writeText(u).then(()=>E.toast("Copied.",{type:"success"}),()=>E.toast(u,{type:"info",duration:8e3}))}function H(u,l,i,b){const k=E.contextMenu(u,{cursor:"glyph",match:l,inherit:!1,density:"compact",items:i});f.add(()=>k?.destroy?.());const w=v=>{const m=v.target.closest(l);if(!m||!u.contains(m))return;const p=v.target.closest(".wpx-kebab");if(p){O(p);return}b?.(m)},q=v=>{const m=v.target.closest(l);m&&(v.key==="F10"&&v.shiftKey?(v.preventDefault(),O(m)):v.key==="Enter"&&v.target===m&&b&&(v.preventDefault(),v.stopPropagation(),b(m)))};u.addEventListener("click",w),u.addEventListener("keydown",q),f.add(()=>{u.removeEventListener("click",w),u.removeEventListener("keydown",q)})}export const wordpressImportView={templateUrl:"/admin/js/templates/wordpress-import.html",async onMount(u){f.reset();const l=u.get(0).querySelector(".wpx")||u.get(0),i=()=>It.test(location.hash)&&l.isConnected;let b="";try{b=S.get("auth_user")?.id||""}catch{}const k=ls(b),w=()=>{try{return k?S.get(k):null}catch{return null}},q=e=>{try{k&&S.set(k,e)}catch{}},v=l.querySelector(".wpx-loading");let m;try{m=await kt(v,C(`${$}/status`),xt.rows)}catch(e){if(!l.isConnected)return;v&&(v.hidden=!0);const t=l.querySelector(".wpx-failed");t&&(t.textContent=`Could not load the importer: ${e.message||e}. Reload the page to try again.`,t.hidden=!1);return}if(!i())return;v&&(v.hidden=!0),l.querySelector(".wpx-body").hidden=!1;const p=M.observable(m.staged||[]),B=M.observable(m.history||[]),G=M.observable(m.blog||{available:!1}),je=M.observable(m.shop||{available:!1}),_=m.limits||{},We=m.people?.defaultRole||"",y=M.observable(m.running||null),h=M.observable(""),g=M.observable(null),ie=M.observable(!1),Te=M.observable(!1),Ee=M.observable(""),c=M.observable(He(G.peek().available)),z=M.observable("all"),D=M.observable(""),J=M.observable(""),ce=M.observable(""),Y=M.observable(""),pe=M.observable(""),de=M.observable(!1);let ue=!0;const qs=()=>p.peek().find(e=>e.id===h.peek())||null,X=M.computed(()=>p.value.find(e=>e.id===h.value)||null),Bt=M.computed(()=>h.value?"preview":"start"),U=M.computed(()=>!!G.value.available),_t=M.computed(()=>!!(g.value?.shop||je.value).available),Fe=M.computed(()=>!!h.value&&ps(c.value,U.value)),Q=e=>M.computed({read:()=>c.value[e]!==!1,write:t=>{c.value={...c.peek(),[e]:!!t}}}),P=e=>{c.value={...c.peek(),...e}},ee=e=>{try{return Ya(e)}catch{return e}},zt=M.computed(()=>p.value.map(e=>fs(e,ee))),jt=M.computed(()=>B.value.map(e=>is(e,ee))),j=M.computed(()=>(g.value?.items||[]).map(e=>({...e,choice:c.value.choices?.[e.key]}))),Wt=M.computed(()=>ds(j.value).map(e=>({...e,cls:D.value===e.id?"is-on":"",seg:"kind"}))),Ft=M.computed(()=>Et(j.value,St,Pt,D.value)),Kt=M.computed(()=>St.map(e=>({...e,count:Ft.value[e.id],cls:z.value===e.id?"is-on":"",seg:"filter"}))),$e=M.computed(()=>{const e=J.value.trim().toLowerCase();return j.value.filter(t=>(!D.value||t.kind===D.value)&&Pt(t,z.value)&&(!e||`${t.title} ${t.target} ${t.oldUrl} ${t.postType||""}`.toLowerCase().includes(e)))}),Zt=M.computed(()=>$e.value.slice(0,xe).map(e=>{const t=us(e);return{...t,pillCls:`${t.pillClass}${e.choice?" is-chosen":""}`}})),Vt=M.computed(()=>$e.value.length>xe?`Showing the first ${xe} of ${$e.value.length} - search or filter to find the rest.`:""),Gt=M.computed(()=>j.value.length?"Nothing matches.":"This export has nothing to import."),Jt=M.computed(()=>Ct(g.value)),Yt=M.computed(()=>(g.value?.notes||[]).map(e=>({text:e}))),Xt=M.computed(()=>(g.value?.redirects||[]).slice(0,xe).map(e=>({...e,pill:e.action==="skip"?"Skipped":e.action==="update"?"Update":"New",pillClass:e.action==="skip"?"is-muted":"is-ok"}))),Qt=M.computed(()=>String((g.value?.redirects||[]).filter(e=>e.action!=="skip").length)),ea=M.computed(()=>g.value?.site?.title||X.value?.siteTitle||"WordPress export"),ta=M.computed(()=>{const e=X.value,t=g.value?.site;return[t?.url||e?.siteUrl,e?.fileName,t?.wxrVersion&&`WXR ${t.wxrVersion}`,e?.at&&`uploaded ${ee(e.at)}`].filter(Boolean).join(" \xB7 ")}),te=M.computed(()=>ms(g.value)),aa=M.computed(()=>te.value?.note||""),sa=M.computed(()=>te.value?.tone==="warn"?"is-warn":"is-info"),oa=M.computed(()=>(te.value?.rows||[]).map(e=>({...e,id:e.label}))),na=M.computed(()=>(te.value?.notes||[]).map(e=>({text:e}))),la=M.computed(()=>!!te.value),Le=M.computed(()=>es(g.value)),Se=M.computed(()=>cs(g.value)),ra=M.computed(()=>!!(Le.value.length||Se.value.length)),ia=M.computed(()=>{const e=Se.value.length;return e?`Not imported: ${e} kind${e===1?"":"s"} of WordPress or plugin housekeeping`:""}),T=M.computed(()=>g.value?.people||null),ca=M.computed(()=>!!T.value?.rows?.length),pa=M.computed(()=>(T.value?.rows||[]).map(os)),da=M.computed(()=>!!T.value?.canCreate),ua=M.computed(()=>(T.value?.rows||[]).some(e=>e.choosable)),Ke=M.computed(()=>as(T.value)),ma=M.computed(()=>Ke.value.text),ha=M.computed(()=>Ke.value.tone==="warn"?"is-warn":"is-info"),wa=M.computed(()=>!!(T.value?.canCreate&&T.value?.mailReady&&T.value?.counts?.create)),va=M.computed(()=>ts(T.value)),fa=M.computed({read:()=>c.value.invite===!0,write:e=>{c.value={...c.peek(),invite:!!e}}}),ba=M.computed(()=>U.value?`Posts go to ${G.value.basePath||"/blog"}.`:G.value.reason||"No Blog is switched on here."),me=M.computed(()=>X.value?.uploads||null),ga=M.computed(()=>{const e=me.value;return e?`${e.fileName} - ${e.files} file${e.files===1?"":"s"}, ${ke(e.size)}${e.unsafe?`. ${e.unsafe} with unsafe names (like ../) were ignored`:""}.`:`Zip the wp-content/uploads folder and upload it here (up to ${ke(_.uploads||0)}).`}),ya=M.computed(()=>me.value?"Replace the zip":"Upload the uploads zip"),Ze=M.computed(()=>X.value?.widgets||null),xa=M.computed(()=>ys(X.value,_.widgets||0)),ka=M.computed(()=>Ze.value?"Replace the widgets file":"Upload the widgets file"),Pe=M.observable(""),Ve=M.computed(()=>gs(g.value)),Ge=M.computed(()=>!!g.value&&!y.value&&!ie.value&&!(c.value.media==="zip"&&!me.value)),Ma=M.computed(()=>y.value?`Importing${y.value.siteTitle?` ${y.value.siteTitle}`:""}\u2026`:""),Ta=M.computed(()=>ws(y.value)),Je=M.computed(()=>hs(y.value)),Ea=M.observable(ke(_.wxr||0)),Ye=l.querySelector(".wpx-running .wpx-bar-fill");f.add(M.effect(()=>{Ye&&(Ye.style.width=`${Je.value}%`)}));async function Ce(){const e=await C(`${$}/status`);return i()?(p.value=e.staged||[],B.value=e.history||[],G.value=e.blog||{available:!1},je.value=e.shop||{available:!1},e.running&&!y.peek()&&(y.value=e.running,se()),e):null}let he=0,Re=null;async function W({first:e=!1}={}){const t=h.peek();if(!t)return;const a=++he;Ee.value="";const s=C(`${$}/staged/${t}/preview`,{method:"POST",body:JSON.stringify({options:ye(c.peek(),U.peek())})});try{let r;if(e?(ie.value=!0,r=await kt(l.querySelector(".wpx-plan-loading"),s,xt.table)):(Te.value=!0,r=await s),a!==he||!i()||h.peek()!==t)return;g.value=r.plan}catch(r){if(a!==he||!i())return;if(r.status===404){E.toast("That upload has gone - upload the export again.",{type:"warning"}),ae(),Ce().catch(()=>{});return}Ee.value=`Could not read the export: ${r.message||r}`}finally{a===he&&(ie.value=!1,Te.value=!1)}}let we="";f.add(M.effect(()=>{const e=`${h.value}|${Lt(c.value)}`;if(e===we)return;const t=we.split("|")[0];we=e,!(!h.value||t!==h.value)&&(clearTimeout(Re),Re=setTimeout(()=>W(),250))})),f.add(()=>clearTimeout(Re)),f.add(M.effect(()=>{const e=h.value,t=c.value,a=Fe.value;if(!e||!ue||!k)return;const s=w();q(At(s,b,e,a?{options:ye(t,!0),at:new Date().toISOString(),was:e}:null))}));const qe=e=>{k&&q(At(w(),b,e,null))};async function ve(e){if(!p.peek().some(d=>d.id===e))return;const t=p.peek().find(d=>d.id===e),a=$t(w(),p.peek().map(d=>d.id),b).items[e];if(ue=!a,g.value=null,z.value="all",D.value="",J.value="",c.value=He(U.peek()),we=`${e}|${Lt(c.peek())}`,h.value=e,await W({first:!0}),!i()||h.peek()!==e||!a)return;await new Promise(d=>setTimeout(d,0));const s=rs({when:a.at?ee(a.at):"",file:t?.fileName||""}),r=await Me(V(s.text),{title:s.title,confirmText:s.confirmText,cancelText:s.cancelText});!i()||h.peek()!==e||(ue=!0,r?qe(e):c.value=ye(a.options,U.peek()))}function ae(){h.value="",g.value=null,ue=!0}async function Xe(e=h.peek()){const t=p.peek().find(a=>a.id===e);if(t&&await Me(`Discard the upload of <strong>${V(t.siteTitle||t.fileName)}</strong>? Nothing has been imported from it.`,{title:"Discard upload",confirmText:"Discard",danger:!0}))try{if(await C(`${$}/staged/${e}`,{method:"DELETE"}),qe(e),!i())return;h.peek()===e&&ae(),p.value=p.peek().filter(a=>a.id!==e),R(re)}catch(a){E.toast(`Not discarded: ${a.message||a}`,{type:"error"})}}async function Qe(e){if(!e)return;if(Y.value="",!/\.(xml|zip)$/i.test(e.name)){Y.value="Upload the .xml file WordPress exports, or a .zip holding it.";return}if(_.wxr&&e.size>_.wxr*1.2&&/\.xml$/i.test(e.name)){Y.value=`That file is over ${ke(_.wxr)}.`;return}const t=l.querySelector(".wpx-start .wpx-upload .wpx-bar-fill");ce.value=`Uploading ${e.name}\u2026`;try{const a=await _e(`${$}/upload`,e,s=>{t&&(t.style.width=`${Math.round(s*100)}%`),ce.value=s<1?`Uploading ${e.name} - ${Math.round(s*100)}%`:`Reading ${e.name}\u2026`});if(!i())return;p.value=[a,...p.peek().filter(s=>s.id!==a.id)],R(re),await ve(a.id)}catch(a){i()&&(Y.value=a.message||String(a))}finally{i()&&(ce.value="",t&&(t.style.width="0"))}}async function $a(e){const t=h.peek();if(!e||!t)return;if(!/\.zip$/i.test(e.name)){E.toast("Zip the wp-content/uploads folder and upload the .zip.",{type:"warning"});return}const a=l.querySelector(".wpx-zip-fill");pe.value=`Uploading ${e.name}\u2026`;try{const s=await _e(`${$}/staged/${t}/uploads`,e,r=>{a&&(a.style.width=`${Math.round(r*100)}%`),pe.value=r<1?`Uploading ${e.name} - ${Math.round(r*100)}%`:`Checking ${e.name}\u2026`});if(!i())return;p.value=p.peek().map(r=>r.id===s.id?s:r),h.peek()===t&&W()}catch(s){i()&&E.toast(s.message||String(s),{type:"error"})}finally{i()&&(pe.value="",a&&(a.style.width="0"))}}async function La(e){const t=h.peek();if(!(!e||!t)){if(!/\.(wie|json)$/i.test(e.name)){E.toast('Upload the .wie file the "Widget Importer & Exporter" plugin exports.',{type:"warning"});return}Pe.value=`Reading ${e.name}\u2026`;try{const a=await _e(`${$}/staged/${t}/widgets`,e,()=>{});if(!i())return;p.value=p.peek().map(s=>s.id===a.id?a:s),h.peek()===t&&W()}catch(a){i()&&E.toast(a.message||String(a),{type:"error"})}finally{i()&&(Pe.value="")}}}async function Sa(){const e=h.peek();try{const t=await C(`${$}/staged/${e}/widgets`,{method:"DELETE"});if(!i())return;p.value=p.peek().map(a=>a.id===t.id?t:a),W()}catch(t){E.toast(`Not removed: ${t.message||t}`,{type:"error"})}}async function Pa(){const e=h.peek();try{const t=await C(`${$}/staged/${e}/uploads`,{method:"DELETE"});if(!i())return;p.value=p.peek().map(a=>a.id===t.id?t:a),W()}catch(t){E.toast(`Not removed: ${t.message||t}`,{type:"error"})}}async function Ca(){const e=h.peek(),t=g.peek();if(!e||!t||!Ge.peek())return;const s=Ct(t).filter(d=>d.value&&d.id!=="comments").map(d=>`${d.value} ${d.label.toLowerCase()}`);if(!(!await Me(`Import <strong>${V(t.site?.title||"this export")}</strong>: ${V(s.join(", ")||"nothing new")}? Pages edited here since an earlier import are left alone unless you chose Overwrite.`,{title:"Run the import",confirmText:"Run import"})||!i()||h.peek()!==e))try{const d=await C(`${$}/staged/${e}/run`,{method:"POST",body:JSON.stringify({options:ye(c.peek(),U.peek())})});if(qe(e),!i())return;y.value={...d.job,siteTitle:t.site?.title||""},ae(),R(re),se()}catch(d){E.toast(`The import did not start: ${d.message||d}`,{type:"error"})}}let Ae=null;function se(){clearTimeout(Ae);const e=y.peek();e&&(Ae=setTimeout(async()=>{try{const t=await C(`${$}/jobs/${e.id}`);if(!i())return;if(y.value={...t.job,siteTitle:e.siteTitle},t.job.status==="running")return se();if(y.value=null,await Ce().catch(()=>{}),R(re),R("#/pages"),R("#/media"),R("#/plugins/shopping-cart"),R("#/collections"),R("#/blocks"),!i())return;t.job.status==="done"?(E.toast("The import has finished - here is its report.",{type:"success"}),fe(t.job.reportId)):(E.toast(`The import stopped: ${t.job.error||"an error"}`,{type:"error"}),t.job.reportId&&fe(t.job.reportId))}catch(t){if(!i())return;if(t.status===404){y.value=null,Ce().catch(()=>{});return}se()}},700))}f.add(()=>clearTimeout(Ae)),y.peek()&&se();let F=!1;async function fe(e){if(F||!e)return;F=!0;let t;try{t=await C(`${$}/history/${e}`)}catch(o){F=!1,E.toast(`Could not open the report: ${o.message||o}`,{type:"error"});return}if(!i()){F=!1;return}let a;try{a=E.slideover({title:V(`Report - ${t.run?.siteTitle||"WordPress import"}`),size:"lg",position:"right"})}catch(o){throw F=!1,o}const s=Rs(`
|
|
79
|
+
</div>`,zt='<div class="wpx-tile"><strong>{{value}}</strong><small>{{label}} <span data-bind-hidden="!sub">{{sub}}</span></small></div>',ze='<p class="wpx-alert"><span>{{text}}</span></p>',jt="<li>{{text}}</li>",Go='<div class="wpx-fact"><dt>{{label}}</dt><dd>{{value}}</dd></div>',je='<button type="button" data-on-click="$root.pickSeg($data)" data-bind-class="cls">{{label}} <b>{{count}}</b></button>',b=vo(Ht);function We(u,l,p){return new Promise((g,T)=>{const v=new XMLHttpRequest,A=new FormData;A.append("file",l),v.open("POST",`/api${u}`);const w=uo();w&&v.setRequestHeader("Authorization",`Bearer ${w}`),v.upload.onprogress=m=>{m.lengthComputable&&p(m.loaded/m.total)},v.onload=()=>{let m=null;try{m=JSON.parse(v.responseText)}catch{}v.status>=200&&v.status<300?g(m):T(new Error(m?.error||`The upload failed (${v.status}).`))},v.onerror=()=>T(new Error("The upload failed - the connection dropped.")),v.send(A),b.add(()=>{v.readyState!==4&&v.abort()})})}const Me=u=>u>=1048576?`${Math.round(u/1048576)} MB`:`${Math.max(1,Math.round(u/1024))} KB`,G=u=>String(u??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");function Jo(u){const l=document.createElement("template");return l.innerHTML=u.trim(),l.content.firstElementChild}async function Te(u,l){const p=E.confirm(u,l);let g=null;try{g=[...document.querySelectorAll(".dm-dialog-overlay")].at(-1)??null}catch{}const T=b.add(()=>{if(!g)return;const v=g;g=null;try{v.querySelector(".dm-dialog-cancel")?.click(),v.remove()}catch{}});try{return await p}finally{g=null,T()}}function Fe(u){navigator.clipboard?.writeText(u).then(()=>E.toast("Copied.",{type:"success"}),()=>E.toast(u,{type:"info",duration:8e3}))}function U(u,l,p,g){const T=E.contextMenu(u,{cursor:"glyph",match:l,inherit:!1,density:"compact",items:p});b.add(()=>T?.destroy?.());const v=w=>{const m=w.target.closest(l);if(!m||!u.contains(m))return;const d=w.target.closest(".wpx-kebab");if(d){B(d);return}g?.(m)},A=w=>{const m=w.target.closest(l);m&&(w.key==="F10"&&w.shiftKey?(w.preventDefault(),B(m)):w.key==="Enter"&&w.target===m&&g&&(w.preventDefault(),w.stopPropagation(),g(m)))};u.addEventListener("click",v),u.addEventListener("keydown",A),b.add(()=>{u.removeEventListener("click",v),u.removeEventListener("keydown",A)})}export const wordpressImportView={templateUrl:"/admin/js/templates/wordpress-import.html",async onMount(u){b.reset();const l=u.get(0).querySelector(".wpx")||u.get(0),p=()=>Ht.test(location.hash)&&l.isConnected;let g="";try{g=S.get("auth_user")?.id||""}catch{}const T=$o(g),v=()=>{try{return T?S.get(T):null}catch{return null}},A=e=>{try{T&&S.set(T,e)}catch{}},w=l.querySelector(".wpx-loading");let m;try{m=await St(w,R(`${P}/status`),$t.rows)}catch(e){if(!l.isConnected)return;w&&(w.hidden=!0);const t=l.querySelector(".wpx-failed");t&&(t.textContent=`Could not load the importer: ${e.message||e}. Reload the page to try again.`,t.hidden=!1);return}if(!p())return;w&&(w.hidden=!0),l.querySelector(".wpx-body").hidden=!1;const d=M.observable(m.staged||[]),_=M.observable(m.history||[]),J=M.observable(m.blog||{available:!1}),Ke=M.observable(m.shop||{available:!1}),z=m.limits||{},Ze=m.people?.defaultRole||"",y=M.observable(m.running||null),h=M.observable(""),f=M.observable(null),pe=M.observable(!1),Ee=M.observable(!1),$e=M.observable(""),i=M.observable(_e(J.peek().available)),j=M.observable("all"),D=M.observable(""),Q=M.observable(""),ce=M.observable(""),X=M.observable(""),de=M.observable(""),ue=M.observable(!1);let me=!0;const Qo=()=>d.peek().find(e=>e.id===h.peek())||null,ee=M.computed(()=>d.value.find(e=>e.id===h.value)||null),Wt=M.computed(()=>h.value?"preview":"start"),H=M.computed(()=>!!J.value.available),Ft=M.computed(()=>!!(f.value?.shop||Ke.value).available),Ve=M.computed(()=>!!h.value&&Co(i.value,H.value)),W=e=>M.computed({read:()=>i.value[e]!==!1,write:t=>{i.value={...i.peek(),[e]:!!t}}}),$=e=>{i.value={...i.peek(),...e}},te=e=>{try{return wo(e)}catch{return e}},Kt=M.computed(()=>d.value.map(e=>Bo(e,te))),Zt=M.computed(()=>_.value.map(e=>Lo(e,te))),F=M.computed(()=>(f.value?.items||[]).map(e=>({...e,choice:i.value.choices?.[e.key]}))),Vt=M.computed(()=>Ro(F.value).map(e=>({...e,cls:D.value===e.id?"is-on":"",seg:"kind"}))),Yt=M.computed(()=>Ct(F.value,At,It,D.value)),Gt=M.computed(()=>At.map(e=>({...e,count:Yt.value[e.id],cls:j.value===e.id?"is-on":"",seg:"filter"}))),Se=M.computed(()=>{const e=Q.value.trim().toLowerCase();return F.value.filter(t=>(!D.value||t.kind===D.value)&&It(t,j.value)&&(!e||`${t.title} ${t.target} ${t.oldUrl} ${t.postType||""}`.toLowerCase().includes(e)))}),Jt=M.computed(()=>Se.value.slice(0,ke).map(e=>{const t=qo(e);return{...t,pillCls:`${t.pillClass}${e.choice?" is-chosen":""}`}})),Qt=M.computed(()=>Se.value.length>ke?`Showing the first ${ke} of ${Se.value.length} - search or filter to find the rest.`:""),Xt=M.computed(()=>F.value.length?"Nothing matches.":"This export has nothing to import."),ea=M.computed(()=>Nt(f.value)),ta=M.computed(()=>(f.value?.notes||[]).map(e=>({text:e}))),aa=M.computed(()=>(f.value?.redirects||[]).slice(0,ke).map(e=>({...e,pill:e.action==="skip"?"Skipped":e.action==="update"?"Update":"New",pillClass:e.action==="skip"?"is-muted":"is-ok"}))),oa=M.computed(()=>String((f.value?.redirects||[]).filter(e=>e.action!=="skip").length)),sa=M.computed(()=>f.value?.site?.title||ee.value?.siteTitle||"WordPress export"),na=M.computed(()=>{const e=ee.value,t=f.value?.site;return[t?.url||e?.siteUrl,e?.fileName,t?.wxrVersion&&`WXR ${t.wxrVersion}`,e?.at&&`uploaded ${te(e.at)}`].filter(Boolean).join(" \xB7 ")}),ae=M.computed(()=>Ao(f.value)),la=M.computed(()=>ae.value?.note||""),ra=M.computed(()=>ae.value?.tone==="warn"?"is-warn":"is-info"),ia=M.computed(()=>(ae.value?.rows||[]).map(e=>({...e,id:e.label}))),pa=M.computed(()=>(ae.value?.notes||[]).map(e=>({text:e}))),ca=M.computed(()=>!!ae.value),x=M.computed(()=>yo(f.value)),da=M.computed(()=>!!x.value),ua=M.computed(()=>x.value?.wp||""),ma=M.computed(()=>x.value?.now||""),ha=M.computed(()=>x.value?.after||""),va=M.computed(()=>x.value?.tone==="warn"?"":"is-info"),wa=M.computed(()=>(x.value?.notes||[]).map(e=>({text:e}))),fa=M.computed(()=>x.value?.editNow||""),ba=M.computed(()=>!!x.value?.frontSwitch),ga=M.computed(()=>!!x.value?.latestSwitch),ya=M.computed(()=>!!x.value?.postsSwitch),xa=M.computed(()=>x.value?.postsText||""),Ye=M.computed(()=>x.value?.question||""),Ge=M.computed(()=>!!Ye.value&&typeof i.value.homeReplace!="boolean"),ka=M.computed({read:()=>i.value.latestPosts===!0,write:e=>$({latestPosts:!!e})}),Ma=M.computed({read:()=>!!x.value?.postsId&&i.value.postsPage===x.value.postsId,write:e=>$({postsPage:e&&x.peek()?.postsId||0})}),Le=M.computed(()=>go(f.value)),Pe=M.computed(()=>Po(f.value)),Ta=M.computed(()=>!!(Le.value.length||Pe.value.length)),Ea=M.computed(()=>{const e=Pe.value.length;return e?`Not imported: ${e} kind${e===1?"":"s"} of WordPress or plugin housekeeping`:""}),L=M.computed(()=>f.value?.people||null),$a=M.computed(()=>!!L.value?.rows?.length),Sa=M.computed(()=>(L.value?.rows||[]).map(To)),La=M.computed(()=>!!L.value?.canCreate),Pa=M.computed(()=>(L.value?.rows||[]).some(e=>e.choosable)),Je=M.computed(()=>ko(L.value)),Ca=M.computed(()=>Je.value.text),Ra=M.computed(()=>Je.value.tone==="warn"?"is-warn":"is-info"),qa=M.computed(()=>!!(L.value?.canCreate&&L.value?.mailReady&&L.value?.counts?.create)),Aa=M.computed(()=>xo(L.value)),Ia=M.computed({read:()=>i.value.invite===!0,write:e=>{i.value={...i.peek(),invite:!!e}}}),Na=M.computed(()=>H.value?`Posts go to ${J.value.basePath||"/blog"}.`:J.value.reason||"No Blog is switched on here."),he=M.computed(()=>ee.value?.uploads||null),Oa=M.computed(()=>{const e=he.value;return e?`${e.fileName} - ${e.files} file${e.files===1?"":"s"}, ${Me(e.size)}${e.unsafe?`. ${e.unsafe} with unsafe names (like ../) were ignored`:""}.`:`Zip the wp-content/uploads folder and upload it here (up to ${Me(z.uploads||0)}).`}),Ba=M.computed(()=>he.value?"Replace the zip":"Upload the uploads zip"),Qe=M.computed(()=>ee.value?.widgets||null),Da=M.computed(()=>Uo(ee.value,z.widgets||0)),Ha=M.computed(()=>Qe.value?"Replace the widgets file":"Upload the widgets file"),Ce=M.observable(""),Xe=M.computed(()=>Ho(f.value)),Ua=M.computed(()=>Ge.value?"Answer the home page question first.":""),et=M.computed(()=>!!f.value&&!y.value&&!pe.value&&!(i.value.media==="zip"&&!he.value)&&!Ge.value),_a=M.computed(()=>y.value?`Importing${y.value.siteTitle?` ${y.value.siteTitle}`:""}\u2026`:""),za=M.computed(()=>No(y.value)),tt=M.computed(()=>Io(y.value)),ja=M.observable(Me(z.wxr||0)),at=l.querySelector(".wpx-running .wpx-bar-fill");b.add(M.effect(()=>{at&&(at.style.width=`${tt.value}%`)}));async function Re(){const e=await R(`${P}/status`);return p()?(d.value=e.staged||[],_.value=e.history||[],J.value=e.blog||{available:!1},Ke.value=e.shop||{available:!1},e.running&&!y.peek()&&(y.value=e.running,se()),e):null}let ve=0,qe=null;async function K({first:e=!1}={}){const t=h.peek();if(!t)return;const a=++ve;$e.value="";const o=R(`${P}/staged/${t}/preview`,{method:"POST",body:JSON.stringify({options:xe(i.peek(),H.peek())})});try{let r;if(e?(pe.value=!0,r=await St(l.querySelector(".wpx-plan-loading"),o,$t.table)):(Ee.value=!0,r=await o),a!==ve||!p()||h.peek()!==t)return;f.value=r.plan}catch(r){if(a!==ve||!p())return;if(r.status===404){E.toast("That upload has gone - upload the export again.",{type:"warning"}),oe(),Re().catch(()=>{});return}$e.value=`Could not read the export: ${r.message||r}`}finally{a===ve&&(pe.value=!1,Ee.value=!1)}}let we="";b.add(M.effect(()=>{const e=`${h.value}|${qt(i.value)}`;if(e===we)return;const t=we.split("|")[0];we=e,!(!h.value||t!==h.value)&&(clearTimeout(qe),qe=setTimeout(()=>K(),250))})),b.add(()=>clearTimeout(qe)),b.add(M.effect(()=>{const e=h.value,t=i.value,a=Ve.value;if(!e||!me||!T)return;const o=v();A(Dt(o,g,e,a?{options:xe(t,!0),at:new Date().toISOString(),was:e}:null))}));const Ae=e=>{T&&A(Dt(v(),g,e,null))};async function fe(e){if(!d.peek().some(c=>c.id===e))return;const t=d.peek().find(c=>c.id===e),a=Rt(v(),d.peek().map(c=>c.id),g).items[e];if(me=!a,f.value=null,j.value="all",D.value="",Q.value="",i.value=_e(H.peek()),we=`${e}|${qt(i.peek())}`,h.value=e,await K({first:!0}),!p()||h.peek()!==e||!a)return;await new Promise(c=>setTimeout(c,0));const o=So({when:a.at?te(a.at):"",file:t?.fileName||""}),r=await Te(G(o.text),{title:o.title,confirmText:o.confirmText,cancelText:o.cancelText});!p()||h.peek()!==e||(me=!0,r?Ae(e):i.value=xe(a.options,H.peek()))}function oe(){h.value="",f.value=null,me=!0}async function ot(e=h.peek()){const t=d.peek().find(a=>a.id===e);if(t&&await Te(`Discard the upload of <strong>${G(t.siteTitle||t.fileName)}</strong>? Nothing has been imported from it.`,{title:"Discard upload",confirmText:"Discard",danger:!0}))try{if(await R(`${P}/staged/${e}`,{method:"DELETE"}),Ae(e),!p())return;h.peek()===e&&oe(),d.value=d.peek().filter(a=>a.id!==e),q(ie)}catch(a){E.toast(`Not discarded: ${a.message||a}`,{type:"error"})}}async function st(e){if(!e)return;if(X.value="",!/\.(xml|zip)$/i.test(e.name)){X.value="Upload the .xml file WordPress exports, or a .zip holding it.";return}if(z.wxr&&e.size>z.wxr*1.2&&/\.xml$/i.test(e.name)){X.value=`That file is over ${Me(z.wxr)}.`;return}const t=l.querySelector(".wpx-start .wpx-upload .wpx-bar-fill");ce.value=`Uploading ${e.name}\u2026`;try{const a=await We(`${P}/upload`,e,o=>{t&&(t.style.width=`${Math.round(o*100)}%`),ce.value=o<1?`Uploading ${e.name} - ${Math.round(o*100)}%`:`Reading ${e.name}\u2026`});if(!p())return;d.value=[a,...d.peek().filter(o=>o.id!==a.id)],q(ie),await fe(a.id)}catch(a){p()&&(X.value=a.message||String(a))}finally{p()&&(ce.value="",t&&(t.style.width="0"))}}async function Wa(e){const t=h.peek();if(!e||!t)return;if(!/\.zip$/i.test(e.name)){E.toast("Zip the wp-content/uploads folder and upload the .zip.",{type:"warning"});return}const a=l.querySelector(".wpx-zip-fill");de.value=`Uploading ${e.name}\u2026`;try{const o=await We(`${P}/staged/${t}/uploads`,e,r=>{a&&(a.style.width=`${Math.round(r*100)}%`),de.value=r<1?`Uploading ${e.name} - ${Math.round(r*100)}%`:`Checking ${e.name}\u2026`});if(!p())return;d.value=d.peek().map(r=>r.id===o.id?o:r),h.peek()===t&&K()}catch(o){p()&&E.toast(o.message||String(o),{type:"error"})}finally{p()&&(de.value="",a&&(a.style.width="0"))}}async function Fa(e){const t=h.peek();if(!(!e||!t)){if(!/\.(wie|json)$/i.test(e.name)){E.toast('Upload the .wie file the "Widget Importer & Exporter" plugin exports.',{type:"warning"});return}Ce.value=`Reading ${e.name}\u2026`;try{const a=await We(`${P}/staged/${t}/widgets`,e,()=>{});if(!p())return;d.value=d.peek().map(o=>o.id===a.id?a:o),h.peek()===t&&K()}catch(a){p()&&E.toast(a.message||String(a),{type:"error"})}finally{p()&&(Ce.value="")}}}async function Ka(){const e=h.peek();try{const t=await R(`${P}/staged/${e}/widgets`,{method:"DELETE"});if(!p())return;d.value=d.peek().map(a=>a.id===t.id?t:a),K()}catch(t){E.toast(`Not removed: ${t.message||t}`,{type:"error"})}}async function Za(){const e=h.peek();try{const t=await R(`${P}/staged/${e}/uploads`,{method:"DELETE"});if(!p())return;d.value=d.peek().map(a=>a.id===t.id?t:a),K()}catch(t){E.toast(`Not removed: ${t.message||t}`,{type:"error"})}}async function Va(){const e=h.peek(),t=f.peek();if(!e||!t||!et.peek())return;const o=Nt(t).filter(c=>c.value&&c.id!=="comments").map(c=>`${c.value} ${c.label.toLowerCase()}`);if(!(!await Te(`Import <strong>${G(t.site?.title||"this export")}</strong>: ${G(o.join(", ")||"nothing new")}? Pages edited here since an earlier import are left alone unless you chose Overwrite.`,{title:"Run the import",confirmText:"Run import"})||!p()||h.peek()!==e))try{const c=await R(`${P}/staged/${e}/run`,{method:"POST",body:JSON.stringify({options:xe(i.peek(),H.peek())})});if(Ae(e),!p())return;y.value={...c.job,siteTitle:t.site?.title||""},oe(),q(ie),se()}catch(c){E.toast(`The import did not start: ${c.message||c}`,{type:"error"})}}let Ie=null;function se(){clearTimeout(Ie);const e=y.peek();e&&(Ie=setTimeout(async()=>{try{const t=await R(`${P}/jobs/${e.id}`);if(!p())return;if(y.value={...t.job,siteTitle:e.siteTitle},t.job.status==="running")return se();if(y.value=null,await Re().catch(()=>{}),q(ie),q("#/pages"),q("#/media"),q("#/plugins/shopping-cart"),q("#/collections"),q("#/blocks"),!p())return;t.job.status==="done"?(E.toast("The import has finished - here is its report.",{type:"success"}),be(t.job.reportId)):(E.toast(`The import stopped: ${t.job.error||"an error"}`,{type:"error"}),t.job.reportId&&be(t.job.reportId))}catch(t){if(!p())return;if(t.status===404){y.value=null,Re().catch(()=>{});return}se()}},700))}b.add(()=>clearTimeout(Ie)),y.peek()&&se();let Z=!1;async function be(e){if(Z||!e)return;Z=!0;let t;try{t=await R(`${P}/history/${e}`)}catch(s){Z=!1,E.toast(`Could not open the report: ${s.message||s}`,{type:"error"});return}if(!p()){Z=!1;return}let a;try{a=E.slideover({title:G(`Report - ${t.run?.siteTitle||"WordPress import"}`),size:"lg",position:"right"})}catch(s){throw Z=!1,s}const o=Jo(`
|
|
80
80
|
<div class="wpx wpx-report">
|
|
81
81
|
<p class="wpx-note" data-bind-text="meta.value"></p>
|
|
82
82
|
<div class="wpx-tiles" data-each="tiles.value key=id"></div>
|
|
83
83
|
<div class="wpx-note-list" data-each="notes.value key=text"></div>
|
|
84
|
+
<p class="wpx-alert is-info" hidden data-bind-hidden="!homePrevious.value"><span data-bind-text="homePreviousText.value"></span>
|
|
85
|
+
<button type="button" class="btn btn-sm btn-ghost wpx-open-previous">Open it</button></p>
|
|
84
86
|
<div class="wpx-bar-row"><div class="wpx-seg" role="group" aria-label="Show" data-each="filters.value key=id"></div>
|
|
85
87
|
<span data-help-title="The report" data-help="Every item of the export and what happened to it. Kept as HTML: the page had tables, columns or other layout Markdown cannot say - it shows as it did, and edits as HTML. Needs rebuilding: shortcodes and page builders this site has no equivalent for. Right-click (or \u22EE, or Shift+F10) an item to open it."></span></div>
|
|
86
88
|
<p class="wpx-note" data-bind-hidden="rows.value.length">Nothing matches.</p>
|
|
@@ -90,4 +92,4 @@ import{apiRequest as C,getToken as Za}from"../api.js";import{addBannerAction as
|
|
|
90
92
|
<div class="wpx-list wpx-report-people" data-each="people.value key=key"></div>
|
|
91
93
|
<div class="wpx-card-title" data-bind-hidden="!redirects.value.length">Redirects</div>
|
|
92
94
|
<div class="wpx-list wpx-report-redirects" data-each="redirects.value key=from"></div>
|
|
93
|
-
</div>`);s.querySelector(".wpx-tiles").innerHTML=Dt,s.querySelector(".wpx-note-list").innerHTML=Ut,s.querySelector(".wpx-seg").innerHTML=Be,s.querySelector(".wpx-report-items").innerHTML=Nt,s.querySelector(".wpx-report-redirects").innerHTML=Ot,s.querySelector(".wpx-report-people").innerHTML=Ss;const r=M.observable(t.run?.summary?.failed?"failed":"all"),d=t.items||[],ft=Et(d,Rt,qt),N=t.run?.summary||{},De=o=>Object.values(N.kinds||{}).reduce((n,x)=>n+(x[o]||0),0),Na={meta:M.observable([ee(t.run?.at),t.run?.by,t.run?.file,t.run?.durationMs?`${Math.max(1,Math.round(t.run.durationMs/1e3))} s`:""].filter(Boolean).join(" \xB7 ")),tiles:M.observable([{id:"made",label:"Made",value:De("created"),sub:""},{id:"updated",label:"Updated",value:De("updated"),sub:""},{id:"kept",label:"Left as is",value:De("kept"),sub:""},{id:"redirects",label:"Redirects",value:(N.redirects?.created||0)+(N.redirects?.updated||0),sub:""},...N.people?[{id:"people",label:"Accounts made",value:N.people.created||0,sub:N.people.invited?`${N.people.invited} emailed`:""}]:[],{id:"comments",label:"Comments",value:N.comments||0,sub:""},{id:"failed",label:"Failed",value:N.failed||0,sub:""}]),notes:M.observable((t.notes||[]).map(o=>({text:o}))),people:M.observable((t.people||[]).map(ns)),filters:M.computed(()=>Rt.filter(o=>o.id==="all"||ft[o.id]).map(o=>({...o,count:ft[o.id],cls:r.value===o.id?"is-on":""}))),rows:M.computed(()=>d.filter(o=>qt(o,r.value)).slice(0,1e3).map(o=>{const n=vs(o);return{...n,pillCls:n.pillClass}})),redirects:M.observable((t.redirects||[]).filter(o=>o.result!=="skipped").slice(0,1e3).map(o=>({...o,reason:o.error||"",pill:o.result==="failed"?"Failed":o.result==="updated"?"Updated":"Added",pillClass:o.result==="failed"?"is-bad":"is-ok"})))};a.element.appendChild(s);const Oa=M.applyBindings(Na,s,{methods:{pickSeg:o=>{r.value=o.id}}}),Da=yt(s),bt=new Map(d.map(o=>[o.key,o])),Ua=s.querySelector(".wpx-report-items"),Ha=o=>{const n=bt.get(o.dataset.key);if(!n)return[];const x=typeof n.target=="string"&&n.target.startsWith("/")?n.target:"",L=[{header:n.title}];if(x&&n.result!=="failed"&&n.result!=="skipped"&&L.push({label:"Open on the site",icon:"external-link",action:()=>window.open(x,"_blank","noopener")}),x&&(n.kind==="page"||n.kind==="custom"&&!n.collection)&&(n.result==="created"||n.result==="updated"||n.result==="kept")&&L.push({label:"Edit the page",icon:"edit",action:()=>{a.close(),location.hash=`#/pages/edit${x}`}}),n.kind==="widgets"&&/^[a-z0-9][a-z0-9-]{0,79}$/.test(n.target||"")&&["created","updated","kept"].includes(n.result)&&(L.push({label:"Edit the block",icon:"edit",action:()=>{a.close(),location.hash=`#/blocks/edit/${n.target}`}}),n.footer&&L.push({label:"Footer settings",icon:"settings",action:()=>{a.close(),location.hash="#/settings"}})),(n.kind==="collection"||n.kind==="custom")&&n.result!=="failed"&&n.result!=="skipped"&&/^[a-z0-9-]{1,80}$/.test(n.kind==="collection"?n.target:n.collection||"")){const Z=n.kind==="collection"?n.target:n.collection;L.push({label:"Open the collection",icon:"database",action:()=>{a.close(),location.hash=`#/collections/${Z}/entries`}})}return n.kind==="product"&&n.entryId&&/^[\w-]{1,64}$/.test(n.entryId)&&L.push({label:"Edit in the Shop",icon:"shopping-bag",action:()=>{a.close(),location.hash=`#/plugins/shopping-cart/products/${encodeURIComponent(n.entryId)}`}}),/^https?:\/\//i.test(n.oldUrl)&&L.push({label:"Open the old address",icon:"link",action:()=>window.open(n.oldUrl,"_blank","noopener,noreferrer")}),x&&L.push({label:"Copy the new address",icon:"copy",action:()=>ze(new URL(x,location.origin).href)}),L},Ba=E.contextMenu(Ua,{cursor:"glyph",match:".wpx-row",inherit:!1,density:"compact",items:Ha}),_a=s.querySelector(".wpx-report-people"),za=new Map((t.people||[]).map(o=>[o.key,o])),ja=E.contextMenu(_a,{cursor:"glyph",match:".wpx-row",inherit:!1,density:"compact",items:o=>{const n=za.get(o.dataset.key);if(!n)return[];const x=/^[0-9a-f-]{36}$/i.test(n.userId||"")?n.userId:"";return[{header:n.name},...x&&n.result!=="skipped"?[{label:"Open their account",icon:"user",action:()=>{a.close(),location.hash=`#/users/edit/${x}`}}]:[],{label:"Open Users",icon:"users",action:()=>{a.close(),location.hash="#/users"}}]}}),Wa=s.querySelector(".wpx-report-redirects"),Fa=E.contextMenu(Wa,{cursor:"glyph",match:".wpx-row",inherit:!1,density:"compact",items:o=>[{header:o.dataset.from},...o.dataset.from.includes("*")?[]:[{label:"Try it on the site",icon:"external-link",action:()=>window.open(o.dataset.from,"_blank","noopener")}],{label:"Open SEO \u203A Redirects",icon:"corner-up-right",action:()=>{a.close(),location.hash="#/seo/redirects"}}]}),Ue=o=>{const n=o.target.closest(".wpx-kebab");if(n){O(n);return}const x=o.target.closest(".wpx-report-people .wpx-row");if(x){O(x.querySelector(".wpx-kebab")||x);return}const L=o.target.closest(".wpx-report-items .wpx-row");if(!L)return;const Z=bt.get(L.dataset.key);Z?.target?.startsWith("/")&&Z.result!=="failed"&&Z.result!=="skipped"&&window.open(Z.target,"_blank","noopener")},gt=o=>{const n=o.target.closest(".wpx-row");n&&(o.key==="F10"&&o.shiftKey?(o.preventDefault(),O(n)):o.key==="Enter"&&o.target===n&&(o.preventDefault(),o.stopPropagation(),Ue({target:n})))};s.addEventListener("click",Ue),s.addEventListener("keydown",gt);const Ka=f.add(()=>a.close());Ga(a,()=>{F=!1,Oa.dispose(),Da(),Ba?.destroy?.(),Fa?.destroy?.(),ja?.destroy?.(),s.removeEventListener("click",Ue),s.removeEventListener("keydown",gt),Ka()}),a.open(),I.scan(s)}async function Ra(e){const t=B.peek().find(a=>a.id===e);if(t&&await Me(`Remove the import of <strong>${V(t.siteTitle||t.source)}</strong> from this list? Everything it imported stays on the site.`,{title:"Remove from the history",confirmText:"Remove"}))try{if(await C(`${$}/history/${e}`,{method:"DELETE"}),!i())return;B.value=B.peek().filter(a=>a.id!==e),R(re)}catch(a){E.toast(`Not removed: ${a.message||a}`,{type:"error"})}}l.querySelector(".wpx-staged").innerHTML=Ts,l.querySelector(".wpx-items").innerHTML=Nt,l.querySelector(".wpx-redirects").innerHTML=Ot,l.querySelector(".wpx-history").innerHTML=Es,l.querySelector(".wpx-tiles").innerHTML=Dt,l.querySelector(".wpx-note-list").innerHTML=Ut,l.querySelector(".wpx-kinds").innerHTML=Be,l.querySelector(".wpx-filters").innerHTML=Be,l.querySelector(".wpx-facts").innerHTML=Cs,l.querySelector(".wpx-product-notes").innerHTML=Ht,l.querySelector(".wpx-types").innerHTML=$s,l.querySelector(".wpx-internal").innerHTML=Ht,l.querySelector(".wpx-people-list").innerHTML=Ls,l.querySelector(".wpx-widget-areas").innerHTML=Ps;const qa={mode:Bt,job:y,jobTitle:Ma,jobText:Ta,jobPct:Je,staged:p,stagedRows:zt,historyRows:jt,plan:g,planLoading:ie,planError:Ee,refreshing:Te,opt:c,blogAvailable:U,blogNote:ba,dirty:Fe,canRun:Ge,siteTitle:ea,siteMeta:ta,tiles:Jt,notes:Yt,kinds:Wt,filters:Kt,rows:Zt,moreText:Vt,emptyText:Gt,redirectRows:Xt,redirectCount:Qt,query:J,uploadText:ce,uploadError:Y,dropping:de,wxrLimit:Ea,zipInfo:me,zipText:ga,zipButton:ya,zipUploadText:pe,hasPeople:ca,peopleRows:pa,peopleCanCreate:da,peopleChoosable:ua,peopleNote:ma,peopleNoteCls:ha,inviteAvailable:wa,inviteText:va,optInvite:fa,shopAvailable:_t,hasProducts:la,productNote:aa,productNoteCls:sa,productFacts:oa,productNotes:na,typeRows:Le,internalRows:Se,hasCustom:ra,internalSummary:ia,widgetsInfo:Ze,widgetsText:xa,widgetsButton:ka,widgetsUploadText:Pe,widgetRows:Ve,optComments:Q("comments"),optMenus:Q("menus"),optRedirects:Q("redirects"),optDrafts:Q("drafts"),optProducts:Q("products")},Aa=M.applyBindings(qa,l,{methods:{back:()=>ae(),discard:()=>Xe(),run:()=>Ca(),resetChoices:()=>{c.value=He(U.peek())},postsBlog:()=>P({posts:"blog"}),postsPages:()=>P({posts:"pages"}),postsSkip:()=>P({posts:"skip"}),mediaDownload:()=>P({media:"download"}),mediaZip:()=>P({media:"zip"}),mediaSkip:()=>P({media:"skip"}),removeZip:()=>Pa(),removeWidgets:()=>Sa(),peopleAll:()=>P({users:Mt(T.peek(),"create")}),peopleNone:()=>P({users:Mt(T.peek(),"skip")}),pickSeg:e=>{e.seg==="kind"?D.value=e.id:z.value=e.id},showProducts:()=>{D.value="product",z.value="all",J.value="",l.querySelector(".wpx-items")?.closest(".wpx-card")?.scrollIntoView({behavior:"smooth",block:"start"})}}});f.add(()=>Aa.dispose()),f.add(yt(l,{position:"bottom"}));const oe=l.querySelector(".wpx-file"),et=()=>{const e=oe.files?.[0];oe.value="",Qe(e)};oe.addEventListener("change",et);const K=l.querySelector(".wpx-drop"),tt=e=>{e.preventDefault(),de.value=!0},at=()=>{de.value=!1},st=e=>{e.preventDefault(),de.value=!1,Qe(e.dataTransfer?.files?.[0])};K.addEventListener("dragover",tt),K.addEventListener("dragleave",at),K.addEventListener("drop",st);const be=l.querySelector(".wpx-zip-file"),ot=()=>{const e=be.files?.[0];be.value="",$a(e)};be.addEventListener("change",ot);const ge=l.querySelector(".wpx-wie-file"),nt=()=>{const e=ge.files?.[0];ge.value="",La(e)};ge.addEventListener("change",nt),f.add(()=>ge.removeEventListener("change",nt)),f.add(()=>{oe.removeEventListener("change",et),K.removeEventListener("dragover",tt),K.removeEventListener("dragleave",at),K.removeEventListener("drop",st),be.removeEventListener("change",ot)}),H(l.querySelector(".wpx-staged"),".wpx-row",e=>[{header:p.peek().find(t=>t.id===e.dataset.id)?.siteTitle||"Upload"},{label:"Preview the import",icon:"eye",action:()=>ve(e.dataset.id)},{label:"Discard the upload",icon:"trash-2",action:()=>Xe(e.dataset.id)}],e=>ve(e.dataset.id));const lt=(e,t)=>{c.value={...c.peek(),choices:Xa(c.peek().choices,e,t)}};H(l.querySelector(".wpx-items"),".wpx-row",e=>{const t=j.peek().find(s=>s.key===e.dataset.key);if(!t)return[];const a=[{header:t.title}];for(const s of Tt(t,t.choice))a.push({label:s.label,icon:s.icon,action:()=>lt(t.key,s.id)});return t.oldUrl&&/^https?:\/\//i.test(t.oldUrl)&&a.push({label:"Open the old address",icon:"link",action:()=>window.open(t.oldUrl,"_blank","noopener,noreferrer")}),t.target?.startsWith("/")&&(t.action==="update"||t.action==="keep")&&a.push({label:"Open it on this site",icon:"external-link",action:()=>window.open(t.target,"_blank","noopener")}),a.length===1&&a.push({label:"Nothing to change here",icon:"info",disabled:!0,action:()=>{}}),a},e=>O(e.querySelector(".wpx-kebab")||e));const rt=(e,t)=>{c.value=Ms(c.peek(),e,t)},it=(e,t)=>{c.value=ks(c.peek(),e,t)},Ia=e=>{D.value="",z.value="all",J.value=e,l.querySelector(".wpx-items")?.closest(".wpx-card")?.scrollIntoView({behavior:"smooth",block:"start"})},ne=l.querySelector(".wpx-types"),ct=e=>{if(!e.target.closest(".wpx-type-ctl"))return;e.stopPropagation();const a=e.target.closest("button[data-as]"),s=e.target.closest(".wpx-type-row");a&&s&&rt(s.dataset.type,a.dataset.as)},pt=e=>{const t=e.target.closest("input[data-list-page]"),a=e.target.closest(".wpx-type-row");t&&a&&it(a.dataset.type,t.checked)};ne.addEventListener("click",ct,!0),ne.addEventListener("change",pt),f.add(()=>{ne.removeEventListener("click",ct,!0),ne.removeEventListener("change",pt)}),H(ne,".wpx-type-row",e=>{const t=Le.peek().find(a=>a.type===e.dataset.type);return t?[{header:`${t.label} ("${t.type}")`},...bs(t).map(a=>({label:a.label,icon:a.icon,action:()=>{a.id==="show"?Ia(t.type):a.id==="list"||a.id==="nolist"?it(t.type,a.id==="list"):rt(t.type,a.id)}}))]:[]},e=>O(e.querySelector(".wpx-kebab")||e));const Ie=(e,t)=>{c.value=xs(c.peek(),e,t)},le=l.querySelector(".wpx-widget-areas"),dt=e=>{e.target.closest(".wpx-type-ctl")&&e.stopPropagation()},ut=e=>{const t=e.target.closest("input[data-footer]"),a=e.target.closest(".wpx-widget-row");t&&a&&Ie(a.dataset.area,t.checked)};le.addEventListener("click",dt,!0),le.addEventListener("change",ut),f.add(()=>{le.removeEventListener("click",dt,!0),le.removeEventListener("change",ut)}),H(le,".wpx-widget-row",e=>{const t=Ve.peek().find(r=>r.area===e.dataset.area),a=j.peek().find(r=>r.key===`widgets:${e.dataset.area}`);if(!t)return[];const s=[{header:`${t.label} ("${t.area}")`}];if(t.canPlace&&s.push(t.placeOn?{label:"Leave it out of the footer",icon:"eye-off",action:()=>Ie(t.area,!1)}:{label:"Place in the footer",icon:"layout",action:()=>Ie(t.area,!0)}),a)for(const r of Tt(a,a.choice))s.push({label:r.label,icon:r.icon,action:()=>lt(a.key,r.id)});return s.length===1&&s.push({label:"Nothing to change here",icon:"info",disabled:!0,action:()=>{}}),s},e=>O(e.querySelector(".wpx-kebab")||e));const mt=(e,t)=>{const a=T.peek()?.rows?.find(s=>s.key===e);a&&P({users:Qa(c.peek().users,a,t)})},Ne=l.querySelector(".wpx-people-list"),ht=e=>{if(!e.target.closest(".wpx-type-ctl"))return;e.stopPropagation();const a=e.target.closest("button[data-user]"),s=e.target.closest(".wpx-person");a&&s&&mt(s.dataset.key,a.dataset.user)};Ne.addEventListener("click",ht,!0),f.add(()=>Ne.removeEventListener("click",ht,!0)),H(Ne,".wpx-person",e=>{const t=T.peek()?.rows?.find(a=>a.key===e.dataset.key);return t?[{header:t.name},...ss(t).map(a=>({label:a.label,icon:a.icon,disabled:!!a.disabled,action:()=>{a.disabled||(a.id==="copy"?ze(t.email):mt(t.key,a.id))}}))]:[]},e=>O(e.querySelector(".wpx-kebab")||e));const A=l.querySelector(".wpx-role");f.add(M.effect(()=>{const e=T.value;if(!A)return;const t=e?.roles||[],a=e?.role||"",s=`${t.map(r=>r.name).join(",")}|${a}`;A.dataset.sig!==s&&(A.dataset.sig=s,A.replaceChildren(...t.map(r=>{const d=document.createElement("option");return d.value=r.name,d.textContent=r.name===We?`${r.label} (default)`:r.label,d})),A.value=a)}));const wt=()=>P({userRole:A.value===We?"":A.value});A?.addEventListener("change",wt),f.add(()=>A?.removeEventListener("change",wt)),H(l.querySelector(".wpx-redirects"),".wpx-row",e=>[{header:e.dataset.from},{label:"Copy the old address",icon:"copy",action:()=>ze(e.dataset.from)}],null),H(l.querySelector(".wpx-history"),".wpx-row",e=>[{header:B.peek().find(t=>t.id===e.dataset.id)?.siteTitle||"Import"},{label:"Open the report",icon:"file-text",action:()=>fe(e.dataset.id)},{label:"Remove from the history",icon:"trash-2",action:()=>Ra(e.dataset.id)}],e=>fe(e.dataset.id)),Va(u,{id:"wpx-upload",icon:"upload",title:"Upload an export",onClick:()=>{h.peek()&&ae(),setTimeout(()=>oe.click(),0)}}),I.scan(l);const Oe=$t(w(),p.peek().map(e=>e.id),b);Oe.pruned&&k&&q({owner:b,items:Oe.items});const vt=Object.entries(Oe.items).sort((e,t)=>String(t[1].at).localeCompare(String(e[1].at)))[0];vt&&!y.peek()&&await ve(vt[0])}};
|
|
95
|
+
</div>`);o.querySelector(".wpx-tiles").innerHTML=zt,o.querySelector(".wpx-note-list").innerHTML=ze,o.querySelector(".wpx-seg").innerHTML=je,o.querySelector(".wpx-report-items").innerHTML=Ut,o.querySelector(".wpx-report-redirects").innerHTML=_t,o.querySelector(".wpx-report-people").innerHTML=Vo;const r=M.observable(t.run?.summary?.failed?"failed":"all"),c=/^\/[a-z0-9][a-z0-9/-]{0,200}$/.test(t.home?.previous||"")?t.home.previous:"",De=t.items||[],kt=Ct(De,Ot,Bt),O=t.run?.summary||{},He=s=>Object.values(O.kinds||{}).reduce((n,k)=>n+(k[s]||0),0),Xa={meta:M.observable([te(t.run?.at),t.run?.by,t.run?.file,t.run?.durationMs?`${Math.max(1,Math.round(t.run.durationMs/1e3))} s`:""].filter(Boolean).join(" \xB7 ")),tiles:M.observable([{id:"made",label:"Made",value:He("created"),sub:""},{id:"updated",label:"Updated",value:He("updated"),sub:""},{id:"kept",label:"Left as is",value:He("kept"),sub:""},{id:"redirects",label:"Redirects",value:(O.redirects?.created||0)+(O.redirects?.updated||0),sub:""},...O.people?[{id:"people",label:"Accounts made",value:O.people.created||0,sub:O.people.invited?`${O.people.invited} emailed`:""}]:[],{id:"comments",label:"Comments",value:O.comments||0,sub:""},{id:"failed",label:"Failed",value:O.failed||0,sub:""}]),notes:M.observable((t.notes||[]).map(s=>({text:s}))),homePrevious:M.observable(c),homePreviousText:M.observable(c?`This site's home page from before the import${t.home?.previousTitle?` ("${t.home.previousTitle}")`:""} is now a draft at ${c} - nothing was deleted. Publish it there, or delete it, from Pages.`:""),people:M.observable((t.people||[]).map(Eo)),filters:M.computed(()=>Ot.filter(s=>s.id==="all"||kt[s.id]).map(s=>({...s,count:kt[s.id],cls:r.value===s.id?"is-on":""}))),rows:M.computed(()=>De.filter(s=>Bt(s,r.value)).slice(0,1e3).map(s=>{const n=Oo(s);return{...n,pillCls:n.pillClass}})),redirects:M.observable((t.redirects||[]).filter(s=>s.result!=="skipped").slice(0,1e3).map(s=>({...s,reason:s.error||"",pill:s.result==="failed"?"Failed":s.result==="updated"?"Updated":"Added",pillClass:s.result==="failed"?"is-bad":"is-ok"})))};a.element.appendChild(o);const eo=M.applyBindings(Xa,o,{methods:{pickSeg:s=>{r.value=s.id}}}),to=Et(o),Mt=new Map(De.map(s=>[s.key,s])),ao=o.querySelector(".wpx-report-items"),oo=s=>{const n=Mt.get(s.dataset.key);if(!n)return[];const k=typeof n.target=="string"&&n.target.startsWith("/")?n.target:"",C=[{header:n.title}];if(k&&n.result!=="failed"&&n.result!=="skipped"&&C.push({label:"Open on the site",icon:"external-link",action:()=>window.open(k,"_blank","noopener")}),k&&(n.kind==="page"||n.kind==="custom"&&!n.collection)&&(n.result==="created"||n.result==="updated"||n.result==="kept")&&C.push({label:"Edit the page",icon:"edit",action:()=>{a.close(),location.hash=`#/pages/edit${k}`}}),n.kind==="widgets"&&/^[a-z0-9][a-z0-9-]{0,79}$/.test(n.target||"")&&["created","updated","kept"].includes(n.result)&&(C.push({label:"Edit the block",icon:"edit",action:()=>{a.close(),location.hash=`#/blocks/edit/${n.target}`}}),n.footer&&C.push({label:"Footer settings",icon:"settings",action:()=>{a.close(),location.hash="#/settings"}})),(n.kind==="collection"||n.kind==="custom")&&n.result!=="failed"&&n.result!=="skipped"&&/^[a-z0-9-]{1,80}$/.test(n.kind==="collection"?n.target:n.collection||"")){const Y=n.kind==="collection"?n.target:n.collection;C.push({label:"Open the collection",icon:"database",action:()=>{a.close(),location.hash=`#/collections/${Y}/entries`}})}return n.kind==="product"&&n.entryId&&/^[\w-]{1,64}$/.test(n.entryId)&&C.push({label:"Edit in the Shop",icon:"shopping-bag",action:()=>{a.close(),location.hash=`#/plugins/shopping-cart/products/${encodeURIComponent(n.entryId)}`}}),/^https?:\/\//i.test(n.oldUrl)&&C.push({label:"Open the old address",icon:"link",action:()=>window.open(n.oldUrl,"_blank","noopener,noreferrer")}),k&&C.push({label:"Copy the new address",icon:"copy",action:()=>Fe(new URL(k,location.origin).href)}),C},so=E.contextMenu(ao,{cursor:"glyph",match:".wpx-row",inherit:!1,density:"compact",items:oo}),no=o.querySelector(".wpx-report-people"),lo=new Map((t.people||[]).map(s=>[s.key,s])),ro=E.contextMenu(no,{cursor:"glyph",match:".wpx-row",inherit:!1,density:"compact",items:s=>{const n=lo.get(s.dataset.key);if(!n)return[];const k=/^[0-9a-f-]{36}$/i.test(n.userId||"")?n.userId:"";return[{header:n.name},...k&&n.result!=="skipped"?[{label:"Open their account",icon:"user",action:()=>{a.close(),location.hash=`#/users/edit/${k}`}}]:[],{label:"Open Users",icon:"users",action:()=>{a.close(),location.hash="#/users"}}]}}),io=o.querySelector(".wpx-report-redirects"),po=E.contextMenu(io,{cursor:"glyph",match:".wpx-row",inherit:!1,density:"compact",items:s=>[{header:s.dataset.from},...s.dataset.from.includes("*")?[]:[{label:"Try it on the site",icon:"external-link",action:()=>window.open(s.dataset.from,"_blank","noopener")}],{label:"Open SEO \u203A Redirects",icon:"corner-up-right",action:()=>{a.close(),location.hash="#/seo/redirects"}}]}),Ue=s=>{if(s.target.closest(".wpx-open-previous")&&c){a.close(),location.hash=`#/pages/edit${c}`;return}const n=s.target.closest(".wpx-kebab");if(n){B(n);return}const k=s.target.closest(".wpx-report-people .wpx-row");if(k){B(k.querySelector(".wpx-kebab")||k);return}const C=s.target.closest(".wpx-report-items .wpx-row");if(!C)return;const Y=Mt.get(C.dataset.key);Y?.target?.startsWith("/")&&Y.result!=="failed"&&Y.result!=="skipped"&&window.open(Y.target,"_blank","noopener")},Tt=s=>{const n=s.target.closest(".wpx-row");n&&(s.key==="F10"&&s.shiftKey?(s.preventDefault(),B(n)):s.key==="Enter"&&s.target===n&&(s.preventDefault(),s.stopPropagation(),Ue({target:n})))};o.addEventListener("click",Ue),o.addEventListener("keydown",Tt);const co=b.add(()=>a.close());ho(a,()=>{Z=!1,eo.dispose(),to(),so?.destroy?.(),po?.destroy?.(),ro?.destroy?.(),o.removeEventListener("click",Ue),o.removeEventListener("keydown",Tt),co()}),a.open(),I.scan(o)}async function Ya(e){const t=_.peek().find(a=>a.id===e);if(t&&await Te(`Remove the import of <strong>${G(t.siteTitle||t.source)}</strong> from this list? Everything it imported stays on the site.`,{title:"Remove from the history",confirmText:"Remove"}))try{if(await R(`${P}/history/${e}`,{method:"DELETE"}),!p())return;_.value=_.peek().filter(a=>a.id!==e),q(ie)}catch(a){E.toast(`Not removed: ${a.message||a}`,{type:"error"})}}l.querySelector(".wpx-staged").innerHTML=Wo,l.querySelector(".wpx-items").innerHTML=Ut,l.querySelector(".wpx-redirects").innerHTML=_t,l.querySelector(".wpx-history").innerHTML=Fo,l.querySelector(".wpx-tiles").innerHTML=zt,l.querySelector(".wpx-note-list").innerHTML=ze,l.querySelector(".wpx-home-notes").innerHTML=ze,l.querySelector(".wpx-kinds").innerHTML=je,l.querySelector(".wpx-filters").innerHTML=je,l.querySelector(".wpx-facts").innerHTML=Go,l.querySelector(".wpx-product-notes").innerHTML=jt,l.querySelector(".wpx-types").innerHTML=Ko,l.querySelector(".wpx-internal").innerHTML=jt,l.querySelector(".wpx-people-list").innerHTML=Zo,l.querySelector(".wpx-widget-areas").innerHTML=Yo;const Ga={mode:Wt,job:y,jobTitle:_a,jobText:za,jobPct:tt,staged:d,stagedRows:Kt,historyRows:Zt,plan:f,planLoading:pe,planError:$e,refreshing:Ee,opt:i,blogAvailable:H,blogNote:Na,dirty:Ve,canRun:et,siteTitle:sa,siteMeta:na,tiles:ea,notes:ta,kinds:Vt,filters:Gt,rows:Jt,moreText:Qt,emptyText:Xt,redirectRows:aa,redirectCount:oa,query:Q,uploadText:ce,uploadError:X,dropping:ue,wxrLimit:ja,zipInfo:he,zipText:Oa,zipButton:Ba,zipUploadText:de,hasPeople:$a,peopleRows:Sa,peopleCanCreate:La,peopleChoosable:Pa,peopleNote:Ca,peopleNoteCls:Ra,inviteAvailable:qa,inviteText:Aa,optInvite:Ia,shopAvailable:Ft,hasProducts:ca,productNote:la,productNoteCls:ra,productFacts:ia,productNotes:pa,typeRows:Le,internalRows:Pe,hasCustom:Ta,internalSummary:Ea,widgetsInfo:Qe,widgetsText:Da,widgetsButton:Ha,widgetsUploadText:Ce,widgetRows:Xe,hasHome:da,homeWp:ua,homeNow:ma,homeAfter:ha,homeAfterCls:va,homeNotes:wa,homeEdit:fa,homeFrontSwitch:ba,homeLatestSwitch:ga,homePostsSwitch:ya,homePostsText:xa,homeQuestion:Ye,runWhy:Ua,optHome:W("home"),optLatest:ka,optPostsPage:Ma,optComments:W("comments"),optMenus:W("menus"),optRedirects:W("redirects"),optDrafts:W("drafts"),optProducts:W("products")},Ja=M.applyBindings(Ga,l,{methods:{back:()=>oe(),discard:()=>ot(),run:()=>Va(),resetChoices:()=>{i.value=_e(H.peek())},postsBlog:()=>$({posts:"blog"}),postsPages:()=>$({posts:"pages"}),postsSkip:()=>$({posts:"skip"}),mediaDownload:()=>$({media:"download"}),mediaZip:()=>$({media:"zip"}),mediaSkip:()=>$({media:"skip"}),homeYes:()=>$({homeReplace:!0}),homeNo:()=>$({homeReplace:!1}),removeZip:()=>Za(),removeWidgets:()=>Ka(),peopleAll:()=>$({users:Lt(L.peek(),"create")}),peopleNone:()=>$({users:Lt(L.peek(),"skip")}),pickSeg:e=>{e.seg==="kind"?D.value=e.id:j.value=e.id},showProducts:()=>{D.value="product",j.value="all",Q.value="",l.querySelector(".wpx-items")?.closest(".wpx-card")?.scrollIntoView({behavior:"smooth",block:"start"})}}});b.add(()=>Ja.dispose()),b.add(Et(l,{position:"bottom"}));const ne=l.querySelector(".wpx-file"),nt=()=>{const e=ne.files?.[0];ne.value="",st(e)};ne.addEventListener("change",nt);const V=l.querySelector(".wpx-drop"),lt=e=>{e.preventDefault(),ue.value=!0},rt=()=>{ue.value=!1},it=e=>{e.preventDefault(),ue.value=!1,st(e.dataTransfer?.files?.[0])};V.addEventListener("dragover",lt),V.addEventListener("dragleave",rt),V.addEventListener("drop",it);const ge=l.querySelector(".wpx-zip-file"),pt=()=>{const e=ge.files?.[0];ge.value="",Wa(e)};ge.addEventListener("change",pt);const ye=l.querySelector(".wpx-wie-file"),ct=()=>{const e=ye.files?.[0];ye.value="",Fa(e)};ye.addEventListener("change",ct),b.add(()=>ye.removeEventListener("change",ct)),b.add(()=>{ne.removeEventListener("change",nt),V.removeEventListener("dragover",lt),V.removeEventListener("dragleave",rt),V.removeEventListener("drop",it),ge.removeEventListener("change",pt)}),U(l.querySelector(".wpx-staged"),".wpx-row",e=>[{header:d.peek().find(t=>t.id===e.dataset.id)?.siteTitle||"Upload"},{label:"Preview the import",icon:"eye",action:()=>fe(e.dataset.id)},{label:"Discard the upload",icon:"trash-2",action:()=>ot(e.dataset.id)}],e=>fe(e.dataset.id));const dt=(e,t)=>{i.value={...i.peek(),choices:fo(i.peek().choices,e,t)}};U(l.querySelector(".wpx-items"),".wpx-row",e=>{const t=F.peek().find(o=>o.key===e.dataset.key);if(!t)return[];const a=[{header:t.title}];for(const o of Pt(t,t.choice))a.push({label:o.label,icon:o.icon,action:()=>dt(t.key,o.id)});return t.oldUrl&&/^https?:\/\//i.test(t.oldUrl)&&a.push({label:"Open the old address",icon:"link",action:()=>window.open(t.oldUrl,"_blank","noopener,noreferrer")}),t.target?.startsWith("/")&&(t.action==="update"||t.action==="keep")&&a.push({label:"Open it on this site",icon:"external-link",action:()=>window.open(t.target,"_blank","noopener")}),a.length===1&&a.push({label:"Nothing to change here",icon:"info",disabled:!0,action:()=>{}}),a},e=>B(e.querySelector(".wpx-kebab")||e));const ut=(e,t)=>{i.value=jo(i.peek(),e,t)},mt=(e,t)=>{i.value=zo(i.peek(),e,t)},Qa=e=>{D.value="",j.value="all",Q.value=e,l.querySelector(".wpx-items")?.closest(".wpx-card")?.scrollIntoView({behavior:"smooth",block:"start"})},le=l.querySelector(".wpx-types"),ht=e=>{if(!e.target.closest(".wpx-type-ctl"))return;e.stopPropagation();const a=e.target.closest("button[data-as]"),o=e.target.closest(".wpx-type-row");a&&o&&ut(o.dataset.type,a.dataset.as)},vt=e=>{const t=e.target.closest("input[data-list-page]"),a=e.target.closest(".wpx-type-row");t&&a&&mt(a.dataset.type,t.checked)};le.addEventListener("click",ht,!0),le.addEventListener("change",vt),b.add(()=>{le.removeEventListener("click",ht,!0),le.removeEventListener("change",vt)}),U(le,".wpx-type-row",e=>{const t=Le.peek().find(a=>a.type===e.dataset.type);return t?[{header:`${t.label} ("${t.type}")`},...Do(t).map(a=>({label:a.label,icon:a.icon,action:()=>{a.id==="show"?Qa(t.type):a.id==="list"||a.id==="nolist"?mt(t.type,a.id==="list"):ut(t.type,a.id)}}))]:[]},e=>B(e.querySelector(".wpx-kebab")||e));const Ne=(e,t)=>{i.value=_o(i.peek(),e,t)},re=l.querySelector(".wpx-widget-areas"),wt=e=>{e.target.closest(".wpx-type-ctl")&&e.stopPropagation()},ft=e=>{const t=e.target.closest("input[data-footer]"),a=e.target.closest(".wpx-widget-row");t&&a&&Ne(a.dataset.area,t.checked)};re.addEventListener("click",wt,!0),re.addEventListener("change",ft),b.add(()=>{re.removeEventListener("click",wt,!0),re.removeEventListener("change",ft)}),U(re,".wpx-widget-row",e=>{const t=Xe.peek().find(r=>r.area===e.dataset.area),a=F.peek().find(r=>r.key===`widgets:${e.dataset.area}`);if(!t)return[];const o=[{header:`${t.label} ("${t.area}")`}];if(t.canPlace&&o.push(t.placeOn?{label:"Leave it out of the footer",icon:"eye-off",action:()=>Ne(t.area,!1)}:{label:"Place in the footer",icon:"layout",action:()=>Ne(t.area,!0)}),a)for(const r of Pt(a,a.choice))o.push({label:r.label,icon:r.icon,action:()=>dt(a.key,r.id)});return o.length===1&&o.push({label:"Nothing to change here",icon:"info",disabled:!0,action:()=>{}}),o},e=>B(e.querySelector(".wpx-kebab")||e));const bt=(e,t)=>{const a=L.peek()?.rows?.find(o=>o.key===e);a&&$({users:bo(i.peek().users,a,t)})},Oe=l.querySelector(".wpx-people-list"),gt=e=>{if(!e.target.closest(".wpx-type-ctl"))return;e.stopPropagation();const a=e.target.closest("button[data-user]"),o=e.target.closest(".wpx-person");a&&o&&bt(o.dataset.key,a.dataset.user)};Oe.addEventListener("click",gt,!0),b.add(()=>Oe.removeEventListener("click",gt,!0)),U(Oe,".wpx-person",e=>{const t=L.peek()?.rows?.find(a=>a.key===e.dataset.key);return t?[{header:t.name},...Mo(t).map(a=>({label:a.label,icon:a.icon,disabled:!!a.disabled,action:()=>{a.disabled||(a.id==="copy"?Fe(t.email):bt(t.key,a.id))}}))]:[]},e=>B(e.querySelector(".wpx-kebab")||e));const N=l.querySelector(".wpx-role");b.add(M.effect(()=>{const e=L.value;if(!N)return;const t=e?.roles||[],a=e?.role||"",o=`${t.map(r=>r.name).join(",")}|${a}`;N.dataset.sig!==o&&(N.dataset.sig=o,N.replaceChildren(...t.map(r=>{const c=document.createElement("option");return c.value=r.name,c.textContent=r.name===Ze?`${r.label} (default)`:r.label,c})),N.value=a)}));const yt=()=>$({userRole:N.value===Ze?"":N.value});N?.addEventListener("change",yt),b.add(()=>N?.removeEventListener("change",yt)),U(l.querySelector(".wpx-redirects"),".wpx-row",e=>[{header:e.dataset.from},{label:"Copy the old address",icon:"copy",action:()=>Fe(e.dataset.from)}],null),U(l.querySelector(".wpx-history"),".wpx-row",e=>[{header:_.peek().find(t=>t.id===e.dataset.id)?.siteTitle||"Import"},{label:"Open the report",icon:"file-text",action:()=>be(e.dataset.id)},{label:"Remove from the history",icon:"trash-2",action:()=>Ya(e.dataset.id)}],e=>be(e.dataset.id)),mo(u,{id:"wpx-upload",icon:"upload",title:"Upload an export",onClick:()=>{h.peek()&&oe(),setTimeout(()=>ne.click(),0)}}),I.scan(l);const Be=Rt(v(),d.peek().map(e=>e.id),g);Be.pruned&&T&&A({owner:g,items:Be.items});const xt=Object.entries(Be.items).sort((e,t)=>String(t[1].at).localeCompare(String(e[1].at)))[0];xt&&!y.peek()&&await fe(xt[0])}};
|
package/package.json
CHANGED
|
@@ -128,6 +128,7 @@ export function planForScreen(plan, blog, shop = {}) {
|
|
|
128
128
|
options: plan.options,
|
|
129
129
|
summary: plan.summary,
|
|
130
130
|
people: peopleForScreen(plan.people),
|
|
131
|
+
home: plan.home || null,
|
|
131
132
|
notes: plan.notes,
|
|
132
133
|
items: plan.items.map(r => ({
|
|
133
134
|
key: r.key, kind: r.kind, wpId: r.wpId, title: r.title, action: r.action, reason: r.reason || '',
|
|
@@ -138,7 +139,9 @@ export function planForScreen(plan, blog, shop = {}) {
|
|
|
138
139
|
...(r.kind === 'custom' && {as: r.as || '', postType: r.postType || '', collection: r.collection || '', listAt: r.listAt || ''}),
|
|
139
140
|
...(r.kind === 'collection' && {postType: r.postType || '', fields: r.fields || 0}),
|
|
140
141
|
...(r.kind === 'widgets' && {area: r.area || '', footer: Boolean(r.footer), place: r.place || '', needs: r.needs || '', widgetTypes: r.widgetTypes || []}),
|
|
141
|
-
...(r.listFor && {listFor: r.listFor})
|
|
142
|
+
...(r.listFor && {listFor: r.listFor}),
|
|
143
|
+
...(r.front && {front: true}), ...(r.moveFrom && {moveFrom: r.moveFrom}),
|
|
144
|
+
...(r.homeLatest && {homeLatest: true}), ...(r.postsPage && {postsPage: true}), ...(r.postsIndex && {postsIndex: true})
|
|
142
145
|
})),
|
|
143
146
|
redirects: plan.redirects.map(r => ({from: r.from, to: r.to, action: r.action, reason: r.reason || ''}))
|
|
144
147
|
};
|
|
@@ -282,9 +282,13 @@ export async function setPageFrontmatter(urlPath, patch) {
|
|
|
282
282
|
*
|
|
283
283
|
* @param {string} oldUrlPath
|
|
284
284
|
* @param {string} newUrlPath
|
|
285
|
+
* @param {object} [opts]
|
|
286
|
+
* @param {boolean} [opts.redirect=true] - false: the old address is not to lead to the new one (the home
|
|
287
|
+
* page moved aside - "/" stays the home page), so the SEO Tool adds no redirect and re-aims none
|
|
288
|
+
* @param {string} [opts.source] - who moved it, passed on to listeners
|
|
285
289
|
* @returns {Promise<void>}
|
|
286
290
|
*/
|
|
287
|
-
export async function renamePage(oldUrlPath, newUrlPath) {
|
|
291
|
+
export async function renamePage(oldUrlPath, newUrlPath, {redirect = true, source = ''} = {}) {
|
|
288
292
|
const oldFile = await resolveExistingFilePath(oldUrlPath);
|
|
289
293
|
const newFile = urlPathToFilePath(newUrlPath);
|
|
290
294
|
await fs.mkdir(path.dirname(newFile), { recursive: true });
|
|
@@ -296,7 +300,7 @@ export async function renamePage(oldUrlPath, newUrlPath) {
|
|
|
296
300
|
// Version directory move failure is non-fatal
|
|
297
301
|
}
|
|
298
302
|
// The old URL may be linked from anywhere - the SEO plugin offers a redirect.
|
|
299
|
-
hooks.emit('content:pageRenamed', {from: oldUrlPath, to: newUrlPath});
|
|
303
|
+
hooks.emit('content:pageRenamed', {from: oldUrlPath, to: newUrlPath, ...(redirect === false && {redirect: false}), ...(source && {source})});
|
|
300
304
|
}
|
|
301
305
|
|
|
302
306
|
/**
|