Combine margin-block-start and margin-block-end into the margin-block
shorthand to satisfy the declaration-block-no-redundant-longhand-properties
stylelint rule.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
When working with large asset groups, users asked for a one-click way
to remove every asset under a group path. Multi-select across hundreds
of items is impractical, and ungrouping first and then deleting leaves
the orphaned items in the flat list.
This change adds a "Delete group" option to the assets-panel
context-menu for three asset types that already carry group structure:
- Components (including variants — sibling variants sharing a variant
container are deduplicated, and the container is deleted once via
the same dispatch the per-item delete uses in file_library.cljs).
- Colors.
- Typographies.
A confirmation modal is shown before deletion, with the count of
assets to be removed, so the action is never silent. All deletes run
inside a single undo transaction, so one Cmd+Z restores the whole
group.
Changes
-------
- `assets/groups.cljs` — `asset-group-title*` accepts an optional
`on-delete-group` prop and conditionally adds the menu entry
between "Ungroup" and "Combine as variants". When the callback is
not supplied the option is hidden, so asset sections that do not
implement it stay unaffected.
- `assets/components.cljs` — threads `on-delete-group` through the
recursive `components-group*` and defines the section-level
handler, dispatching to `dwsh/delete-shapes` for variant containers
and `dwl/delete-component` for plain components.
- `assets/colors.cljs` — same threading + a simple `dwl/delete-color`
dispatch per color in the group.
- `assets/typographies.cljs` — same threading + a
`dwl/delete-typography` dispatch per typography in the group.
- `translations/en.po` — three new strings: the menu label
(`workspace.assets.delete-group`) and the modal title/message
(`modals.delete-asset-group.title`/`.message`, plural-aware).
Github #9141
Signed-off-by: FairyPigDev <luislee3108@gmail.com>
Signed-off-by: FairyPiggyDev <luislee3108@gmail.com>
The ::mf/props and ::mf/wrap-props metadata keys are no-ops on modern
components (those defined with mf/defc and the * suffix) since the *
suffix already triggers the props behavior these keys attempt to
configure. This cleanup removes the redundant metadata from modern
components across all UI directories.
Changes:
- comments/: comments
- dashboard/: comments, deleted, files, fonts, grid, import, libraries,
pin_button, projects, search, sidebar, subscription, team, templates
- exports/: files
- modal/: modal
- settings/: subscription
- static/: static
- viewer/: comments, interactions, viewer
- workspace/: context_menu, libraries, sidebar/assets,
viewport/gradients, tokens/settings/menu
Let users pick the pixel grid color from a standard color picker.
The grid color was previously hardcoded, making it invisible on
mid-tone canvases. Choice is stored on the file so it persists
across sessions. Defaults preserve the current appearance when
unset.
Closes#7750
Signed-off-by: jack-stormentswe <crazycoder131@gmail.com>
Closes#7736.
The Layers sidebar offered no way to expand every nested level of a
single subtree at once. Unfolding a layer that wraps a deep tree
required clicking each disclosure indicator one level at a time -
O(siblings * depth) clicks. The asymmetry was particularly visible
next to the existing Shift+click gesture, which collapses every
layer in the panel in a single action via `dwc/collapse-all`, with
no expand counterpart for either a single subtree or the whole
tree.
Add a new `dwc/expand-subtree` event in
`app.main.data.workspace.collapse` that uses
`cfh/get-children-ids-with-self` to gather the shape's id together
with every descendant id, then merges `{descendant-id true}` entries
into `[:workspace-local :expanded]` so the entire subtree opens in
one update. Existing expansion state on unrelated branches is left
untouched (`merge`, not `assoc`), matching the per-key shape used by
`toggle-collapse` and `expand-collapse`.
Wire the gesture into `layer_item.cljs` `toggle-collapse` callback as
a third branch:
- Shift+click while expanded - collapse every layer (existing).
- Alt+click while collapsed - expand the entire subtree (new).
- Otherwise - toggle this single level (existing).
Alt is chosen instead of Shift to avoid the ambiguity the issue
author flagged: "for a layer of middle depth it is unclear whether
[Shift+click] should fold all (up to the topmost parent) or expand
all (only the current subtree)". Alt is a common platform
convention for "do this recursively" (Finder, file managers,
several IDEs), so the asymmetric mapping matches user expectations.
The callback's `mf/deps` vector is extended with `id` and `objects`
so the closure refreshes when the shape tree changes.
CHANGES.md entry added under the 2.17.0 New features section.
`library.connectLibrary()` declared its permission check **outside** the
`js/Promise.` wrapper, so when a plugin without `library:write` permission
called `await library.connectLibrary(id)` the method did not return a
`Promise` at all:
- With the default `throwValidationErrors` flag off → `u/not-valid`
logs to console and returns `nil`. `await nil` resolves to `nil`, so
the plugin sees a "successful" result and crashes later when it tries
to use methods on what it thinks is a `LibraryProxy`.
- With `throwValidationErrors` on → `u/not-valid` throws synchronously,
so the caller gets a thrown exception instead of a rejected promise —
inconsistent with every other `library:*` / `content:*` method which
always returns a Promise that rejects via `reject-not-valid`.
Additionally, the in-Promise `(not (string? library-id))` branch used
`(reject nil)` — the plugin got a rejected Promise but with no error
message.
Move the permission check inside the Promise constructor and replace
both validation errors with `u/reject-not-valid`, matching the pattern
used by the sibling methods `restore`, `remove`, `pin`, `saveVersion`,
`findVersions` in `frontend/src/app/plugins/file.cljs` and every other
promise-returning plugin method. No new imports.
Also add a CHANGES.md entry under the 2.17.0 Unreleased bugs-fixed section.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
Closes#9092.
`restore-version-from-plugin` accepted `_reject` as a dead parameter and
its stream had no `rx/catch`, so errors raised during the restore flow
(failed `rp/cmd! :restore-file-snapshot`, persistence timeouts, or
exceptions inside the watch body) silently swallowed instead of
rejecting the plugin-facing promise at `file.cljs:81`. Plugin code
that did `await version.restore()` would hang indefinitely on any
failure.
Wire `reject` through and wrap the emission with the same `rx/catch`
pattern already used by `create-version-from-plugins` in this file.
- Rename `_reject` to `reject` in the function signature
- Wrap the `rx/concat` body with `rx/catch` that calls `(reject error)`
and returns `rx/empty` on error, mirroring `create-version-from-plugins`
- Add a CHANGES.md entry under the 2.17.0 Unreleased bugs-fixed section
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
The malli schema for the LDAP provider params (`schema:params` in
`backend/src/app/auth/ldap.clj`) declared the bind-password slot as
`:bind-passwor` (missing trailing `d`). The runtime code in the same
file uses `:bind-password` everywhere — `prepare-params` reads
`(:bind-password cfg)` on line 21 and `try-connectivity` reads
`(:bind-password cfg)` on line 89. Effects of the typo:
1. The schema slot for `:bind-password` is missing, so a wrong type
(e.g. a number or vector instead of a string) for the actual key
slips through `check-params` unvalidated. Malli `[:map ...]` is
open by default, so the genuine `:bind-password` key is silently
accepted as an unknown extra key.
2. Anyone reading the schema (operator, future contributor, or
tooling generating docs) sees a non-existent `:bind-passwor`
parameter and could legitimately set that key — schema would
accept it, runtime would never read it, LDAP bind would silently
fail with a confusing "no password" error.
Cross-checked against the pre-malli `clojure.spec` shape removed in
commit 88fb5e7ab (2024-10-29, "♻️ Update integrant to latest
version", which carried the spec→malli migration). The deleted spec
defined `(s/def ::bind-password ::us/string)` correctly — the typo
was introduced when re-typing the keys into the new malli vector-of-
tuples form.
Add a CHANGES.md entry under the 2.17.0 Unreleased 🐛 Bugs fixed
section.
One-character fix.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
login-with-ldap raised a :restriction exception with the message
"ldap auth provider is not initialized" stored under :hide instead
of :hint. ex/raise (common/src/app/common/exceptions.cljc:33-34)
uses :hint as the ExceptionInfo message and the downstream error
formatters only read :hint (line 250, 312) — :hide is unread
anywhere in the codebase (0 other occurrences vs 447 for :hint).
Effect: when LDAP is misconfigured, operators saw the generic
"restriction" error message instead of the diagnostic string. The
typo has been present since the LDAP command was first introduced
by commit 14d1cb90bd (2022-06-30, "Refactor auth code") and was
carried forward through 6cdf696fc (2023-01-05, "Fix issues on ldap
provider and rpc method") without ever surfacing as a code-review
comment.
One-character fix: :hide -> :hint. Add a CHANGES.md entry under
the 2.17.0 Unreleased 🐛 Bugs fixed section.