collabmd 0.1.32 → 0.1.34
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/dist/client/assets/{drawio-editor-Br4qyh3r.js → drawio-editor-BMTwP5mD.js} +1 -1
- package/dist/client/assets/{drawioEditor-ClmnTx5J.js → drawioEditor-D6clB5OH.js} +2 -2
- package/dist/client/assets/{editor-session-Cf-iV5-3.js → editor-session-Dzy_85Wp.js} +1 -1
- package/dist/client/assets/{excalidraw-editor-CXAxVhlw.js → excalidraw-editor-CAP9F8CB.js} +3 -3
- package/dist/client/assets/{excalidrawEditor-DoH_kMdu.js → excalidrawEditor-DD4AvzYP.js} +2 -2
- package/dist/client/assets/{exportDocument-9wTrBZNS.css → exportDocument-BbkN85c4.css} +1 -1
- package/dist/client/assets/index-BIt5EZXz.css +1 -0
- package/dist/client/assets/{index-C8QZYHvV.js → index-BLrtj9YM.js} +2 -2
- package/dist/client/assets/main-CfSHaGes.js +1368 -0
- package/dist/client/assets/{vault-api-client-Bf9tB_GW.js → vault-api-client-p7h7cXKM.js} +1 -1
- package/dist/client/drawio-editor.html +1 -1
- package/dist/client/excalidraw-editor.html +1 -1
- package/dist/client/export-document.html +2 -2
- package/dist/client/index.html +2 -2
- package/package.json +6 -5
- package/src/client/application/app-shell/git-feature.js +44 -36
- package/src/client/application/app-shell/ui-feature-shell.js +84 -63
- package/src/client/bootstrap/collabmd-app-shell.js +6 -0
- package/src/client/infrastructure/editor-session.js +4 -0
- package/src/client/infrastructure/editor-view-adapter.js +23 -0
- package/src/client/infrastructure/vault-api-client.js +48 -0
- package/src/client/presentation/bases-preview-controller.js +1388 -28
- package/src/client/presentation/comments-panel.js +50 -5
- package/src/client/presentation/excalidraw-embed-controller.js +4 -1
- package/src/client/presentation/file-history-view-controller.js +9 -1
- package/src/client/presentation/git-panel-controller.js +101 -91
- package/src/client/styles/components/scrollbars.css +5 -0
- package/src/client/styles/features/preview-markdown.css +468 -23
- package/src/server/domain/backlink-index.js +202 -11
- package/src/server/domain/bases/base-definition.js +138 -11
- package/src/server/domain/bases/base-expression-runtime.js +54 -17
- package/src/server/domain/bases/base-index-snapshot-store.js +167 -20
- package/src/server/domain/bases/base-query-metadata.js +242 -0
- package/src/server/domain/bases/base-query-results.js +18 -8
- package/src/server/domain/bases/base-query-service.js +360 -49
- package/src/server/domain/bases/base-transform.js +116 -0
- package/src/server/infrastructure/http/create-request-handler.js +63 -28
- package/src/server/infrastructure/http/create-vault-api-command-handler.js +275 -256
- package/src/server/infrastructure/http/create-vault-api-query-handler.js +258 -184
- package/src/server/infrastructure/persistence/vault-file-store.js +68 -12
- package/dist/client/assets/index-CxSbUTs2.css +0 -1
- package/dist/client/assets/main-BjHHMlv0.js +0 -1249
- /package/dist/client/assets/{exportDocument-Bia2hI25.js → exportDocument-Zfwq1XVx.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
import{l as e,n as t}from"./runtime-config-CqhchMC4.js";var n={enabled:!1,implemented:!0,loginEndpoint:`/api/auth/oidc/login`,passwordLabel:`Password`,provider:``,requiresLogin:!1,sessionEndpoint:`/api/auth/session`,statusEndpoint:`/api/auth/status`,strategy:`none`,submitLabel:`Continue`},r=`data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAIAAAABc2X6AAAGsklEQVR4Ae3cA3jsShgG4Gvbtu1js7aObdu2bdbudmvbtu1VtUg2ydw7x95mstnt5rZ5voflG80/fzL72L89bOsF94J7wWgb2dSgiAzpPHmwbfPK1qWzxDNsRdb6Ar2BgtF9hSbDRbYG4mk2beuXwm+Q89yV+TmAILgHptrb5DyPtg3LhBZjBCP+RovewNZlc2TOl8nGel0HA4LA4qPhkRSM6XcHoEYk86fIfT2AQqFzYIBjMncHofkoZBWNCM1GSq+cpdpadQIMKEoRzIeXIroEkW08TObpDAiiO8F4Tga85TBnoEc8xVKZm9UNYECS0stnBCP/Ud+AnJH/SC+eAiShPTDZ3CRZPIN9CUokC6ZSYqE2wHhmKhw/2TegR2RnSFSUaRaMJccLxg7QsAQhktkTAACaAmOxkbA80h2taKIZKWzR1BFWRAQLRvXhphYdDEtcWDxxU4sOhjdDkdVYbmrRwYAgJIums3RTNWrftbHz/AmZh5MiLBAGVqOdZ4+1790inmrFvpYZuPPEATWdknmT5f7eZEN9V2N7o9zPu3XNInQte2BlcYE6tVTbltXw4kf9h5QlhW3rliBr1QcDAODsjPFlhmelqfNvKQty4S9B0KoPVgTxmWk7Tx0COMZCF6GzA3ZC0LWMwJSsTWiOXj+O6iP382KzowAAvMOhaxmAqw/Ijr4tGPsHgnbsACwxlpNNPABIIv5LIvxpzOVlkdXPNMGK8CCudi2pFi+ovRFlwLOtc7/uUgvnxhxu05LpIyD17nTu+EAw8q9HaVtXzgcAcBUMcAER/sx9YBj5pdeExr897NLtT9TVcLgRTzVcgbyHBuc9L5n8PdLJzAEwmWP1KDCMMvTp9jWf3tbC1gdQKDgMBhRBRL0GYaojO35zxOo8fZjbz5ZAZz700Anm9pLI9g+yoY7bYKrJBWJoRpk8SJ0/fDoc13QuRuNdgMmydfTBZPkGdcDDd0q1EDkOVIKzTOiDKVGY7oPLmylVYCKlL30wIKW6D44tJlSCE76nC45+CwHXfWDfdKVKcMwHdMEJ33MC7JqEqwRHvEgXnDaYE+ArMayBB3ECDAennnVKn4tUDU74gS446k1OgB3i8Z41LHmkKHtW4eGfpRpctv5/VlomlxOsTR6kKQN1H1wnptiZHpYFv27pMbqus4kxOChbySzTz8loakfukhIkYKEBEBzw6SBXk79cLQ5lXv5XuxtJAaMDdA/v+JMydVs8irBnDvB+g9QbGeY1SUFg2gTn1JD0z+cdPIVaTbym0JemeQ6FzrtzJtdFm+DT4Rh9MD9DybxNmxL03mg3g/u0MP3cbWo6GrWjbZMBg/0Id6wqAcWwEX+F/10fVzPIe2jmRW3VTiP+VBjC4bU6KgMAID9qaQt9frl3P6hSndOaP7HrxdSYPQiH92QYhvAwTRH7KdSWBL9h5j4GeugkqDpWc1oZBqaelSGNwMWNJMLjUkHxBn//zwZeH3topr+7bWxDmia0AID17gok7aTTMrTnw1KsfZTPVMhAyj9uVl5lIexqcQLs4KFpYXjpSjQw3HwrIqCBQQ5mXsZInBWtoIOac1GOqrU4IsUJwOSllsmha5iZTf3npzXnqXka+1dFmzo4D9vZgQp2TsAZvrZUIC7729WSmRlmVfz+HGExKpUCVGJj1oSQlTd+SZ9Lm4bubqKvtTkmk+OAIRhu+zMu3jEwyqTQ1d7lofWdzV0VyWSxpPJkjpOB76z7fsPfjjOHHMhBb0QzAhMUMS18nRrgOzHkz96YdPR4toNTMT+gKjq4OtatNPBCvgfcp9PD1w/wsFP14y7WA4/zu9SudVWw8HKpUC4Zw5uOLmQ//c4fGrZL8iit+WEpvMmxAIZbtrCor7uNLpj/ubpk6N6Kh059M6tINl8Qh4UUHGa73wzjNGHQ4dj7wC6JOPtLACLqkvq4WeuE2cWi/+nLt0csOKnQ1CKP+IYMWELqgPnGiLVh6O7Go8GYZpfxpDbnwkaHjpj3JfLRV7Wgb01SARxIupc6wntyfGOG9pbikRQJmzvodRg7mRq2tkkm7IbFlhktBdaBS7SsPZx1haDIbltOSwGKXxl5px7UZGaEb8gXlerEgmmMxB2KfEciTKHRAsvbmPo0nVsST1BEdH3Kyrh9bJVlQ7wmbk05USSu0PUPPWjDOtxLg5bF7h7tM42B08x//o7U0/AmrCSV3PtYiwZpS3B13MHMS/DIz4rYaBO0VM93JpwbwaJtqNfEsbwZFgEL50VtgcJLBV6wK9aKtfd+cEkvuBfcC37k9h8VGR+csPdltgAAAABJRU5ErkJggg==`;function i(){return{...n,...t().auth??{}}}function a(){let e=window.location.hash.startsWith(`#`)?window.location.hash.slice(1):window.location.hash;return new URLSearchParams(e)}function o(){return a().get(`auth_password`)||``}function s(){let e=a();if(!e.has(`auth_password`))return;e.delete(`auth_password`);let t=e.toString(),n=`${window.location.pathname}${window.location.search}${t?`#${t}`:``}`;window.history.replaceState(null,``,n)}function c(e){let t=a(),n=t.get(e)||``;if(!n)return``;t.delete(e);let r=t.toString(),i=`${window.location.pathname}${window.location.search}${r?`#${r}`:``}`;return window.history.replaceState(null,``,i),n}function l(){return`${window.location.pathname}${window.location.search}${window.location.hash}`}async function u(e){let t=await fetch(e.statusEndpoint,{headers:{Accept:`application/json`}}),n=await t.json().catch(()=>({}));if(!t.ok)throw Error(n.error||`Failed to read auth status`);return n}function d(e){let t=e?.auth??{};if(t.strategy!==`oidc`||t.provider!==`google`)return;let n=String(e?.user?.name??``).trim();if(n)try{window.localStorage.setItem(`collabmd-user-name`,n)}catch{}}async function f(e,t){let n=await fetch(e.sessionEndpoint,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({password:t})}),r=await n.json().catch(()=>({}));if(!n.ok)throw Error(r.error||`Authentication failed`);return r}function p(){let e=document.createElement(`div`);e.className=`auth-gate-overlay`;let t=document.createElement(`section`);return t.className=`auth-gate-card`,e.append(t),{card:t,overlay:e}}function m(){let e=document.createElement(`span`);e.className=`auth-gate-button__icon`,e.setAttribute(`aria-hidden`,`true`);let t=document.createElement(`img`);return t.alt=``,t.decoding=`async`,t.height=20,t.loading=`eager`,t.src=r,t.width=20,e.append(t),e}function h(e,t,{errorMessage:n=``}){e.replaceChildren();let r=document.createElement(`h1`);r.textContent=`Authentication required`;let i=document.createElement(`p`);i.textContent=`Sign in with Google to join this session.`;let a=document.createElement(`div`);a.className=`auth-gate-actions`;let o=document.createElement(`button`);o.className=`ui-button ui-button--secondary auth-gate-button auth-gate-button--google`,o.type=`button`,o.append(m(),document.createTextNode(t.submitLabel||`Continue with Google`));let s=document.createElement(`div`);s.className=`auth-gate-error`,s.textContent=n,a.append(o),e.append(r,i,s,a),o.addEventListener(`click`,()=>{let e=new URL(t.loginEndpoint,window.location.origin);e.searchParams.set(`returnTo`,l()),window.location.assign(e.toString())})}function g(e,{title:t,body:n,secondaryActionLabel:r=``,onSecondaryAction:i=null}){e.replaceChildren();let a=document.createElement(`h1`);a.textContent=t;let o=document.createElement(`p`);if(o.textContent=n,e.append(a,o),r&&typeof i==`function`){let t=document.createElement(`button`);t.className=`ui-button ui-button--secondary auth-gate-secondary-button`,t.type=`button`,t.textContent=r,t.addEventListener(`click`,()=>{i()}),e.append(t)}}function _(e,t,{onSubmit:n}){e.replaceChildren();let r=document.createElement(`h1`);r.textContent=`Authentication required`;let i=document.createElement(`p`);i.textContent=`Enter the host password to join this shared session.`;let a=document.createElement(`form`);a.className=`auth-gate-form`;let o=document.createElement(`label`);o.className=`auth-gate-label`,o.textContent=t.passwordLabel;let s=document.createElement(`input`);s.className=`ui-input auth-gate-input`,s.type=`password`,s.name=`password`,s.autocomplete=`current-password`,s.required=!0;let c=document.createElement(`div`);c.className=`auth-gate-error`;let l=document.createElement(`div`);l.className=`auth-gate-actions`;let u=document.createElement(`button`);u.className=`ui-button ui-button--primary auth-gate-button`,u.type=`submit`,u.textContent=t.submitLabel,l.append(u),o.append(s),a.append(r,i,o,c,l),e.append(a),a.addEventListener(`submit`,e=>{e.preventDefault();let t=s.value;s.disabled=!0,u.disabled=!0,c.textContent=``,n(t).catch(e=>{c.textContent=e instanceof Error?e.message:`Authentication failed`,s.disabled=!1,u.disabled=!1,s.select(),s.focus()})}),queueMicrotask(()=>{s.focus()})}async function v(){let e=i();if(!e.enabled||e.strategy===`none`)return{authenticated:!0,auth:e};let{card:t,overlay:n}=p();document.body.append(n);let r=c(`auth_error`);return new Promise(i=>{let a=(t=null)=>{s(),d(t),n.remove(),i({authenticated:!0,auth:t?.auth??e,user:t?.user??null})};(async()=>{g(t,{body:`Checking access to this session…`,title:`CollabMD`});try{let t=await u(e);if(t.authenticated){a(t);return}}catch(e){g(t,{body:e instanceof Error?`${e.message} Refresh the page and try again.`:`Failed to contact the auth service. Refresh the page and try again.`,title:`Cannot verify access`});return}if(e.strategy===`password`){let n=o();if(n)try{s(),await f(e,n),a();return}catch{}_(t,e,{onSubmit:async t=>{await f(e,t),a()}});return}if(e.strategy===`oidc`){h(t,e,{errorMessage:r}),r=``;return}g(t,{body:`This authentication strategy is not available.`,title:`Authentication unavailable`})})()})}function y(e){return encodeURIComponent(String(e??``))}function b(e){return String(e??``).replace(/\/+$/u,``).split(`/`).filter(Boolean).pop()||``}function x(e,t){let n=URL.createObjectURL(e),r=document.createElement(`a`);r.href=n,r.download=t,document.body.appendChild(r),r.click(),r.remove(),window.setTimeout(()=>URL.revokeObjectURL(n),0)}function S(e=``,t=`download`){let n=String(e).match(/filename\*=UTF-8''([^;]+)/iu);if(n)try{return decodeURIComponent(n[1])}catch{return t}return String(e).match(/filename="([^"]+)"/iu)?.[1]||t}function C(e,t={}){let n={...t};return e&&(n[`X-CollabMD-Request-Id`]=String(e)),n}async function w(e,t){let n=await e.json().catch(()=>({}));if(!e.ok||n.ok===!1){let r=Error(n.error||t);throw r.status=e.status,r.body=n,r}return n}async function T(e,{fallbackError:t,fallbackFileName:n}={}){let r=await fetch(e);if(!r.ok){let e=await r.json().catch(()=>({}));throw Error(e.error||t)}return x(await r.blob(),S(r.headers.get(`content-disposition`)||``,n)),r}var E=new class{async readTree(){return w(await fetch(e(`/files`)),`Failed to load file tree`)}async readFile(t){return w(await fetch(e(`/file?path=${encodeURIComponent(t)}`)),`Failed to read file`)}async queryBase({activeFilePath:t=``,path:n=``,search:r=``,source:i=null,sourcePath:a=``,view:o=``}={}){return w(await fetch(e(`/base/query`),{body:JSON.stringify({activeFilePath:t,path:n,search:r,source:i,sourcePath:a,view:o}),headers:{"Content-Type":`application/json`},method:`POST`}),`Failed to query base`)}async exportBaseCsv({activeFilePath:t=``,path:n=``,search:r=``,source:i=null,sourcePath:a=``,view:o=``}={}){let s=await fetch(e(`/base/export`),{body:JSON.stringify({activeFilePath:t,path:n,search:r,source:i,sourcePath:a,view:o}),headers:{"Content-Type":`application/json`},method:`POST`});if(!s.ok){let e=await s.json().catch(()=>({}));throw Error(e.error||`Failed to export base CSV`)}return{blob:await s.blob(),contentDisposition:s.headers.get(`content-disposition`)||``}}async createFile({content:t,path:n,requestId:r=null}){return w(await fetch(e(`/file`),{body:JSON.stringify({content:t,path:n}),headers:C(r,{"Content-Type":`application/json`}),method:`POST`}),`Failed to create file`)}async writeFile({content:t,path:n,requestId:r=null}){return w(await fetch(e(`/file`),{body:JSON.stringify({content:t,path:n}),headers:C(r,{"Content-Type":`application/json`}),method:`PUT`}),`Failed to write file`)}async renameFile({oldPath:t,newPath:n,requestId:r=null}){return w(await fetch(e(`/file`),{body:JSON.stringify({newPath:n,oldPath:t}),headers:C(r,{"Content-Type":`application/json`}),method:`PATCH`}),`Failed to rename file`)}async deleteFile(t,{requestId:n=null}={}){return w(await fetch(e(`/file?path=${encodeURIComponent(t)}`),{headers:n?C(n):void 0,method:`DELETE`}),`Failed to delete file`)}async createDirectory(t,{requestId:n=null}={}){return w(await fetch(e(`/directory`),{body:JSON.stringify({path:t}),headers:C(n,{"Content-Type":`application/json`}),method:`POST`}),`Failed to create folder`)}async renameDirectory({oldPath:t,newPath:n,requestId:r=null}){return w(await fetch(e(`/directory`),{body:JSON.stringify({newPath:n,oldPath:t}),headers:C(r,{"Content-Type":`application/json`}),method:`PATCH`}),`Failed to rename folder`)}async deleteDirectory(t,{recursive:n=!1,requestId:r=null}={}){let i=new URLSearchParams({path:String(t??``)});return n&&i.set(`recursive`,`1`),w(await fetch(e(`/directory?${i.toString()}`),{headers:r?C(r):void 0,method:`DELETE`}),`Failed to delete folder`)}async uploadImageAttachment({file:t,fileName:n=``,sourcePath:r}){return w(await fetch(e(`/attachments`),{body:t,headers:{"Content-Type":t?.type||`application/octet-stream`,"X-CollabMD-File-Name":y(n),"X-CollabMD-Source-Path":y(r)},method:`POST`}),`Failed to upload image`)}async downloadFile(t){let n=b(t)||`download`;return T(e(`/download/file?path=${encodeURIComponent(t)}`),{fallbackError:`Failed to download file`,fallbackFileName:n})}async downloadDirectory(t){let n=b(t)||`vault`;return T(e(`/download/directory?path=${encodeURIComponent(t)}`),{fallbackError:`Failed to download folder`,fallbackFileName:`${n}.zip`})}};export{v as n,E as t};
|
|
1
|
+
import{l as e,n as t}from"./runtime-config-CqhchMC4.js";var n={enabled:!1,implemented:!0,loginEndpoint:`/api/auth/oidc/login`,passwordLabel:`Password`,provider:``,requiresLogin:!1,sessionEndpoint:`/api/auth/session`,statusEndpoint:`/api/auth/status`,strategy:`none`,submitLabel:`Continue`},r=`data:image/png;base64,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`;function i(){return{...n,...t().auth??{}}}function a(){let e=window.location.hash.startsWith(`#`)?window.location.hash.slice(1):window.location.hash;return new URLSearchParams(e)}function o(){return a().get(`auth_password`)||``}function s(){let e=a();if(!e.has(`auth_password`))return;e.delete(`auth_password`);let t=e.toString(),n=`${window.location.pathname}${window.location.search}${t?`#${t}`:``}`;window.history.replaceState(null,``,n)}function c(e){let t=a(),n=t.get(e)||``;if(!n)return``;t.delete(e);let r=t.toString(),i=`${window.location.pathname}${window.location.search}${r?`#${r}`:``}`;return window.history.replaceState(null,``,i),n}function l(){return`${window.location.pathname}${window.location.search}${window.location.hash}`}async function u(e){let t=await fetch(e.statusEndpoint,{headers:{Accept:`application/json`}}),n=await t.json().catch(()=>({}));if(!t.ok)throw Error(n.error||`Failed to read auth status`);return n}function d(e){let t=e?.auth??{};if(t.strategy!==`oidc`||t.provider!==`google`)return;let n=String(e?.user?.name??``).trim();if(n)try{window.localStorage.setItem(`collabmd-user-name`,n)}catch{}}async function f(e,t){let n=await fetch(e.sessionEndpoint,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({password:t})}),r=await n.json().catch(()=>({}));if(!n.ok)throw Error(r.error||`Authentication failed`);return r}function p(){let e=document.createElement(`div`);e.className=`auth-gate-overlay`;let t=document.createElement(`section`);return t.className=`auth-gate-card`,e.append(t),{card:t,overlay:e}}function m(){let e=document.createElement(`span`);e.className=`auth-gate-button__icon`,e.setAttribute(`aria-hidden`,`true`);let t=document.createElement(`img`);return t.alt=``,t.decoding=`async`,t.height=20,t.loading=`eager`,t.src=r,t.width=20,e.append(t),e}function h(e,t,{errorMessage:n=``}){e.replaceChildren();let r=document.createElement(`h1`);r.textContent=`Authentication required`;let i=document.createElement(`p`);i.textContent=`Sign in with Google to join this session.`;let a=document.createElement(`div`);a.className=`auth-gate-actions`;let o=document.createElement(`button`);o.className=`ui-button ui-button--secondary auth-gate-button auth-gate-button--google`,o.type=`button`,o.append(m(),document.createTextNode(t.submitLabel||`Continue with Google`));let s=document.createElement(`div`);s.className=`auth-gate-error`,s.textContent=n,a.append(o),e.append(r,i,s,a),o.addEventListener(`click`,()=>{let e=new URL(t.loginEndpoint,window.location.origin);e.searchParams.set(`returnTo`,l()),window.location.assign(e.toString())})}function g(e,{title:t,body:n,secondaryActionLabel:r=``,onSecondaryAction:i=null}){e.replaceChildren();let a=document.createElement(`h1`);a.textContent=t;let o=document.createElement(`p`);if(o.textContent=n,e.append(a,o),r&&typeof i==`function`){let t=document.createElement(`button`);t.className=`ui-button ui-button--secondary auth-gate-secondary-button`,t.type=`button`,t.textContent=r,t.addEventListener(`click`,()=>{i()}),e.append(t)}}function _(e,t,{onSubmit:n}){e.replaceChildren();let r=document.createElement(`h1`);r.textContent=`Authentication required`;let i=document.createElement(`p`);i.textContent=`Enter the host password to join this shared session.`;let a=document.createElement(`form`);a.className=`auth-gate-form`;let o=document.createElement(`label`);o.className=`auth-gate-label`,o.textContent=t.passwordLabel;let s=document.createElement(`input`);s.className=`ui-input auth-gate-input`,s.type=`password`,s.name=`password`,s.autocomplete=`current-password`,s.required=!0;let c=document.createElement(`div`);c.className=`auth-gate-error`;let l=document.createElement(`div`);l.className=`auth-gate-actions`;let u=document.createElement(`button`);u.className=`ui-button ui-button--primary auth-gate-button`,u.type=`submit`,u.textContent=t.submitLabel,l.append(u),o.append(s),a.append(r,i,o,c,l),e.append(a),a.addEventListener(`submit`,e=>{e.preventDefault();let t=s.value;s.disabled=!0,u.disabled=!0,c.textContent=``,n(t).catch(e=>{c.textContent=e instanceof Error?e.message:`Authentication failed`,s.disabled=!1,u.disabled=!1,s.select(),s.focus()})}),queueMicrotask(()=>{s.focus()})}async function v(){let e=i();if(!e.enabled||e.strategy===`none`)return{authenticated:!0,auth:e};let{card:t,overlay:n}=p();document.body.append(n);let r=c(`auth_error`);return new Promise(i=>{let a=(t=null)=>{s(),d(t),n.remove(),i({authenticated:!0,auth:t?.auth??e,user:t?.user??null})};(async()=>{g(t,{body:`Checking access to this session…`,title:`CollabMD`});try{let t=await u(e);if(t.authenticated){a(t);return}}catch(e){g(t,{body:e instanceof Error?`${e.message} Refresh the page and try again.`:`Failed to contact the auth service. Refresh the page and try again.`,title:`Cannot verify access`});return}if(e.strategy===`password`){let n=o();if(n)try{s(),await f(e,n),a();return}catch{}_(t,e,{onSubmit:async t=>{await f(e,t),a()}});return}if(e.strategy===`oidc`){h(t,e,{errorMessage:r}),r=``;return}g(t,{body:`This authentication strategy is not available.`,title:`Authentication unavailable`})})()})}function y(e){return encodeURIComponent(String(e??``))}function b(e){return String(e??``).replace(/\/+$/u,``).split(`/`).filter(Boolean).pop()||``}function x(e,t){let n=URL.createObjectURL(e),r=document.createElement(`a`);r.href=n,r.download=t,document.body.appendChild(r),r.click(),r.remove(),window.setTimeout(()=>URL.revokeObjectURL(n),0)}function S(e=``,t=`download`){let n=String(e).match(/filename\*=UTF-8''([^;]+)/iu);if(n)try{return decodeURIComponent(n[1])}catch{return t}return String(e).match(/filename="([^"]+)"/iu)?.[1]||t}function C(e,t={}){let n={...t};return e&&(n[`X-CollabMD-Request-Id`]=String(e)),n}async function w(e,t){let n=await e.json().catch(()=>({}));if(!e.ok||n.ok===!1){let r=Error(n.error||t);throw r.status=e.status,r.body=n,r}return n}async function T(e,{fallbackError:t,fallbackFileName:n}={}){let r=await fetch(e);if(!r.ok){let e=await r.json().catch(()=>({}));throw Error(e.error||t)}return x(await r.blob(),S(r.headers.get(`content-disposition`)||``,n)),r}var E=new class{async readTree(){return w(await fetch(e(`/files`)),`Failed to load file tree`)}async readFile(t){return w(await fetch(e(`/file?path=${encodeURIComponent(t)}`)),`Failed to read file`)}async queryBase({activeFilePath:t=``,path:n=``,search:r=``,source:i=null,sourcePath:a=``,view:o=``}={}){return w(await fetch(e(`/base/query`),{body:JSON.stringify({activeFilePath:t,path:n,search:r,source:i,sourcePath:a,view:o}),headers:{"Content-Type":`application/json`},method:`POST`}),`Failed to query base`)}async exportBaseCsv({activeFilePath:t=``,path:n=``,search:r=``,source:i=null,sourcePath:a=``,view:o=``}={}){let s=await fetch(e(`/base/export`),{body:JSON.stringify({activeFilePath:t,path:n,search:r,source:i,sourcePath:a,view:o}),headers:{"Content-Type":`application/json`},method:`POST`});if(!s.ok){let e=await s.json().catch(()=>({}));throw Error(e.error||`Failed to export base CSV`)}return{blob:await s.blob(),contentDisposition:s.headers.get(`content-disposition`)||``}}async queryBasePropertyValues({activeFilePath:t=``,path:n=``,propertyId:r=``,query:i=``,source:a=null,sourcePath:o=``,view:s=``}={}){return w(await fetch(e(`/base/property-values`),{body:JSON.stringify({activeFilePath:t,path:n,propertyId:r,query:i,source:a,sourcePath:o,view:s}),headers:{"Content-Type":`application/json`},method:`POST`}),`Failed to load base property values`)}async transformBase({activeFilePath:t=``,mutation:n=null,path:r=``,source:i=null,sourcePath:a=``,view:o=``}={}){return w(await fetch(e(`/base/transform`),{body:JSON.stringify({activeFilePath:t,mutation:n,path:r,source:i,sourcePath:a,view:o}),headers:{"Content-Type":`application/json`},method:`POST`}),`Failed to transform base`)}async createFile({content:t,path:n,requestId:r=null}){return w(await fetch(e(`/file`),{body:JSON.stringify({content:t,path:n}),headers:C(r,{"Content-Type":`application/json`}),method:`POST`}),`Failed to create file`)}async writeFile({content:t,path:n,requestId:r=null}){return w(await fetch(e(`/file`),{body:JSON.stringify({content:t,path:n}),headers:C(r,{"Content-Type":`application/json`}),method:`PUT`}),`Failed to write file`)}async renameFile({oldPath:t,newPath:n,requestId:r=null}){return w(await fetch(e(`/file`),{body:JSON.stringify({newPath:n,oldPath:t}),headers:C(r,{"Content-Type":`application/json`}),method:`PATCH`}),`Failed to rename file`)}async deleteFile(t,{requestId:n=null}={}){return w(await fetch(e(`/file?path=${encodeURIComponent(t)}`),{headers:n?C(n):void 0,method:`DELETE`}),`Failed to delete file`)}async createDirectory(t,{requestId:n=null}={}){return w(await fetch(e(`/directory`),{body:JSON.stringify({path:t}),headers:C(n,{"Content-Type":`application/json`}),method:`POST`}),`Failed to create folder`)}async renameDirectory({oldPath:t,newPath:n,requestId:r=null}){return w(await fetch(e(`/directory`),{body:JSON.stringify({newPath:n,oldPath:t}),headers:C(r,{"Content-Type":`application/json`}),method:`PATCH`}),`Failed to rename folder`)}async deleteDirectory(t,{recursive:n=!1,requestId:r=null}={}){let i=new URLSearchParams({path:String(t??``)});return n&&i.set(`recursive`,`1`),w(await fetch(e(`/directory?${i.toString()}`),{headers:r?C(r):void 0,method:`DELETE`}),`Failed to delete folder`)}async uploadImageAttachment({file:t,fileName:n=``,sourcePath:r}){return w(await fetch(e(`/attachments`),{body:t,headers:{"Content-Type":t?.type||`application/octet-stream`,"X-CollabMD-File-Name":y(n),"X-CollabMD-Source-Path":y(r)},method:`POST`}),`Failed to upload image`)}async downloadFile(t){let n=b(t)||`download`;return T(e(`/download/file?path=${encodeURIComponent(t)}`),{fallbackError:`Failed to download file`,fallbackFileName:n})}async downloadDirectory(t){let n=b(t)||`vault`;return T(e(`/download/directory?path=${encodeURIComponent(t)}`),{fallbackError:`Failed to download folder`,fallbackFileName:`${n}.zip`})}};export{v as n,E as t};
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>draw.io — CollabMD</title>
|
|
7
|
-
<script type="module" crossorigin src="./assets/drawioEditor-
|
|
7
|
+
<script type="module" crossorigin src="./assets/drawioEditor-D6clB5OH.js"></script>
|
|
8
8
|
<link rel="modulepreload" crossorigin href="./assets/runtime-config-loader-_D2KZKn-.js">
|
|
9
9
|
<link rel="modulepreload" crossorigin href="./assets/preload-helper-Bo9GmnuQ.js">
|
|
10
10
|
</head>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Excalidraw — CollabMD</title>
|
|
7
|
-
<script type="module" crossorigin src="./assets/excalidrawEditor-
|
|
7
|
+
<script type="module" crossorigin src="./assets/excalidrawEditor-DD4AvzYP.js"></script>
|
|
8
8
|
<link rel="modulepreload" crossorigin href="./assets/runtime-config-loader-_D2KZKn-.js">
|
|
9
9
|
<link rel="modulepreload" crossorigin href="./assets/preload-helper-Bo9GmnuQ.js">
|
|
10
10
|
</head>
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>CollabMD Export</title>
|
|
7
|
-
<script type="module" crossorigin src="./assets/exportDocument-
|
|
7
|
+
<script type="module" crossorigin src="./assets/exportDocument-Zfwq1XVx.js"></script>
|
|
8
8
|
<link rel="modulepreload" crossorigin href="./assets/runtime-config-loader-_D2KZKn-.js">
|
|
9
9
|
<link rel="modulepreload" crossorigin href="./assets/preload-helper-Bo9GmnuQ.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="./assets/base-h1uscjTi.js">
|
|
11
11
|
<link rel="stylesheet" crossorigin href="./assets/base-CaIEJUF9.css">
|
|
12
|
-
<link rel="stylesheet" crossorigin href="./assets/exportDocument-
|
|
12
|
+
<link rel="stylesheet" crossorigin href="./assets/exportDocument-BbkN85c4.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body data-theme="light" data-surface="export-document">
|
|
15
15
|
<main class="export-page-shell">
|
package/dist/client/index.html
CHANGED
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
document.documentElement.setAttribute('data-initial-file-requested', 'true');
|
|
16
16
|
}
|
|
17
17
|
</script>
|
|
18
|
-
<script type="module" crossorigin src="./assets/index-
|
|
18
|
+
<script type="module" crossorigin src="./assets/index-BLrtj9YM.js"></script>
|
|
19
19
|
<link rel="modulepreload" crossorigin href="./assets/runtime-config-loader-_D2KZKn-.js">
|
|
20
20
|
<link rel="modulepreload" crossorigin href="./assets/preload-helper-Bo9GmnuQ.js">
|
|
21
21
|
<link rel="modulepreload" crossorigin href="./assets/base-h1uscjTi.js">
|
|
22
22
|
<link rel="stylesheet" crossorigin href="./assets/base-CaIEJUF9.css">
|
|
23
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
23
|
+
<link rel="stylesheet" crossorigin href="./assets/index-BIt5EZXz.css">
|
|
24
24
|
</head>
|
|
25
25
|
<body>
|
|
26
26
|
<div id="appRoot"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "collabmd",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.34",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Collaborative markdown vault — like Obsidian, but online. Serve any directory of markdown files for realtime collaborative editing.",
|
|
6
6
|
"repository": {
|
|
@@ -84,6 +84,7 @@
|
|
|
84
84
|
"openid-client": "^6.8.2",
|
|
85
85
|
"react": "^19.2.4",
|
|
86
86
|
"react-dom": "^19.2.4",
|
|
87
|
+
"sharp": "^0.34.5",
|
|
87
88
|
"ws": "^8.20.0",
|
|
88
89
|
"y-codemirror.next": "^0.3.5",
|
|
89
90
|
"y-protocols": "^1.0.7",
|
|
@@ -98,11 +99,11 @@
|
|
|
98
99
|
"devDependencies": {
|
|
99
100
|
"@eslint/js": "^10.0.1",
|
|
100
101
|
"@playwright/test": "^1.58.2",
|
|
101
|
-
"@vitest/browser": "^4.1.
|
|
102
|
-
"@vitest/browser-playwright": "^4.1.
|
|
102
|
+
"@vitest/browser": "^4.1.2",
|
|
103
|
+
"@vitest/browser-playwright": "^4.1.2",
|
|
103
104
|
"eslint": "^10.1.0",
|
|
104
105
|
"globals": "^17.4.0",
|
|
105
|
-
"vite": "^8.0.
|
|
106
|
-
"vitest": "^4.1.
|
|
106
|
+
"vite": "^8.0.3",
|
|
107
|
+
"vitest": "^4.1.2"
|
|
107
108
|
}
|
|
108
109
|
}
|
|
@@ -232,6 +232,48 @@ export const gitFeature = {
|
|
|
232
232
|
await this.fileHistoryView.openFileHistory({ filePath });
|
|
233
233
|
},
|
|
234
234
|
|
|
235
|
+
async _loadGitFileSnapshot({ hash, filePath, resolvedCurrentFilePath }) {
|
|
236
|
+
const data = await this.gitApiClient.readFileSnapshot({
|
|
237
|
+
hash,
|
|
238
|
+
path: filePath,
|
|
239
|
+
});
|
|
240
|
+
this.setStaticPreviewDocument?.({
|
|
241
|
+
...data,
|
|
242
|
+
currentFilePath: resolvedCurrentFilePath,
|
|
243
|
+
});
|
|
244
|
+
this.resetPreviewMode();
|
|
245
|
+
this.elements.markdownToolbar?.classList.add('hidden');
|
|
246
|
+
this.elements.outlineToggle?.classList.toggle('hidden', data.fileKind !== 'markdown');
|
|
247
|
+
|
|
248
|
+
if (data.fileKind === 'markdown' || data.fileKind === 'mermaid' || data.fileKind === 'plantuml') {
|
|
249
|
+
if (data.fileKind === 'mermaid') {
|
|
250
|
+
this.elements.previewContent?.classList.add('is-mermaid-file-preview');
|
|
251
|
+
} else if (data.fileKind === 'plantuml') {
|
|
252
|
+
this.elements.previewContent?.classList.add('is-plantuml-file-preview');
|
|
253
|
+
}
|
|
254
|
+
this.previewRenderer.beginDocumentLoad();
|
|
255
|
+
this.previewRenderer.queueRender();
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
this.elements.outlineToggle?.classList.add('hidden');
|
|
260
|
+
this.renderTextFilePreview?.({
|
|
261
|
+
content: data.content,
|
|
262
|
+
filePath: resolvedCurrentFilePath,
|
|
263
|
+
});
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
_handleGitFilePreviewError(error, resolvedCurrentFilePath) {
|
|
267
|
+
console.error('[git-preview] Failed to load file snapshot:', error);
|
|
268
|
+
this.clearStaticPreviewDocument?.();
|
|
269
|
+
this.toastController.show('Failed to load historical file preview');
|
|
270
|
+
this.renderTextFilePreview?.({
|
|
271
|
+
content: 'Failed to load historical file preview.',
|
|
272
|
+
filePath: resolvedCurrentFilePath,
|
|
273
|
+
});
|
|
274
|
+
this.elements.outlineToggle?.classList.add('hidden');
|
|
275
|
+
},
|
|
276
|
+
|
|
235
277
|
async showGitFilePreview({ hash, filePath = null, currentFilePath = null } = {}) {
|
|
236
278
|
const resolvedCurrentFilePath = String(currentFilePath ?? '').trim() || filePath;
|
|
237
279
|
if (!hash || !filePath || !resolvedCurrentFilePath) {
|
|
@@ -256,43 +298,9 @@ export const gitFeature = {
|
|
|
256
298
|
this.syncFileHistoryButton({ filePath: resolvedCurrentFilePath, mode: 'history-preview' });
|
|
257
299
|
|
|
258
300
|
try {
|
|
259
|
-
|
|
260
|
-
hash,
|
|
261
|
-
path: filePath,
|
|
262
|
-
});
|
|
263
|
-
this.setStaticPreviewDocument?.({
|
|
264
|
-
...data,
|
|
265
|
-
currentFilePath: resolvedCurrentFilePath,
|
|
266
|
-
});
|
|
267
|
-
this.resetPreviewMode();
|
|
268
|
-
this.elements.markdownToolbar?.classList.add('hidden');
|
|
269
|
-
this.elements.outlineToggle?.classList.toggle('hidden', data.fileKind !== 'markdown');
|
|
270
|
-
|
|
271
|
-
if (data.fileKind === 'markdown' || data.fileKind === 'mermaid' || data.fileKind === 'plantuml') {
|
|
272
|
-
if (data.fileKind === 'mermaid') {
|
|
273
|
-
this.elements.previewContent?.classList.add('is-mermaid-file-preview');
|
|
274
|
-
} else if (data.fileKind === 'plantuml') {
|
|
275
|
-
this.elements.previewContent?.classList.add('is-plantuml-file-preview');
|
|
276
|
-
}
|
|
277
|
-
this.previewRenderer.beginDocumentLoad();
|
|
278
|
-
this.previewRenderer.queueRender();
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
this.elements.outlineToggle?.classList.add('hidden');
|
|
283
|
-
this.renderTextFilePreview?.({
|
|
284
|
-
content: data.content,
|
|
285
|
-
filePath: resolvedCurrentFilePath,
|
|
286
|
-
});
|
|
301
|
+
await this._loadGitFileSnapshot({ hash, filePath, resolvedCurrentFilePath });
|
|
287
302
|
} catch (error) {
|
|
288
|
-
|
|
289
|
-
this.clearStaticPreviewDocument?.();
|
|
290
|
-
this.toastController.show('Failed to load historical file preview');
|
|
291
|
-
this.renderTextFilePreview?.({
|
|
292
|
-
content: 'Failed to load historical file preview.',
|
|
293
|
-
filePath: resolvedCurrentFilePath,
|
|
294
|
-
});
|
|
295
|
-
this.elements.outlineToggle?.classList.add('hidden');
|
|
303
|
+
this._handleGitFilePreviewError(error, resolvedCurrentFilePath);
|
|
296
304
|
}
|
|
297
305
|
},
|
|
298
306
|
|
|
@@ -136,31 +136,7 @@ function promptForVersionReload(payload = null) {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
/** @this {UiShellContext} */
|
|
139
|
-
function
|
|
140
|
-
this.elements.emptyStateNewFileBtn?.addEventListener('click', () => {
|
|
141
|
-
this.fileExplorer.actionController.openRootCreateMenu({
|
|
142
|
-
anchor: this.elements.emptyStateNewFileBtn,
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
this.elements.emptyStateSearchBtn?.addEventListener('click', () => {
|
|
147
|
-
void this.toggleQuickSwitcher();
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
this.elements.chatToggleButton?.addEventListener('click', () => {
|
|
151
|
-
this.toggleChatPanel();
|
|
152
|
-
this.closeToolbarOverflowMenu?.();
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
this.elements.chatForm?.addEventListener('submit', (event) => {
|
|
156
|
-
event.preventDefault();
|
|
157
|
-
this.handleChatSubmit();
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
this.elements.chatNotificationButton?.addEventListener('click', () => {
|
|
161
|
-
void this.handleChatNotificationToggle();
|
|
162
|
-
});
|
|
163
|
-
|
|
139
|
+
function bindToolbarEvents() {
|
|
164
140
|
this.elements.shareButton?.addEventListener('click', () => {
|
|
165
141
|
void this.copyCurrentLink();
|
|
166
142
|
this.closeToolbarOverflowMenu?.();
|
|
@@ -197,7 +173,10 @@ function bindEvents() {
|
|
|
197
173
|
this.openDisplayNameDialog();
|
|
198
174
|
this.closeToolbarOverflowMenu?.();
|
|
199
175
|
});
|
|
176
|
+
}
|
|
200
177
|
|
|
178
|
+
/** @this {UiShellContext} */
|
|
179
|
+
function bindDialogEvents() {
|
|
201
180
|
this.elements.displayNameCancel?.addEventListener('click', () => {
|
|
202
181
|
this.elements.displayNameDialog?.close();
|
|
203
182
|
});
|
|
@@ -233,14 +212,6 @@ function bindEvents() {
|
|
|
233
212
|
}
|
|
234
213
|
});
|
|
235
214
|
|
|
236
|
-
this.elements.markdownToolbar?.addEventListener('click', (event) => {
|
|
237
|
-
this.handleMarkdownToolbarClick?.(event);
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
this.elements.markdownToolbar?.addEventListener('keydown', (event) => {
|
|
241
|
-
this.handleMarkdownToolbarKeydown?.(event);
|
|
242
|
-
});
|
|
243
|
-
|
|
244
215
|
this.elements.displayNameForm?.addEventListener('submit', (event) => {
|
|
245
216
|
event.preventDefault();
|
|
246
217
|
this.handleDisplayNameSubmit();
|
|
@@ -250,6 +221,44 @@ function bindEvents() {
|
|
|
250
221
|
event.preventDefault();
|
|
251
222
|
void this.handleGitCommitSubmit();
|
|
252
223
|
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** @this {UiShellContext} */
|
|
227
|
+
function bindEvents() {
|
|
228
|
+
this.elements.emptyStateNewFileBtn?.addEventListener('click', () => {
|
|
229
|
+
this.fileExplorer.actionController.openRootCreateMenu({
|
|
230
|
+
anchor: this.elements.emptyStateNewFileBtn,
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
this.elements.emptyStateSearchBtn?.addEventListener('click', () => {
|
|
235
|
+
void this.toggleQuickSwitcher();
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
this.elements.chatToggleButton?.addEventListener('click', () => {
|
|
239
|
+
this.toggleChatPanel();
|
|
240
|
+
this.closeToolbarOverflowMenu?.();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
this.elements.chatForm?.addEventListener('submit', (event) => {
|
|
244
|
+
event.preventDefault();
|
|
245
|
+
this.handleChatSubmit();
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
this.elements.chatNotificationButton?.addEventListener('click', () => {
|
|
249
|
+
void this.handleChatNotificationToggle();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
bindToolbarEvents.call(this);
|
|
253
|
+
bindDialogEvents.call(this);
|
|
254
|
+
|
|
255
|
+
this.elements.markdownToolbar?.addEventListener('click', (event) => {
|
|
256
|
+
this.handleMarkdownToolbarClick?.(event);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
this.elements.markdownToolbar?.addEventListener('keydown', (event) => {
|
|
260
|
+
this.handleMarkdownToolbarKeydown?.(event);
|
|
261
|
+
});
|
|
253
262
|
|
|
254
263
|
this.elements.tabLockTakeoverButton?.addEventListener('click', () => {
|
|
255
264
|
this.handleTabTakeover();
|
|
@@ -299,43 +308,53 @@ function bindEvents() {
|
|
|
299
308
|
});
|
|
300
309
|
|
|
301
310
|
document.addEventListener('pointerdown', (event) => {
|
|
302
|
-
this.
|
|
311
|
+
this.handleDocumentPointerDown(event);
|
|
312
|
+
});
|
|
303
313
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
) {
|
|
309
|
-
this.closeToolbarOverflowMenu();
|
|
310
|
-
}
|
|
314
|
+
document.addEventListener('keydown', (event) => {
|
|
315
|
+
this.handleDocumentKeydown(event);
|
|
316
|
+
});
|
|
317
|
+
}
|
|
311
318
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
319
|
+
/** @this {UiShellContext} */
|
|
320
|
+
function handleDocumentPointerDown(event) {
|
|
321
|
+
this.handleMarkdownToolbarDocumentPointerDown?.(event);
|
|
322
|
+
|
|
323
|
+
if (
|
|
324
|
+
this.toolbarOverflowOpen
|
|
325
|
+
&& !this.elements.toolbarOverflowMenu?.contains(event.target)
|
|
326
|
+
&& !this.elements.toolbarOverflowToggle?.contains(event.target)
|
|
327
|
+
) {
|
|
328
|
+
this.closeToolbarOverflowMenu();
|
|
329
|
+
}
|
|
315
330
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
331
|
+
if (!this.chatIsOpen) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
319
334
|
|
|
320
|
-
|
|
321
|
-
|
|
335
|
+
if (this.elements.chatContainer?.contains(event.target)) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
322
338
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
this.closeToolbarOverflowMenu();
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
339
|
+
this.closeChatPanel();
|
|
340
|
+
}
|
|
328
341
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
342
|
+
/** @this {UiShellContext} */
|
|
343
|
+
function handleDocumentKeydown(event) {
|
|
344
|
+
if (event.key === 'Escape' && this.toolbarOverflowOpen) {
|
|
345
|
+
this.closeToolbarOverflowMenu();
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
333
348
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
349
|
+
if (event.key === 'Escape' && this.chatIsOpen) {
|
|
350
|
+
this.closeChatPanel();
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if ((event.metaKey || event.ctrlKey) && event.key === 'k') {
|
|
355
|
+
event.preventDefault();
|
|
356
|
+
void this.toggleQuickSwitcher();
|
|
357
|
+
}
|
|
339
358
|
}
|
|
340
359
|
|
|
341
360
|
function isNestedTaskListClickTarget(target, taskItem) {
|
|
@@ -521,6 +540,8 @@ export const uiFeatureShellMethods = {
|
|
|
521
540
|
closeToolbarOverflowMenu,
|
|
522
541
|
getStoredLineWrapping,
|
|
523
542
|
handleConnectionChange,
|
|
543
|
+
handleDocumentKeydown,
|
|
544
|
+
handleDocumentPointerDown,
|
|
524
545
|
handlePreviewContentClick,
|
|
525
546
|
handleThemeChange,
|
|
526
547
|
hideEditorLoading,
|
|
@@ -306,8 +306,14 @@ export class CollabMdAppShell {
|
|
|
306
306
|
});
|
|
307
307
|
this.basesPreview = new BasesPreviewController({
|
|
308
308
|
getActiveFilePath: () => this.currentFilePath,
|
|
309
|
+
getSession: () => this.session,
|
|
309
310
|
onOpenFile: (filePath) => filePath && this.navigation.navigateToFile(filePath),
|
|
310
311
|
previewElement: this.elements.previewContent,
|
|
312
|
+
replaceBaseSource: ({ path, source }) => {
|
|
313
|
+
if (path && path === this.currentFilePath) {
|
|
314
|
+
this.session?.replaceText?.(source);
|
|
315
|
+
}
|
|
316
|
+
},
|
|
311
317
|
toastController: this.toastController,
|
|
312
318
|
vaultApiClient: this.vaultApiClient,
|
|
313
319
|
});
|
|
@@ -272,6 +272,10 @@ export class EditorSession {
|
|
|
272
272
|
return this.viewAdapter.insertText(text);
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
+
replaceText(text) {
|
|
276
|
+
return this.viewAdapter.replaceText(text);
|
|
277
|
+
}
|
|
278
|
+
|
|
275
279
|
toggleTaskListItem(lineNumber) {
|
|
276
280
|
if (!this.collaborationClient.initialSyncComplete) {
|
|
277
281
|
return false;
|
|
@@ -934,6 +934,29 @@ export class EditorViewAdapter {
|
|
|
934
934
|
return true;
|
|
935
935
|
}
|
|
936
936
|
|
|
937
|
+
replaceText(text) {
|
|
938
|
+
if (!this.editorView) {
|
|
939
|
+
return false;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
const nextText = String(text ?? '');
|
|
943
|
+
const { state } = this.editorView;
|
|
944
|
+
this.editorView.dispatch({
|
|
945
|
+
changes: {
|
|
946
|
+
from: 0,
|
|
947
|
+
insert: nextText,
|
|
948
|
+
to: state.doc.length,
|
|
949
|
+
},
|
|
950
|
+
selection: {
|
|
951
|
+
anchor: 0,
|
|
952
|
+
head: 0,
|
|
953
|
+
},
|
|
954
|
+
userEvent: 'input',
|
|
955
|
+
});
|
|
956
|
+
this.editorView.focus();
|
|
957
|
+
return true;
|
|
958
|
+
}
|
|
959
|
+
|
|
937
960
|
toggleTaskListItem(lineNumber) {
|
|
938
961
|
const state = this.editorView?.state;
|
|
939
962
|
if (!this.editorView || !state) {
|
|
@@ -141,6 +141,54 @@ export class VaultApiClient {
|
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
async queryBasePropertyValues({
|
|
145
|
+
activeFilePath = '',
|
|
146
|
+
path = '',
|
|
147
|
+
propertyId = '',
|
|
148
|
+
query = '',
|
|
149
|
+
source = null,
|
|
150
|
+
sourcePath = '',
|
|
151
|
+
view = '',
|
|
152
|
+
} = {}) {
|
|
153
|
+
const response = await fetch(resolveApiUrl('/base/property-values'), {
|
|
154
|
+
body: JSON.stringify({
|
|
155
|
+
activeFilePath,
|
|
156
|
+
path,
|
|
157
|
+
propertyId,
|
|
158
|
+
query,
|
|
159
|
+
source,
|
|
160
|
+
sourcePath,
|
|
161
|
+
view,
|
|
162
|
+
}),
|
|
163
|
+
headers: { 'Content-Type': 'application/json' },
|
|
164
|
+
method: 'POST',
|
|
165
|
+
});
|
|
166
|
+
return parseApiResponse(response, 'Failed to load base property values');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async transformBase({
|
|
170
|
+
activeFilePath = '',
|
|
171
|
+
mutation = null,
|
|
172
|
+
path = '',
|
|
173
|
+
source = null,
|
|
174
|
+
sourcePath = '',
|
|
175
|
+
view = '',
|
|
176
|
+
} = {}) {
|
|
177
|
+
const response = await fetch(resolveApiUrl('/base/transform'), {
|
|
178
|
+
body: JSON.stringify({
|
|
179
|
+
activeFilePath,
|
|
180
|
+
mutation,
|
|
181
|
+
path,
|
|
182
|
+
source,
|
|
183
|
+
sourcePath,
|
|
184
|
+
view,
|
|
185
|
+
}),
|
|
186
|
+
headers: { 'Content-Type': 'application/json' },
|
|
187
|
+
method: 'POST',
|
|
188
|
+
});
|
|
189
|
+
return parseApiResponse(response, 'Failed to transform base');
|
|
190
|
+
}
|
|
191
|
+
|
|
144
192
|
async createFile({ content, path, requestId = null }) {
|
|
145
193
|
const response = await fetch(resolveApiUrl('/file'), {
|
|
146
194
|
body: JSON.stringify({ content, path }),
|