chore(web-ui): rebuild admin SPA against @phlix/ui v0.79.0 (v1.2.2)#524
Conversation
Bumps web-ui's @phlix/ui pin v0.78.0 -> v0.79.0 and regenerates the committed public/assets/app/ bundle, so the deployed server actually serves the plugin configure/lifecycle UX (visible enable errors, secret set/length status, field-help links). Version 1.2.1 -> 1.2.2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Not up to standards ⛔🔴 Issues
|
| Category | Results |
|---|---|
| CodeStyle | 1 minor |
| Complexity | 5 medium |
🟢 Metrics 1669 complexity · 0 duplication
Metric Results Complexity 1669 Duplication 0
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2a99a4aa30
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -0,0 +1,2 @@ | |||
| import{A as e,B as t,D as n,J as r,M as i,_ as ee,c as a,h as o,l as s,m as c,o as l,r as u,s as d,u as f,x as te,xt as p,yt as ne,z as m}from"./runtime-core.esm-bundler-Del-PMg5.js";import{i as re,r as ie,s as ae}from"./runtime-dom.esm-bundler-Bwq0qijf.js";import{n as oe,t as se}from"./Icon-Bd1lZf6E-Bv7comGB.js";import{t as h}from"./Modal-DnGvbsI9-C5Ii3rq7.js";import{n as ce,o as g,s as le}from"./client-DH50wjeq-Bx47DlfG.js";import{t as ue}from"./useToastStore-BDoKlU6N-LhUU0Qm7.js";import{t as _}from"./Button-CnyfCnhY-OTruTKEt.js";import{t as v}from"./Badge-Dq-pYhrz-CAIMOWAu.js";import{t as y}from"./Switch-B9lejr6_-x5ApHDOZ.js";import{t as de}from"./Skeleton-CzU_l53W-DZIXnGks.js";import{t as fe}from"./EmptyState-588Z_81C-BpSzenOt.js";import{t as pe}from"./PageHint-7Giwob0l-C0xibLs-.js";import{g as me,h as he,m as ge}from"./index-BuhIOrml.js";var _e={class:`admin-plugins`,"aria-labelledby":`plugins-heading`},ve={class:`admin-plugins__head`},ye={class:`admin-plugins__head-actions`},be={class:`admin-plugins__sources`,"aria-label":`Catalog sources`},xe=[`href`],Se=[`disabled`,`aria-label`,`onClick`],Ce={key:0,class:`admin-plugins__install-error`,role:`alert`},we={class:`admin-plugins__install-error-body`},Te={key:1,class:`admin-plugins__install-error`,role:`alert`},Ee={class:`admin-plugins__install-error-body`},De={key:2,class:`admin-plugins__skel`},Oe={key:1,class:`admin-plugins__grid`,"aria-label":`Catalog plugins`},ke={class:`admin-plugins__card-head`},Ae={class:`admin-plugins__card-title`},je={class:`admin-plugins__card-badges`},Me={key:0,class:`admin-plugins__card-summary`},Ne={key:1,class:`admin-plugins__card-tags`},Pe={class:`admin-plugins__card-actions`},Fe=[`href`],Ie={key:4,class:`admin-plugins__orphans`,"aria-labelledby":`orphans-heading`},Le={class:`admin-plugins__table`,"aria-label":`Other installed plugins`},Re={class:`admin-plugins__mono`},ze={class:`admin-plugins__actions`},Be={class:`admin-plugins__field`},Ve={class:`admin-plugins__field`},He={key:0,class:`admin-plugins__skel`},Ue={class:`admin-plugins__label`},We={key:0,class:`admin-plugins__req`,"aria-hidden":`true`,title:`Required`},Ge={key:1,class:`admin-plugins__optional`},Ke=[`onUpdate:modelValue`,`type`,`autocomplete`,`placeholder`,`aria-label`,`aria-invalid`],qe={class:`admin-plugins__secret-dots`,"aria-hidden":`true`},Je={key:2,class:`admin-plugins__hint`},Ye={key:3,class:`admin-plugins__hint admin-plugins__default-hint`},Xe=[`href`],Ze={key:5,class:`admin-plugins__error`,role:`alert`},b=oe(ee({__name:`PluginsPage`,props:{client:{}},setup(ee){let oe=ee,b=te(`apiBase`,``),Qe=l(()=>typeof b==`string`?b:b?.value??``),x=new ge(oe.client??new le({baseUrl:Qe.value,tokenStore:new ce})),S=ue(),$e=r([]),C=r(!0),w=r(null);async function et(){C.value=!0,w.value=null;try{$e.value=await x.list()}catch(e){w.value=g(e,`Failed to load plugins.`),S.error(w.value)}finally{C.value=!1}}let T=r({default_source:``,sources:[],catalogs:[],errors:[]}),tt=r(!0);async function E(){tt.value=!0;try{T.value=await x.catalog()}catch(e){S.error(g(e,`Failed to load the plugin catalog.`))}finally{tt.value=!1}}async function D(){await Promise.all([et(),E()])}let O=l(()=>{let e=new Set,t=[];for(let n of T.value.catalogs)for(let r of n.plugins)e.has(r.name)||(e.add(r.name),t.push(r));return t}),nt=l(()=>new Set(O.value.map(e=>e.name))),rt=l(()=>$e.value.filter(e=>!nt.value.has(e.name)));function it(e){let t=e.match(/github\.com[/:]([^/]+\/[^/]+?)(?:\.git)?\/?$/i);if(t)return t[1];try{return new URL(e).host}catch{return e}}function k(e){return{name:e.name,version:``,type:e.type,enabled:e.enabled}}let A=r(!1),j=r(``),at=r(!1);function ot(e){switch(he(e)){case`plugin.url.required`:return`A plugin URL is required.`;case`plugin.url.invalid_scheme`:return`That does not look like a valid plugin URL (use https://…).`;case`plugin.install.failed`:return g(e,`Install failed — the plugin could not be downloaded or read.`);default:return g(e,`Failed to install plugin.`)}}function st(){j.value=``,A.value=!0}function ct(){A.value=!1,j.value=``}let M=r(null);function lt(e){let t=ot(e);M.value=t,S.error(t)}async function ut(){let e=j.value.trim();if(!e){S.error(`A plugin URL is required.`);return}at.value=!0,M.value=null;try{await x.install(e),S.success(`Plugin installed.`),ct(),await D()}catch(e){lt(e)}finally{at.value=!1}}let N=r(null);async function dt(e){if(N.value===null){N.value=e.repo,M.value=null;try{await x.install(e.repo),S.success(`${e.title} installed.`),await D()}catch(e){lt(e)}finally{N.value=null}}}let P=r(!1),F=r(``),ft=r(!1),I=r(null);function pt(){F.value=``,P.value=!0}function mt(){P.value=!1,F.value=``}async function ht(){let e=F.value.trim();if(!e){S.error(`A catalog URL is required.`);return}ft.value=!0;try{await x.addCatalogSource(e),S.success(`Catalog added.`),mt(),await E()}catch(e){let t=he(e);S.error(t===`plugin.catalog.url.invalid`?`That catalog URL is not valid (use an http(s):// URL).`:g(e,`Failed to add catalog.`))}finally{ft.value=!1}}async function gt(e){if(I.value===null){I.value=e;try{await x.removeCatalogSource(e),S.success(`Catalog removed.`),await E()}catch(e){S.error(g(e,`Failed to remove catalog.`))}finally{I.value=null}}}let L=r({}),R=r(!1),z=r(!1),B=r(null),V=r(!1),_t=l(()=>Object.values(L.value).filter(e=>e.update_available).length);function H(e){let t=L.value[e];return t&&t.update_available?t:null}function vt(e){let t={};for(let n of e)n&&typeof n.name==`string`&&n.update_available&&(t[n.name]=n);L.value=t}function yt(e){if(e in L.value){let t={...L.value};delete t[e],L.value=t}}async function bt(){if(!R.value){R.value=!0;try{let e=await x.checkUpdates();vt(e.updates),V.value=e.auto_update;let t=_t.value;S.success(t>0?`${t} update${t===1?``:`s`} available.`:`All plugins are up to date.`)}catch(e){S.error(g(e,`Failed to check for updates.`))}finally{R.value=!1}}}function xt(e){switch(he(e)){case`plugin.update.no_source`:return`This plugin has no update source — reinstall it from a URL to update.`;case`plugin.update.failed`:return g(e,`Update failed — the new version could not be downloaded or read.`);default:return g(e,`Failed to update plugin.`)}}async function St(e){if(B.value===null){B.value=e.name,U.value=null;try{await x.updatePlugin(e.name),S.success(`${e.name} updated.`),yt(e.name),await D()}catch(t){U.value={title:`Couldn't update ${e.name}`,message:xt(t)},S.error(xt(t))}finally{B.value=null}}}async function Ct(){if(!z.value){z.value=!0;try{let e=await x.updateAll();e.failed.length>0?S.error(`${e.updated.length} updated, ${e.failed.length} failed.`):S.success(`${e.updated.length} plugin${e.updated.length===1?``:`s`} updated.`),await D();let t=await x.checkUpdates();vt(t.updates),V.value=t.auto_update}catch(e){S.error(g(e,`Failed to apply updates.`))}finally{z.value=!1}}}async function wt(e){let t=V.value;V.value=e;try{V.value=await x.setAutoUpdate(e),S.success(e?`Auto-update enabled.`:`Auto-update disabled.`)}catch(e){V.value=t,S.error(g(e,`Failed to change auto-update.`))}}let U=r(null);function Tt(e,t,n){let r=g(t,n);U.value={title:e,message:r},S.error(r)}let W=r(null);async function Et(e,t){if(W.value===null){W.value=e.name,U.value=null;try{t?(await x.enable(e.name),S.success(`${e.name} enabled.`)):(await x.disable(e.name),S.success(`${e.name} disabled.`)),await D()}catch(n){Tt(t?`Couldn't enable ${e.name}`:`Couldn't disable ${e.name}`,n,`Failed to update plugin.`)}finally{W.value=null}}}let G=r(null);async function Dt(){let e=G.value;if(e)try{await x.uninstall(e.name),S.success(`${e.name} uninstalled.`),G.value=null,await D()}catch(t){Tt(`Couldn't uninstall ${e.name}`,t,`Failed to uninstall plugin.`),G.value=null}}let K=r(null),q=r(null),Ot=r(!1),J=r(!1),Y=r({}),X=r({}),Z=r({}),kt=l(()=>K.value?`Configure — ${K.value.name}`:`Configure plugin`),At=l(()=>q.value?Object.entries(q.value.settings_schema):[]),jt=l(()=>At.value.length>0);function Mt(e){return e.type===`int`||e.type===`integer`||e.type===`number`||e.type===`float`?`number`:`text`}function Nt(e){return e.type===`bool`||e.type===`boolean`}function Pt(e,t){return Nt(e)?t===!0||t===1||t===`1`||t===`true`:e.secret?``:t??(e.default===void 0?``:e.default)}function Q(e){return q.value?.secret_status?.[e]??null}function Ft(e){return`•`.repeat(Math.max(1,Math.min(e,32)))}function It(e){if(e.secret||!(`default`in e))return null;let t=e.default;return t==null||t===``?null:typeof t==`boolean`?t?`on`:`off`:String(t)}function Lt(e){return e.link_text&&e.link_text.trim()!==``?e.link_text:`Where to get this`}async function Rt(e){K.value=e,q.value=null,Y.value={},X.value={},Z.value={},Ot.value=!0;try{let t=await x.get(e.name);q.value=t;let n={};for(let[e,r]of Object.entries(t.settings_schema))n[e]=Pt(r,t.settings[e]);Y.value=n,X.value={...n}}catch(e){S.error(g(e,`Failed to load plugin settings.`)),K.value=null}finally{Ot.value=!1}}function $(){K.value=null,q.value=null,Y.value={},X.value={},Z.value={}}function zt(){let e={};if(!q.value)return e;for(let[t,n]of Object.entries(q.value.settings_schema)){let r=Y.value[t];if(n.secret){if(r===``||r==null)continue;e[t]=r;continue}r!==X.value[t]&&(Nt(n)?e[t]=r===!0:Mt(n)===`number`?e[t]=r===``||r===null?r:Number(r):e[t]=r)}return e}async function Bt(){let e=K.value;if(!e)return;Z.value={};let t=zt();if(Object.keys(t).length===0){S.success(`No changes to save.`),$();return}J.value=!0;try{await x.updateSettings(e.name,t),S.success(`Settings saved.`),$(),await D()}catch(e){let t=me(e);Object.keys(t).length>0?(Z.value=t,S.error(`Some settings could not be saved — check the highlighted fields.`)):S.error(g(e,`Failed to save settings.`))}finally{J.value=!1}}async function Vt(){try{V.value=await x.getAutoUpdate()}catch{}}return n(()=>{et(),E(),Vt()}),(n,r)=>(e(),f(`section`,_e,[d(`header`,ve,[r[12]||=d(`h1`,{id:`plugins-heading`,class:`admin-plugins__title`},`Plugins`,-1),d(`div`,ye,[o(y,{"model-value":V.value,label:`Auto-update`,"aria-label":`Toggle automatic plugin updates`,"onUpdate:modelValue":wt},null,8,[`model-value`]),r[11]||=d(`span`,{class:`admin-plugins__head-spacer`},null,-1),o(_,{variant:`ghost`,size:`sm`,"left-icon":`rewind`,loading:R.value,onClick:bt},{default:m(()=>[...r[8]||=[c(` Check for updates `,-1)]]),_:1},8,[`loading`]),_t.value>0?(e(),a(_,{key:0,variant:`solid`,size:`sm`,"left-icon":`forward`,loading:z.value,onClick:Ct},{default:m(()=>[c(` Update all (`+p(_t.value)+`) `,1)]),_:1},8,[`loading`])):s(``,!0),o(_,{variant:`ghost`,size:`sm`,"left-icon":`plus`,onClick:pt},{default:m(()=>[...r[9]||=[c(`Add catalog`,-1)]]),_:1}),o(_,{variant:`solid`,size:`sm`,"left-icon":`plus`,onClick:st},{default:m(()=>[...r[10]||=[c(`Install from URL`,-1)]]),_:1})])]),o(pe,null,{default:m(()=>[...r[13]||=[c(` Extend Phlix with add-ons from the plugin catalog. On each catalog plugin, toggle its switch to `,-1),d(`strong`,null,`enable/disable`,-1),c(` it, `,-1),d(`strong`,null,`Install`,-1),c(` or `,-1),d(`strong`,null,`Uninstall`,-1),c(` it, `,-1),d(`strong`,null,`Configure`,-1),c(` its settings, or `,-1),d(`strong`,null,`Update`,-1),c(` when a new version is out. Up top, `,-1),d(`strong`,null,`Check for updates`,-1),c(` refreshes availability, `,-1),d(`strong`,null,`Update all`,-1),c(` upgrades everything at once, `,-1),d(`strong`,null,`Auto-update`,-1),c(` keeps plugins current automatically, and `,-1),d(`strong`,null,`Add catalog`,-1),c(` / `,-1),d(`strong`,null,`Install from URL`,-1),c(` pull in sources or plugins from outside the default catalog. `,-1)]]),_:1}),d(`div`,be,[r[14]||=d(`span`,{class:`admin-plugins__sources-label`},`Catalogs`,-1),(e(!0),f(u,null,i(T.value.sources,t=>(e(),a(v,{key:t,tone:`neutral`},{default:m(()=>[d(`a`,{class:`admin-plugins__source-link`,href:t,target:`_blank`,rel:`noopener noreferrer`},p(it(t)),9,xe),t===T.value.default_source?s(``,!0):(e(),f(`button`,{key:0,type:`button`,class:`admin-plugins__source-remove`,disabled:I.value===t,"aria-label":`Remove catalog ${it(t)}`,onClick:e=>gt(t)},` × `,8,Se))]),_:2},1024))),128))]),M.value?(e(),f(`div`,Ce,[o(se,{name:`alert`,class:`admin-plugins__install-error-icon`}),d(`div`,we,[r[15]||=d(`strong`,null,`Couldn't install the plugin.`,-1),d(`span`,null,p(M.value),1)]),d(`button`,{type:`button`,class:`admin-plugins__install-error-dismiss`,"aria-label":`Dismiss`,onClick:r[0]||=e=>M.value=null},` × `)])):s(``,!0),U.value?(e(),f(`div`,Te,[o(se,{name:`alert`,class:`admin-plugins__install-error-icon`}),d(`div`,Ee,[d(`strong`,null,p(U.value.title)+`.`,1),d(`span`,null,p(U.value.message),1)]),d(`button`,{type:`button`,class:`admin-plugins__install-error-dismiss`,"aria-label":`Dismiss`,onClick:r[1]||=e=>U.value=null},` × `)])):s(``,!0),tt.value?(e(),f(`div`,De,[o(de,{variant:`text`,lines:5})])):(e(),f(u,{key:3},[(e(!0),f(u,null,i(T.value.errors,t=>(e(),f(`p`,{key:t.source,class:`admin-plugins__catalog-error`,role:`alert`},[r[16]||=c(` Couldn't load catalog `,-1),d(`strong`,null,p(it(t.source)),1),c(` — `+p(t.error),1)]))),128)),O.value.length===0&&T.value.errors.length===0?(e(),a(fe,{key:0,icon:`settings`,title:`No plugins in the catalog`,description:`Add a catalog source or install a plugin directly from its URL.`},{actions:m(()=>[o(_,{variant:`solid`,size:`sm`,"left-icon":`plus`,onClick:st},{default:m(()=>[...r[17]||=[c(`Install from URL`,-1)]]),_:1})]),_:1})):(e(),f(`ul`,Oe,[(e(!0),f(u,null,i(O.value,t=>(e(),f(`li`,{key:t.name,class:`admin-plugins__card`},[d(`div`,ke,[d(`h3`,Ae,p(t.title),1),d(`div`,je,[t.type?(e(),a(v,{key:0,tone:`info`},{default:m(()=>[c(p(t.type),1)]),_:2},1024)):s(``,!0),t.installed?(e(),a(v,{key:1,tone:`success`},{default:m(()=>[...r[18]||=[c(`Installed`,-1)]]),_:1})):s(``,!0),H(t.name)?(e(),a(v,{key:2,tone:`warning`,class:`admin-plugins__update-badge`},{default:m(()=>[c(` Update → v`+p(H(t.name)?.latest_version),1)]),_:2},1024)):s(``,!0)])]),t.summary||t.description?(e(),f(`p`,Me,p(t.summary||t.description),1)):s(``,!0),t.tags.length?(e(),f(`div`,Ne,[(e(!0),f(u,null,i(t.tags,t=>(e(),f(`span`,{key:t,class:`admin-plugins__tag`},p(t),1))),128))])):s(``,!0),d(`div`,Pe,[t.installed?(e(),f(u,{key:0},[o(y,{"model-value":t.enabled,label:t.enabled?`Enabled`:`Disabled`,"aria-label":`Toggle ${t.title}`,disabled:W.value===t.name,"onUpdate:modelValue":e=>Et(k(t),e)},null,8,[`model-value`,`label`,`aria-label`,`disabled`,`onUpdate:modelValue`]),r[22]||=d(`span`,{class:`admin-plugins__card-spacer`},null,-1),H(t.name)?(e(),a(_,{key:0,variant:`solid`,size:`sm`,"left-icon":`forward`,loading:B.value===t.name,"aria-label":`Update ${t.title}`,onClick:e=>St(k(t))},{default:m(()=>[...r[19]||=[c(` Update `,-1)]]),_:1},8,[`loading`,`aria-label`,`onClick`])):s(``,!0),o(_,{variant:`ghost`,size:`sm`,"aria-label":`Configure ${t.title}`,onClick:e=>Rt(k(t))},{default:m(()=>[...r[20]||=[c(` Configure `,-1)]]),_:1},8,[`aria-label`,`onClick`]),o(_,{variant:`ghost`,size:`sm`,"aria-label":`Uninstall ${t.title}`,onClick:e=>G.value=k(t)},{default:m(()=>[...r[21]||=[c(` Uninstall `,-1)]]),_:1},8,[`aria-label`,`onClick`])],64)):(e(),f(u,{key:1},[o(_,{variant:`solid`,size:`sm`,"left-icon":`plus`,loading:N.value===t.repo,"aria-label":`Install ${t.title}`,onClick:e=>dt(t)},{default:m(()=>[...r[23]||=[c(` Install `,-1)]]),_:1},8,[`loading`,`aria-label`,`onClick`]),r[24]||=d(`span`,{class:`admin-plugins__card-spacer`},null,-1),d(`a`,{class:`admin-plugins__repo-link`,href:t.repo,target:`_blank`,rel:`noopener noreferrer`},`Repo ↗`,8,Fe)],64))])]))),128))]))],64)),rt.value.length?(e(),f(`section`,Ie,[r[29]||=d(`h2`,{id:`orphans-heading`,class:`admin-plugins__subtitle`},`Other installed plugins`,-1),r[30]||=d(`p`,{class:`admin-plugins__subnote`},`Installed directly from a URL and not listed in any catalog.`,-1),d(`table`,Le,[r[28]||=d(`thead`,null,[d(`tr`,null,[d(`th`,{scope:`col`},`Name`),d(`th`,{scope:`col`},`Version`),d(`th`,{scope:`col`},`Type`),d(`th`,{scope:`col`},`Enabled`),d(`th`,{scope:`col`,class:`admin-plugins__actions-col`},`Actions`)])],-1),d(`tbody`,null,[(e(!0),f(u,null,i(rt.value,t=>(e(),f(`tr`,{key:t.name},[d(`td`,null,p(t.name),1),d(`td`,Re,[c(p(t.version)+` `,1),H(t.name)?(e(),a(v,{key:0,tone:`warning`,class:`admin-plugins__update-badge`},{default:m(()=>[c(` → v`+p(H(t.name)?.latest_version),1)]),_:2},1024)):s(``,!0)]),d(`td`,null,[o(v,{tone:`info`},{default:m(()=>[c(p(t.type),1)]),_:2},1024)]),d(`td`,null,[o(y,{"model-value":t.enabled,label:t.enabled?`Enabled`:`Disabled`,"aria-label":`Toggle ${t.name}`,disabled:W.value===t.name,"onUpdate:modelValue":e=>Et(t,e)},null,8,[`model-value`,`label`,`aria-label`,`disabled`,`onUpdate:modelValue`])]),d(`td`,null,[d(`div`,ze,[H(t.name)?(e(),a(_,{key:0,variant:`solid`,size:`sm`,"left-icon":`forward`,loading:B.value===t.name,"aria-label":`Update ${t.name}`,onClick:e=>St(t)},{default:m(()=>[...r[25]||=[c(` Update `,-1)]]),_:1},8,[`loading`,`aria-label`,`onClick`])):s(``,!0),o(_,{variant:`ghost`,size:`sm`,"aria-label":`Configure ${t.name}`,onClick:e=>Rt(t)},{default:m(()=>[...r[26]||=[c(` Configure `,-1)]]),_:1},8,[`aria-label`,`onClick`]),o(_,{variant:`ghost`,size:`sm`,"aria-label":`Uninstall ${t.name}`,onClick:e=>G.value=t},{default:m(()=>[...r[27]||=[c(` Uninstall `,-1)]]),_:1},8,[`aria-label`,`onClick`])])])]))),128))])])])):s(``,!0),w.value&&!C.value?(e(),a(fe,{key:5,icon:`alert`,title:`Couldn't load installed plugins`,description:w.value},{actions:m(()=>[o(_,{variant:`solid`,size:`sm`,"left-icon":`rewind`,onClick:et},{default:m(()=>[...r[31]||=[c(`Retry`,-1)]]),_:1})]),_:1},8,[`description`])):s(``,!0),o(h,{modelValue:A.value,"onUpdate:modelValue":r[3]||=e=>A.value=e,title:`Install from URL`,onClose:ct},{footer:m(()=>[o(_,{variant:`ghost`,size:`sm`,onClick:ct},{default:m(()=>[...r[34]||=[c(`Cancel`,-1)]]),_:1}),o(_,{variant:`solid`,size:`sm`,loading:at.value,onClick:ut},{default:m(()=>[...r[35]||=[c(`Install`,-1)]]),_:1},8,[`loading`])]),default:m(()=>[d(`form`,{class:`admin-plugins__form`,onSubmit:ae(ut,[`prevent`])},[d(`label`,Be,[r[32]||=d(`span`,{class:`admin-plugins__label`},`Plugin URL`,-1),t(d(`input`,{"onUpdate:modelValue":r[2]||=e=>j.value=e,type:`url`,class:`admin-plugins__input`,autocomplete:`off`,placeholder:`https://github.com/owner/phlix-plugin-name`,required:``},null,512),[[re,j.value]]),r[33]||=d(`span`,{class:`admin-plugins__hint`},` A plugin archive or git repository URL to download and install. `,-1)])],32)]),_:1},8,[`modelValue`]),o(h,{modelValue:P.value,"onUpdate:modelValue":r[5]||=e=>P.value=e,title:`Add catalog`,onClose:mt},{footer:m(()=>[o(_,{variant:`ghost`,size:`sm`,onClick:mt},{default:m(()=>[...r[38]||=[c(`Cancel`,-1)]]),_:1}),o(_,{variant:`solid`,size:`sm`,loading:ft.value,onClick:ht},{default:m(()=>[...r[39]||=[c(`Add`,-1)]]),_:1},8,[`loading`])]),default:m(()=>[d(`form`,{class:`admin-plugins__form`,onSubmit:ae(ht,[`prevent`])},[d(`label`,Ve,[r[36]||=d(`span`,{class:`admin-plugins__label`},`Catalog URL`,-1),t(d(`input`,{"onUpdate:modelValue":r[4]||=e=>F.value=e,type:`url`,class:`admin-plugins__input`,autocomplete:`off`,placeholder:`https://github.com/owner/phlix-plugins`,required:``},null,512),[[re,F.value]]),r[37]||=d(`span`,{class:`admin-plugins__hint`},[c(` A repository (or direct `),d(`code`,null,`plugins.json`),c(` URL) listing installable plugins. `)],-1)])],32)]),_:1},8,[`modelValue`]),o(h,{"model-value":G.value!==null,title:`Uninstall plugin`,size:`sm`,"onUpdate:modelValue":r[7]||=e=>G.value=null},{footer:m(()=>[o(_,{variant:`ghost`,size:`sm`,onClick:r[6]||=e=>G.value=null},{default:m(()=>[...r[42]||=[c(`Cancel`,-1)]]),_:1}),o(_,{variant:`solid`,size:`sm`,onClick:Dt},{default:m(()=>[...r[43]||=[c(`Uninstall`,-1)]]),_:1})]),default:m(()=>[d(`p`,null,[r[40]||=c(` Uninstall `,-1),d(`strong`,null,p(G.value?.name),1),r[41]||=c(`? This removes the plugin and its settings and cannot be undone. `,-1)])]),_:1},8,[`model-value`]),o(h,{"model-value":K.value!==null,title:kt.value,size:`lg`,"onUpdate:modelValue":$},{footer:m(()=>[o(_,{variant:`ghost`,size:`sm`,onClick:$},{default:m(()=>[...r[45]||=[c(`Cancel`,-1)]]),_:1}),jt.value?(e(),a(_,{key:0,variant:`solid`,size:`sm`,loading:J.value,onClick:Bt},{default:m(()=>[...r[46]||=[c(` Save `,-1)]]),_:1},8,[`loading`])):s(``,!0)]),default:m(()=>[Ot.value?(e(),f(`div`,He,[o(de,{variant:`text`,lines:4})])):(e(),f(u,{key:1},[jt.value?(e(),f(`form`,{key:1,class:`admin-plugins__form`,onSubmit:ae(Bt,[`prevent`])},[(e(!0),f(u,null,i(At.value,([n,i])=>(e(),f(`div`,{key:n,class:`admin-plugins__field`},[i.type===`bool`||i.type===`boolean`?(e(),a(y,{key:0,"model-value":Y.value[n]===!0,label:i.label||n,"onUpdate:modelValue":e=>Y.value[n]=e},null,8,[`model-value`,`label`,`onUpdate:modelValue`])):(e(),f(u,{key:1},[d(`span`,Ue,[c(p(i.label||n)+` `,1),i.required?(e(),f(`span`,We,`*`)):(e(),f(`span`,Ge,`optional`))]),t(d(`input`,{"onUpdate:modelValue":e=>Y.value[n]=e,type:i.secret?`password`:Mt(i),class:ne([`admin-plugins__input`,{"is-invalid":Z.value[n]}]),autocomplete:i.secret?`new-password`:`off`,placeholder:i.secret?Q(n)?.set?`Leave blank to keep the current value`:`Not set — enter a value`:void 0,"aria-label":i.label||n,"aria-invalid":Z.value[n]?`true`:void 0},null,10,Ke),[[ie,Y.value[n]]]),i.secret?(e(),f(`span`,{key:0,class:ne([`admin-plugins__secret-status`,{"is-set":Q(n)?.set}])},[Q(n)?.set?(e(),f(u,{key:0},[d(`span`,qe,p(Ft(Q(n)?.length??0)),1),c(` Currently set (`+p(Q(n)?.length)+` characters) — leave blank to keep it. `,1)],64)):(e(),f(u,{key:1},[c(`Not set.`)],64))],2)):s(``,!0)],64)),i.description?(e(),f(`span`,Je,p(i.description),1)):s(``,!0),It(i)?(e(),f(`span`,Ye,[r[44]||=c(` Default: `,-1),d(`code`,null,p(It(i)),1)])):s(``,!0),i.link?(e(),f(`a`,{key:4,class:`admin-plugins__field-link`,href:i.link,target:`_blank`,rel:`noopener noreferrer`},p(Lt(i))+` ↗ `,9,Xe)):s(``,!0),Z.value[n]?(e(),f(`span`,Ze,p(Z.value[n]),1)):s(``,!0)]))),128))],32)):(e(),a(fe,{key:0,icon:`settings`,title:`No configurable settings`,description:`This plugin does not expose any settings.`}))],64))]),_:1},8,[`model-value`,`title`])]))}}),[[`__scopeId`,`data-v-bddf3d8e`]]);export{b as default}; | |||
There was a problem hiding this comment.
Reject unsafe field-help link schemes
When an installed plugin's manifest declares a settings help link such as javascript:..., the configure modal now renders that value directly as an <a href>; the server passes manifest/overlay link strings through unchanged (SettingsMasker::schema() / PluginFieldHelp::decorate()), so clicking the help link can execute script instead of navigating to documentation. Please restrict these links to safe schemes (for example https:/http:) before rendering or before returning them from the API.
Useful? React with 👍 / 👎.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #524 +/- ##
============================================
+ Coverage 57.22% 57.35% +0.13%
Complexity 17495 17495
============================================
Files 587 587
Lines 54893 54893
============================================
+ Hits 31410 31485 +75
+ Misses 23483 23408 -75 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…524) Bumps web-ui's @phlix/ui pin v0.78.0 -> v0.79.0 and regenerates the committed public/assets/app/ bundle, so the deployed server actually serves the plugin configure/lifecycle UX (visible enable errors, secret set/length status, field-help links). Version 1.2.1 -> 1.2.2.
Wires the phlix-ui v0.79.0 plugin-configure UX into the server's served SPA: bumps
web-ui/'s@phlix/uipinv0.78.0→v0.79.0and regenerates the committedpublic/assets/app/bundle (visible enable-failure banner, secret set/length status, field-help links/defaults). Version1.2.1→1.2.2.🤖 Generated with Claude Code