mirror of
https://github.com/logseq/logseq.git
synced 2026-05-23 20:24:15 +00:00
Merge branch 'master' into enhance/keymaps-manager-x
This commit is contained in:
@@ -139,7 +139,17 @@ By convention, a namespace's tests are found at a corresponding namespace
|
||||
of the same name with an added `-test` suffix. For example, tests
|
||||
for `frontend.db.model` are found in `frontend.db.model-test`.
|
||||
|
||||
There are a couple different ways to develop with tests:
|
||||
There are a couple different ways to run tests:
|
||||
|
||||
* [Focus tests](#focus-tests) - Run one or more tests from the CLI
|
||||
* [Autorun tests](#autorun-tests) - Autorun tests from the CLI
|
||||
* [Repl tests](#repl-tests) - Run tests from REPL
|
||||
|
||||
There a couple types of tests and they can overlap with each other:
|
||||
|
||||
* [Database tests](#database-tests) - Tests that involve a datascript DB.
|
||||
* [Performance tests](#performance-tests) - Tests that aim to measure and enforce a performance characteristic.
|
||||
* [Async tests](#async-tests) - Tests that run async code and require some helpers.
|
||||
|
||||
#### Focus Tests
|
||||
|
||||
@@ -166,6 +176,15 @@ To run tests automatically on file save, run `clojure -M:test watch test
|
||||
the `:ns-regexp` option e.g. `clojure -M:test watch test --config-merge
|
||||
'{:autorun true :ns-regexp "frontend.util.page-property-test"}'`.
|
||||
|
||||
#### REPL tests
|
||||
|
||||
Most unit tests e.g. ones that are browser compatible and don't require node libraries, can be run from the REPL. To do so:
|
||||
|
||||
* Start a REPL for your editor. See [here for an example](https://github.com/logseq/logseq/blob/master/docs/develop-logseq.md#repl-setup).
|
||||
* Load a test namespace.
|
||||
* Run `(cljs.test/run-tests)` to run tests for the current test namespace.
|
||||
|
||||
|
||||
#### Database tests
|
||||
|
||||
To write a test that uses a datascript db:
|
||||
@@ -188,7 +207,7 @@ To write a performance test:
|
||||
|
||||
For examples of these tests, see `frontend.db.query-dsl-test` and `frontend.db.model-test`.
|
||||
|
||||
### Async Unit Testing
|
||||
#### Async Tests
|
||||
|
||||
Async unit testing is well supported in ClojureScript.
|
||||
https://clojurescript.org/tools/testing#async-testing is a good guide for how to
|
||||
|
||||
@@ -159,6 +159,38 @@ test('undo the delete action', async ({ page }) => {
|
||||
await expect(page.locator('.logseq-tldraw .tl-line-container')).toHaveCount(1)
|
||||
})
|
||||
|
||||
test('convert the first rectangle to ellipse', async ({ page }) => {
|
||||
await page.keyboard.press('Escape')
|
||||
await page.waitForTimeout(1000)
|
||||
await page.click('.logseq-tldraw .tl-box-container:first-of-type')
|
||||
await page.mouse.move(0, 0) // move mouse to trigger a rerender of the context bar
|
||||
await page.click('.tl-context-bar .tl-geometry-tools-pane-anchor')
|
||||
await page.click('.tl-context-bar .tl-geometry-toolbar [data-tool=ellipse]')
|
||||
|
||||
await expect(page.locator('.logseq-tldraw .tl-ellipse-container')).toHaveCount(1)
|
||||
await expect(page.locator('.logseq-tldraw .tl-box-container')).toHaveCount(1)
|
||||
})
|
||||
|
||||
test('change the color of the ellipse', async ({ page }) => {
|
||||
await page.click('.tl-context-bar .tl-color-bg')
|
||||
await page.click('.tl-context-bar .tl-color-palette .bg-red-500')
|
||||
|
||||
await expect(page.locator('.logseq-tldraw .tl-ellipse-container ellipse:last-of-type')).toHaveAttribute('fill', 'var(--ls-wb-background-color-red)')
|
||||
})
|
||||
|
||||
test('undo the color switch', async ({ page }) => {
|
||||
await page.keyboard.press(modKey + '+z')
|
||||
|
||||
await expect(page.locator('.logseq-tldraw .tl-ellipse-container ellipse:last-of-type')).toHaveAttribute('fill', 'var(--ls-wb-background-color-default)')
|
||||
})
|
||||
|
||||
test('undo the shape conversion', async ({ page }) => {
|
||||
await page.keyboard.press(modKey + '+z')
|
||||
|
||||
await expect(page.locator('.logseq-tldraw .tl-box-container')).toHaveCount(2)
|
||||
await expect(page.locator('.logseq-tldraw .tl-ellipse-container')).toHaveCount(0)
|
||||
})
|
||||
|
||||
test('locked elements should not be removed', async ({ page }) => {
|
||||
await page.keyboard.press('Escape')
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
@@ -667,14 +667,20 @@
|
||||
[]
|
||||
[:div.panel-wrap
|
||||
[:div.text-sm.my-4
|
||||
(ui/admonition
|
||||
:tip
|
||||
[:p "If you have Logseq Sync enabled, you can view a page's edit history directly. This section is for tech-savvy only."])
|
||||
[:span.text-sm.opacity-50.my-4
|
||||
"To view page's edit history, click the three horizontal dots in the top-right corner and select \"View page history\"."]
|
||||
[:br][:br]
|
||||
[:span.text-sm.opacity-50.my-4
|
||||
"You can view a page's edit history by clicking the three horizontal dots "
|
||||
"in the top-right corner and selecting \"View page history\". "
|
||||
"Logseq uses "]
|
||||
"For professional users, Logseq also supports using "]
|
||||
[:a {:href "https://git-scm.com/" :target "_blank"}
|
||||
"Git"]
|
||||
[:span.text-sm.opacity-50.my-4
|
||||
" for version control."]]
|
||||
" for version control."]
|
||||
[:span.text-sm.opacity-50.my-4
|
||||
"Use Git at your own risk as general Git issues are not supported by the Logseq team"]]
|
||||
[:br]
|
||||
(switch-git-auto-commit-row t)
|
||||
(git-auto-commit-seconds t)
|
||||
@@ -827,9 +833,7 @@
|
||||
[[:general "general" (t :settings-page/tab-general) (ui/icon "adjustments")]
|
||||
[:editor "editor" (t :settings-page/tab-editor) (ui/icon "writing")]
|
||||
|
||||
(when (and
|
||||
(util/electron?)
|
||||
(not (file-sync-handler/synced-file-graph? current-repo)))
|
||||
(when (util/electron?)
|
||||
[:git "git" (t :settings-page/tab-version-control) (ui/icon "history")])
|
||||
|
||||
;; (when (util/electron?)
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
:getBlockPageName #(:block/name (model/get-block-page (state/get-current-repo) (parse-uuid %)))
|
||||
:exportToImage (fn [page-name options] (state/set-modal! #(export/export-blocks page-name (merge (js->clj options :keywordize-keys true) {:whiteboard? true}))))
|
||||
:isWhiteboardPage model/whiteboard-page?
|
||||
:isMobile (util/mobile?)
|
||||
:isMobile util/mobile?
|
||||
:saveAsset save-asset-handler
|
||||
:makeAssetUrl editor-handler/make-asset-url
|
||||
:copyToClipboard (fn [text, html] (util/copy-to-clipboard! text :html html))
|
||||
|
||||
@@ -133,9 +133,7 @@ const LogseqPortalViewModeAction = observer(() => {
|
||||
<div className="flex">
|
||||
{collapsed ? 'Expand' : 'Collapse'}
|
||||
<KeyboardShortcut
|
||||
action={
|
||||
collapsed ? 'editor/expand-block-children' : 'editor/collapse-block-children'
|
||||
}
|
||||
action={collapsed ? 'editor/expand-block-children' : 'editor/collapse-block-children'}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
@@ -253,7 +251,7 @@ const NoFillAction = observer(() => {
|
||||
const app = useApp<Shape>()
|
||||
const shapes = filterShapeByAction<BoxShape | PolygonShape | EllipseShape>('NoFill')
|
||||
const handleChange = React.useCallback((v: boolean) => {
|
||||
shapes.forEach(s => s.update({ noFill: v }))
|
||||
app.selectedShapesArray.forEach(s => s.update({ noFill: v }))
|
||||
app.persist()
|
||||
}, [])
|
||||
|
||||
@@ -279,14 +277,14 @@ const SwatchAction = observer(() => {
|
||||
>('Swatch')
|
||||
|
||||
const handleSetColor = React.useCallback((color: string) => {
|
||||
shapes.forEach(s => {
|
||||
app.selectedShapesArray.forEach(s => {
|
||||
s.update({ fill: color, stroke: color })
|
||||
})
|
||||
app.persist()
|
||||
}, [])
|
||||
|
||||
const handleSetOpacity = React.useCallback((opacity: number) => {
|
||||
shapes.forEach(s => {
|
||||
app.selectedShapesArray.forEach(s => {
|
||||
s.update({ opacity: opacity })
|
||||
})
|
||||
app.persist()
|
||||
|
||||
@@ -98,7 +98,11 @@ export class EllipseShape extends TLEllipseShape<EllipseShapeProps> {
|
||||
)
|
||||
|
||||
return (
|
||||
<div {...events} style={{ width: '100%', height: '100%', overflow: 'hidden' }}>
|
||||
<div
|
||||
{...events}
|
||||
style={{ width: '100%', height: '100%', overflow: 'hidden' }}
|
||||
className="tl-ellipse-container"
|
||||
>
|
||||
<TextLabel
|
||||
font={font}
|
||||
text={label}
|
||||
|
||||
@@ -428,6 +428,7 @@ export class TLApi<S extends TLShape = TLShape, K extends TLEventMap = TLEventMa
|
||||
return new ShapeClass({
|
||||
...s.serialized,
|
||||
type: type,
|
||||
nonce: Date.now(),
|
||||
})
|
||||
})
|
||||
this.app.currentPage.addShapes(...clones)
|
||||
|
||||
@@ -17,11 +17,10 @@ export class ContextMenuState<
|
||||
onEnter = (info: TLEventInfo<S>) => {
|
||||
const {
|
||||
selectedIds,
|
||||
selectedShapes,
|
||||
inputs: { shiftKey },
|
||||
} = this.app
|
||||
|
||||
if (info.type === TLTargetType.Shape && !selectedShapes.has(info.shape)) {
|
||||
if (info.type === TLTargetType.Shape && !selectedIds.has(info.shape.id)) {
|
||||
const shape = this.app.getParentGroup(info.shape) ?? info.shape
|
||||
if (shiftKey) {
|
||||
this.app.setSelectedShapes([...Array.from(selectedIds.values()), shape.id])
|
||||
|
||||
Reference in New Issue
Block a user