From 675811ccde84796a7433cb89016dab376d6c597e Mon Sep 17 00:00:00 2001 From: Charlie Date: Thu, 5 Jan 2023 19:30:41 +0800 Subject: [PATCH] Enhance/plugins (#8202) * improve(plugins): install hooks with user options * improve(plugin): remove todos * improve(plugin): hook for a specific plugin * e2e tests * improve(ui): global search bar for the results from the custom search service --- e2e-tests/plugins.spec.ts | 72 +++++++++++++++++++++++ libs/src/LSPlugin.caller.ts | 1 - libs/src/LSPlugin.core.ts | 9 ++- libs/src/LSPlugin.ts | 2 +- libs/src/LSPlugin.user.ts | 3 +- resources/js/lsplugin.core.js | 2 +- src/main/frontend/components/plugins.cljs | 15 ++--- src/main/frontend/components/search.cljs | 4 +- src/main/frontend/components/search.css | 9 ++- src/main/frontend/state.cljs | 17 +++--- src/main/logseq/api.cljs | 4 +- 11 files changed, 112 insertions(+), 26 deletions(-) create mode 100644 e2e-tests/plugins.spec.ts diff --git a/e2e-tests/plugins.spec.ts b/e2e-tests/plugins.spec.ts new file mode 100644 index 000000000..6da19e5c8 --- /dev/null +++ b/e2e-tests/plugins.spec.ts @@ -0,0 +1,72 @@ +import { expect } from '@playwright/test' +import { test } from './fixtures' + +test('enabled plugin system default', async ({ page }) => { + const callAPI = callPageAPI.bind(null, page) + + const pluginEnabled = await callAPI('get_state_from_store', 'plugin/enabled') + await expect(pluginEnabled).toBe(true) + + expect(await page.evaluate(`typeof logseq.api.get_current_graph`)) + .toBe('function') + + const currentGraph = await callAPI('get_current_graph') + expect(Object.keys(currentGraph)).toEqual(['url', 'name', 'path']) +}) + +test('play a plugin from the Marketplace', async ({ page }) => { + await page.keyboard.press('t+p') + const searchInput = page.locator('.search-ctls .form-input') + await searchInput.type('journals') + + const pluginCards = page.locator('.cp__plugins-item-card') + + if (await pluginCards.count()) { + await pluginCards.locator('.ctl .ls-icon-settings').hover() + await page.locator('text=Uninstall').click() + + const confirmYes = page.locator('button').locator('text=Yes') + await confirmYes.click() + } + + // install a plugin from Marketplace + await page.locator('button').locator('text=Marketplace').click() + await page.locator('text=Journals calendar') + + await page.locator('.cp__plugins-item-card').first().locator('text=Install').click() + // wait for the plugin installed + await page.locator('.cp__plugins-item-card').first().locator('text=Installed') + await page.locator('a.ui__modal-close').click() + + // toolbar plugins manager + const pluginFlag = page.locator('.toolbar-plugins-manager-trigger') + + await expect(pluginFlag).toBeVisible() + + await pluginFlag.click() + + await expect(pluginFlag.locator('text=Plugins')).toBeVisible() + await expect(pluginFlag.locator('text=Settings')).toBeVisible() + + await page.locator('text=goto-today').click() + await page.locator('body').click() + + const goToToday = page.locator('#logseq-journals-calendar--goto-today').locator('a.button') + await expect(goToToday).toBeVisible() + await goToToday.click() + + // TODO: debug + await expect(page.locator('body[data-page="page"]')).toBeVisible() +}) + +/** + * @param page + * @param method + * @param args + */ +async function callPageAPI(page, method, ...args) { + return await page.evaluate(([method, args]) => { + // @ts-ignore + return window.logseq.api[method]?.(...args) + }, [method, args]) +} diff --git a/libs/src/LSPlugin.caller.ts b/libs/src/LSPlugin.caller.ts index 660292f87..3b9dc55cf 100644 --- a/libs/src/LSPlugin.caller.ts +++ b/libs/src/LSPlugin.caller.ts @@ -308,7 +308,6 @@ class LSPluginCaller extends EventEmitter { this._callUserModel = async (type, ...payloads: any[]) => { if (type.startsWith(FLAG_AWAIT)) { - // TODO: attach arguments with method call return await refChild.get( type.replace(FLAG_AWAIT, ''), ...payloads diff --git a/libs/src/LSPlugin.core.ts b/libs/src/LSPlugin.core.ts index a654da65b..4b6f481f9 100644 --- a/libs/src/LSPlugin.core.ts +++ b/libs/src/LSPlugin.core.ts @@ -1398,8 +1398,15 @@ class LSPluginCore }) } + const p = pid && this._registeredPlugins.get(pid) + + if (p && !p.disabled && p.options.entry) { + act(p) + return + } + for (const [_, p] of this._registeredPlugins) { - if (p.options.theme || p.disabled) { + if (!p.options.entry || p.disabled) { continue } diff --git a/libs/src/LSPlugin.ts b/libs/src/LSPlugin.ts index 18117fbea..c19a168cb 100644 --- a/libs/src/LSPlugin.ts +++ b/libs/src/LSPlugin.ts @@ -518,7 +518,7 @@ export interface IAppProxy { onSidebarVisibleChanged: IUserHook<{ visible: boolean }> // internal - _installPluginHook: (pid: string, hook: string) => void + _installPluginHook: (pid: string, hook: string, opts?: any) => void _uninstallPluginHook: (pid: string, hookOrAll: string | boolean) => void } diff --git a/libs/src/LSPlugin.user.ts b/libs/src/LSPlugin.user.ts index 1fb04b44c..3ba360627 100644 --- a/libs/src/LSPlugin.user.ts +++ b/libs/src/LSPlugin.user.ts @@ -737,6 +737,7 @@ export class LSPluginUser const type = `hook:${tag}:${safeSnakeCase(e)}` const handler = args[0] + const opts = args[1] caller[f](type, handler) const unlisten = () => { @@ -747,7 +748,7 @@ export class LSPluginUser } if (!isOff) { - that.App._installPluginHook(pid, type) + that.App._installPluginHook(pid, type, opts) } else { unlisten() return diff --git a/resources/js/lsplugin.core.js b/resources/js/lsplugin.core.js index ad836d0d3..02778455a 100644 --- a/resources/js/lsplugin.core.js +++ b/resources/js/lsplugin.core.js @@ -1,2 +1,2 @@ /*! For license information please see lsplugin.core.js.LICENSE.txt */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.LSPlugin=t():e.LSPlugin=t()}(self,(()=>(()=>{var e={227:(e,t,n)=>{var r=n(155);t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;t.splice(1,0,n,"color: inherit");let r=0,o=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(r++,"%c"===e&&(o=r))})),t.splice(o,0,n)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&void 0!==r&&"env"in r&&(e=r.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=n(447)(t);const{formatters:o}=e.exports;o.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},447:(e,t,n)=>{e.exports=function(e){function t(e){let n,o,i,s=null;function a(...e){if(!a.enabled)return;const r=a,o=Number(new Date),i=o-(n||o);r.diff=i,r.prev=n,r.curr=o,n=o,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let s=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((n,o)=>{if("%%"===n)return"%";s++;const i=t.formatters[o];if("function"==typeof i){const t=e[s];n=i.call(r,t),e.splice(s,1),s--}return n})),t.formatArgs.call(r,e),(r.log||t.log).apply(r,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=r,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==s?s:(o!==t.namespaces&&(o=t.namespaces,i=t.enabled(e)),i),set:e=>{s=e}}),"function"==typeof t.init&&t.init(a),a}function r(e,n){const r=t(this.namespace+(void 0===n?":":n)+e);return r.log=this.log,r}function o(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(o),...t.skips.map(o).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let n;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const r=("string"==typeof e?e:"").split(/[\s,]+/),o=r.length;for(n=0;n{t[n]=e[n]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let n=0;for(let t=0;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n1?n-1:0),o=1;o/gm),W=d(/^data-[\-\w.\u00B7-\uFFFF]/),G=d(/^aria-[\-\w]+$/),J=d(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),V=d(/^(?:\w+script|data):/i),Z=d(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),K=d(/^html$/i),Y=function(){return"undefined"==typeof window?null:window},Q=function(t,n){if("object"!==e(t)||"function"!=typeof t.createPolicy)return null;var r=null,o="data-tt-policy-suffix";n.currentScript&&n.currentScript.hasAttribute(o)&&(r=n.currentScript.getAttribute(o));var i="dompurify"+(r?"#"+r:"");try{return t.createPolicy(i,{createHTML:function(e){return e}})}catch(e){return console.warn("TrustedTypes policy "+i+" could not be created."),null}};return function t(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:Y(),r=function(e){return t(e)};if(r.version="2.3.8",r.removed=[],!n||!n.document||9!==n.document.nodeType)return r.isSupported=!1,r;var i=n.document,s=n.document,a=n.DocumentFragment,c=n.HTMLTemplateElement,l=n.Node,u=n.Element,d=n.NodeFilter,f=n.NamedNodeMap,p=void 0===f?n.NamedNodeMap||n.MozNamedAttrMap:f,g=n.HTMLFormElement,m=n.DOMParser,y=n.trustedTypes,k=u.prototype,X=I(k,"cloneNode"),ee=I(k,"nextSibling"),te=I(k,"childNodes"),ne=I(k,"parentNode");if("function"==typeof c){var re=s.createElement("template");re.content&&re.content.ownerDocument&&(s=re.content.ownerDocument)}var oe=Q(y,i),ie=oe?oe.createHTML(""):"",se=s,ae=se.implementation,ce=se.createNodeIterator,le=se.createDocumentFragment,ue=se.getElementsByTagName,he=i.importNode,de={};try{de=T(s).documentMode?s.documentMode:{}}catch(e){}var fe={};r.isSupported="function"==typeof ne&&ae&&void 0!==ae.createHTMLDocument&&9!==de;var pe,ge,me=q,ye=B,_e=W,be=G,ve=V,we=Z,xe=J,Ce=null,Se=j({},[].concat(o(L),o(M),o(N),o(R),o(D))),Oe=null,Ee=j({},[].concat(o(U),o($),o(z),o(H))),Ae=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),ke=null,je=null,Te=!0,Ie=!0,Le=!1,Me=!1,Ne=!1,Pe=!1,Re=!1,Fe=!1,De=!1,Ue=!1,$e=!0,ze=!0,He=!1,qe={},Be=null,We=j({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),Ge=null,Je=j({},["audio","video","img","source","image","track"]),Ve=null,Ze=j({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Ke="http://www.w3.org/1998/Math/MathML",Ye="http://www.w3.org/2000/svg",Qe="http://www.w3.org/1999/xhtml",Xe=Qe,et=!1,tt=["application/xhtml+xml","text/html"],nt="text/html",rt=null,ot=s.createElement("form"),it=function(e){return e instanceof RegExp||e instanceof Function},st=function(t){rt&&rt===t||(t&&"object"===e(t)||(t={}),t=T(t),Ce="ALLOWED_TAGS"in t?j({},t.ALLOWED_TAGS):Se,Oe="ALLOWED_ATTR"in t?j({},t.ALLOWED_ATTR):Ee,Ve="ADD_URI_SAFE_ATTR"in t?j(T(Ze),t.ADD_URI_SAFE_ATTR):Ze,Ge="ADD_DATA_URI_TAGS"in t?j(T(Je),t.ADD_DATA_URI_TAGS):Je,Be="FORBID_CONTENTS"in t?j({},t.FORBID_CONTENTS):We,ke="FORBID_TAGS"in t?j({},t.FORBID_TAGS):{},je="FORBID_ATTR"in t?j({},t.FORBID_ATTR):{},qe="USE_PROFILES"in t&&t.USE_PROFILES,Te=!1!==t.ALLOW_ARIA_ATTR,Ie=!1!==t.ALLOW_DATA_ATTR,Le=t.ALLOW_UNKNOWN_PROTOCOLS||!1,Me=t.SAFE_FOR_TEMPLATES||!1,Ne=t.WHOLE_DOCUMENT||!1,Fe=t.RETURN_DOM||!1,De=t.RETURN_DOM_FRAGMENT||!1,Ue=t.RETURN_TRUSTED_TYPE||!1,Re=t.FORCE_BODY||!1,$e=!1!==t.SANITIZE_DOM,ze=!1!==t.KEEP_CONTENT,He=t.IN_PLACE||!1,xe=t.ALLOWED_URI_REGEXP||xe,Xe=t.NAMESPACE||Qe,t.CUSTOM_ELEMENT_HANDLING&&it(t.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(Ae.tagNameCheck=t.CUSTOM_ELEMENT_HANDLING.tagNameCheck),t.CUSTOM_ELEMENT_HANDLING&&it(t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(Ae.attributeNameCheck=t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),t.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(Ae.allowCustomizedBuiltInElements=t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),pe=pe=-1===tt.indexOf(t.PARSER_MEDIA_TYPE)?nt:t.PARSER_MEDIA_TYPE,ge="application/xhtml+xml"===pe?function(e){return e}:w,Me&&(Ie=!1),De&&(Fe=!0),qe&&(Ce=j({},o(D)),Oe=[],!0===qe.html&&(j(Ce,L),j(Oe,U)),!0===qe.svg&&(j(Ce,M),j(Oe,$),j(Oe,H)),!0===qe.svgFilters&&(j(Ce,N),j(Oe,$),j(Oe,H)),!0===qe.mathMl&&(j(Ce,R),j(Oe,z),j(Oe,H))),t.ADD_TAGS&&(Ce===Se&&(Ce=T(Ce)),j(Ce,t.ADD_TAGS)),t.ADD_ATTR&&(Oe===Ee&&(Oe=T(Oe)),j(Oe,t.ADD_ATTR)),t.ADD_URI_SAFE_ATTR&&j(Ve,t.ADD_URI_SAFE_ATTR),t.FORBID_CONTENTS&&(Be===We&&(Be=T(Be)),j(Be,t.FORBID_CONTENTS)),ze&&(Ce["#text"]=!0),Ne&&j(Ce,["html","head","body"]),Ce.table&&(j(Ce,["tbody"]),delete ke.tbody),h&&h(t),rt=t)},at=j({},["mi","mo","mn","ms","mtext"]),ct=j({},["foreignobject","desc","title","annotation-xml"]),lt=j({},["title","style","font","a","script"]),ut=j({},M);j(ut,N),j(ut,P);var ht=j({},R);j(ht,F);var dt=function(e){var t=ne(e);t&&t.tagName||(t={namespaceURI:Qe,tagName:"template"});var n=w(e.tagName),r=w(t.tagName);return e.namespaceURI===Ye?t.namespaceURI===Qe?"svg"===n:t.namespaceURI===Ke?"svg"===n&&("annotation-xml"===r||at[r]):Boolean(ut[n]):e.namespaceURI===Ke?t.namespaceURI===Qe?"math"===n:t.namespaceURI===Ye?"math"===n&&ct[r]:Boolean(ht[n]):e.namespaceURI===Qe&&!(t.namespaceURI===Ye&&!ct[r])&&!(t.namespaceURI===Ke&&!at[r])&&!ht[n]&&(lt[n]||!ut[n])},ft=function(e){v(r.removed,{element:e});try{e.parentNode.removeChild(e)}catch(t){try{e.outerHTML=ie}catch(t){e.remove()}}},pt=function(e,t){try{v(r.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){v(r.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!Oe[e])if(Fe||De)try{ft(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},gt=function(e){var t,n;if(Re)e=""+e;else{var r=x(e,/^[\r\n\t ]+/);n=r&&r[0]}"application/xhtml+xml"===pe&&(e=''+e+"");var o=oe?oe.createHTML(e):e;if(Xe===Qe)try{t=(new m).parseFromString(o,pe)}catch(e){}if(!t||!t.documentElement){t=ae.createDocument(Xe,"template",null);try{t.documentElement.innerHTML=et?"":o}catch(e){}}var i=t.body||t.documentElement;return e&&n&&i.insertBefore(s.createTextNode(n),i.childNodes[0]||null),Xe===Qe?ue.call(t,Ne?"html":"body")[0]:Ne?t.documentElement:i},mt=function(e){return ce.call(e.ownerDocument||e,e,d.SHOW_ELEMENT|d.SHOW_COMMENT|d.SHOW_TEXT,null,!1)},yt=function(e){return e instanceof g&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof p)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore)},_t=function(t){return"object"===e(l)?t instanceof l:t&&"object"===e(t)&&"number"==typeof t.nodeType&&"string"==typeof t.nodeName},bt=function(e,t,n){fe[e]&&_(fe[e],(function(e){e.call(r,t,n,rt)}))},vt=function(e){var t;if(bt("beforeSanitizeElements",e,null),yt(e))return ft(e),!0;if(E(/[\u0080-\uFFFF]/,e.nodeName))return ft(e),!0;var n=ge(e.nodeName);if(bt("uponSanitizeElement",e,{tagName:n,allowedTags:Ce}),e.hasChildNodes()&&!_t(e.firstElementChild)&&(!_t(e.content)||!_t(e.content.firstElementChild))&&E(/<[/\w]/g,e.innerHTML)&&E(/<[/\w]/g,e.textContent))return ft(e),!0;if("select"===n&&E(/