mirror of
https://github.com/logseq/logseq.git
synced 2026-02-01 22:47:36 +00:00
feat: add a secret global flag to load graph progammtically (#3531)
* feat: add a secret global flag to load graph from a user defined dir * fix: use LOGSEQ_OVERWRITE_OPEN_DIR env var to overwrite the openning graph dir * e2e: add a test for load & check saved graph data * fix: should also pass in process.env for testing fixtures * feat: new way to set open dir folder * fix: e2e * fix: remove playwright global flag check Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,6 +13,7 @@ pom.xml.asc
|
||||
|
||||
node_modules/
|
||||
static/
|
||||
tmp
|
||||
|
||||
.cpcache/
|
||||
/src/gen
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { test } from './fixtures'
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import { test, graphDir } from './fixtures'
|
||||
import { randomString, createRandomPage, newBlock } from './utils'
|
||||
|
||||
|
||||
@@ -41,7 +43,7 @@ test('search', async ({ page }) => {
|
||||
})
|
||||
|
||||
test('create page and blocks', async ({ page }) => {
|
||||
await createRandomPage(page)
|
||||
const pageTitle = await createRandomPage(page)
|
||||
|
||||
// do editing
|
||||
await page.fill(':nth-match(textarea, 1)', 'this is my first bullet')
|
||||
@@ -81,6 +83,21 @@ test('create page and blocks', async ({ page }) => {
|
||||
await page.keyboard.press('Escape')
|
||||
await page.waitForTimeout(500)
|
||||
expect(await page.$$('.ls-block')).toHaveLength(5)
|
||||
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
const contentOnDisk = await fs.readFile(
|
||||
path.join(graphDir, `pages/${pageTitle}.md`),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
expect(contentOnDisk.trim()).toEqual(`
|
||||
- this is my first bullet
|
||||
- this is my second bullet
|
||||
- this is my third bullet
|
||||
- continue editing test
|
||||
continue
|
||||
- test ok`.trim())
|
||||
})
|
||||
|
||||
test('delete and backspace', async ({ page }) => {
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { test as base, expect, ConsoleMessage } from '@playwright/test';
|
||||
import { ElectronApplication, Page, BrowserContext, _electron as electron } from 'playwright'
|
||||
import { loadLocalGraph, randomString } from './utils';
|
||||
|
||||
let electronApp: ElectronApplication
|
||||
let context: BrowserContext
|
||||
let page: Page
|
||||
let repoName = randomString(10)
|
||||
export let graphDir = path.resolve(__dirname, '../tmp/e2e-graph', repoName)
|
||||
|
||||
// NOTE: This is a console log watcher for error logs.
|
||||
const consoleLogWatcher = (msg: ConsoleMessage) => {
|
||||
@@ -19,9 +24,14 @@ base.beforeAll(async () => {
|
||||
return
|
||||
}
|
||||
|
||||
fs.mkdirSync(graphDir, {
|
||||
recursive: true,
|
||||
});
|
||||
|
||||
electronApp = await electron.launch({
|
||||
cwd: "./static",
|
||||
args: ["electron.js"],
|
||||
locale: 'en',
|
||||
})
|
||||
context = electronApp.context()
|
||||
await context.tracing.start({ screenshots: true, snapshots: true });
|
||||
@@ -51,6 +61,8 @@ base.beforeAll(async () => {
|
||||
console.log('Page loaded!')
|
||||
await page.screenshot({ path: 'startup.png' })
|
||||
})
|
||||
|
||||
await loadLocalGraph(page, graphDir);
|
||||
})
|
||||
|
||||
base.beforeEach(async () => {
|
||||
|
||||
@@ -33,6 +33,8 @@ export async function createRandomPage(page: Page) {
|
||||
await page.click('text=/.*New page: ".*/')
|
||||
// wait for textarea of first block
|
||||
await page.waitForSelector(':nth-match(textarea, 1)', { state: 'visible' })
|
||||
|
||||
return randomTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,6 +103,48 @@ export async function escapeToBlockEditor(page: Page): Promise<void> {
|
||||
await page.waitForTimeout(500)
|
||||
}
|
||||
|
||||
export async function setMockedOpenDirPath(
|
||||
page: Page,
|
||||
path?: string
|
||||
): Promise<void> {
|
||||
// set next open directory
|
||||
await page.evaluate(
|
||||
([path]) => {
|
||||
Object.assign(window, {
|
||||
__MOCKED_OPEN_DIR_PATH__: path,
|
||||
})
|
||||
},
|
||||
[path]
|
||||
)
|
||||
}
|
||||
|
||||
export async function loadLocalGraph(page: Page, path?: string): Promise<void> {
|
||||
const hasOpenButton = await page.$('#head >> .button >> text=Open')
|
||||
await setMockedOpenDirPath(page, path);
|
||||
if (hasOpenButton) {
|
||||
await page.click('#head >> .button >> text=Open')
|
||||
} else {
|
||||
if (!(await page.$('.ls-left-sidebar-open'))) {
|
||||
await page.click('.cp__header-left-menu.button')
|
||||
}
|
||||
await page.click('#left-sidebar >> #repo-switch')
|
||||
await page.click('text=Add new graph')
|
||||
await page.waitForSelector('h1:has-text("Open a local directory")')
|
||||
await page.click('h1:has-text("Open a local directory")')
|
||||
}
|
||||
|
||||
setMockedOpenDirPath(page, ''); // reset it
|
||||
|
||||
await page.waitForSelector(':has-text("Parsing files")', {
|
||||
state: 'hidden',
|
||||
timeout: 1000 * 60 * 5,
|
||||
})
|
||||
|
||||
await page.waitForFunction('window.document.title != "Loading"')
|
||||
|
||||
console.log('Graph loaded for ' + path)
|
||||
}
|
||||
|
||||
export async function activateNewPage(page: Page) {
|
||||
await page.click('.ls-block >> nth=0')
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
@@ -83,13 +83,14 @@ contextBridge.exposeInMainWorld('apis', {
|
||||
*
|
||||
* @param {string} html html file with embedded state
|
||||
*/
|
||||
exportPublishAssets (html, customCSSPath, repoPath, assetFilenames) {
|
||||
exportPublishAssets (html, customCSSPath, repoPath, assetFilenames, outputDir) {
|
||||
ipcRenderer.invoke(
|
||||
'export-publish-assets',
|
||||
html,
|
||||
customCSSPath,
|
||||
repoPath,
|
||||
assetFilenames
|
||||
assetFilenames,
|
||||
outputDir
|
||||
)
|
||||
},
|
||||
|
||||
|
||||
@@ -68,12 +68,10 @@
|
||||
(.unregisterProtocol protocol LSP_SCHEME)
|
||||
(.unregisterProtocol protocol "assets")))
|
||||
|
||||
(defn- handle-export-publish-assets [_event html custom-css-path repo-path asset-filenames]
|
||||
(defn- handle-export-publish-assets [_event html custom-css-path repo-path asset-filenames output-path]
|
||||
(p/let [app-path (. app getAppPath)
|
||||
asset-filenames (js->clj asset-filenames)
|
||||
result (. dialog showOpenDialog (clj->js {:properties ["openDirectory" "createDirectory" "promptToCreate", "multiSelections"]}))
|
||||
result (get (js->clj result) "filePaths")
|
||||
root-dir (first result)]
|
||||
root-dir (or output-path (handler/open-dir-dialog))]
|
||||
(when root-dir
|
||||
(let [static-dir (path/join root-dir "static")
|
||||
assets-from-dir (path/join repo-path "assets")
|
||||
|
||||
@@ -139,11 +139,14 @@
|
||||
(remove nil?))]
|
||||
(vec (cons {:path (utils/fix-win-path! path)} result))))
|
||||
|
||||
(defmethod handle :openDir [^js window _messages]
|
||||
(defn open-dir-dialog []
|
||||
(p/let [result (.showOpenDialog dialog (bean/->js
|
||||
{:properties ["openDirectory" "createDirectory" "promptToCreate"]}))
|
||||
result (get (js->clj result) "filePaths")
|
||||
path (first result)]
|
||||
result (get (js->clj result) "filePaths")]
|
||||
(p/resolved (first result))))
|
||||
|
||||
(defmethod handle :openDir [^js window _messages]
|
||||
(p/let [path (open-dir-dialog)]
|
||||
(if path
|
||||
(p/resolved (bean/->js (get-files path)))
|
||||
(p/rejected (js/Error "path empty")))))
|
||||
@@ -269,10 +272,7 @@
|
||||
(watcher/watch-dir! window dir)))
|
||||
|
||||
(defmethod handle :openDialog [^js window messages]
|
||||
(p/let [result (.showOpenDialog dialog (bean/->js
|
||||
{:properties ["openDirectory"]}))
|
||||
result (get (js->clj result) "filePaths")]
|
||||
(p/resolved (first result))))
|
||||
(open-dir-dialog))
|
||||
|
||||
(defmethod handle :getLogseqDotDirRoot []
|
||||
(utils/get-ls-dotdir-root))
|
||||
|
||||
@@ -92,6 +92,13 @@
|
||||
(error-handler error)
|
||||
(log/error :write-file-failed error)))))))))
|
||||
|
||||
(defn- open-dir []
|
||||
(p/let [dir-path (util/mocked-open-dir-path)
|
||||
result (if dir-path
|
||||
(ipc/ipc "getFiles" dir-path)
|
||||
(ipc/ipc "openDir" {}))]
|
||||
result))
|
||||
|
||||
(defrecord Node []
|
||||
protocol/Fs
|
||||
(mkdir! [this dir]
|
||||
@@ -124,7 +131,7 @@
|
||||
(let [path (concat-path dir path)]
|
||||
(ipc/ipc "stat" path)))
|
||||
(open-dir [this ok-handler]
|
||||
(ipc/ipc "openDir" {}))
|
||||
(open-dir))
|
||||
(get-files [this path-or-handle ok-handler]
|
||||
(ipc/ipc "getFiles" path-or-handle))
|
||||
(watch-dir! [this dir]
|
||||
|
||||
@@ -106,7 +106,12 @@
|
||||
html-str (str "data:text/html;charset=UTF-8,"
|
||||
(js/encodeURIComponent raw-html-str))]
|
||||
(if (util/electron?)
|
||||
(js/window.apis.exportPublishAssets raw-html-str (config/get-custom-css-path) (config/get-repo-dir repo) (clj->js asset-filenames))
|
||||
(js/window.apis.exportPublishAssets
|
||||
raw-html-str
|
||||
(config/get-custom-css-path)
|
||||
(config/get-repo-dir repo)
|
||||
(clj->js asset-filenames)
|
||||
(util/mocked-open-dir-path))
|
||||
|
||||
(when-let [anchor (gdom/getElement "download-as-html")]
|
||||
(.setAttribute anchor "href" html-str)
|
||||
|
||||
@@ -71,6 +71,12 @@
|
||||
(let [ua (string/lower-case js/navigator.userAgent)]
|
||||
(string/includes? ua " electron")))))
|
||||
|
||||
#?(:cljs
|
||||
(defn mocked-open-dir-path
|
||||
"Mocked open DIR path for by-passing open dir in electron during testing. Nil if not given"
|
||||
[]
|
||||
(when (electron?) (. js/window -__MOCKED_OPEN_DIR_PATH__))))
|
||||
|
||||
#?(:cljs
|
||||
(def nfs? (and (not (electron?))
|
||||
(not (is-native-platform?)))))
|
||||
|
||||
Reference in New Issue
Block a user