Skip to content

Tags - #22

Open
shsteimer wants to merge 28 commits into
mainfrom
tags
Open

Tags#22
shsteimer wants to merge 28 commits into
mainfrom
tags

Conversation

@shsteimer

Copy link
Copy Markdown
Collaborator

shsteimer and others added 21 commits August 12, 2026 08:08
Ports the multi-select taxonomy tag picker from aemeds-toyota-racing's
tools/plugins/tags. The org/repo already come from the DA SDK context so
the plugin works across sites unmodified; adds a `taxonomy` URL query
param so sites can point it at a taxonomy.json anywhere in their own DA
source, or a full DA source URL to share one taxonomy sheet across
multiple orgs/repos.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a standalone app (tools/apps/tags) for visually managing a site's
tag taxonomy - full CRUD and drag-reorder over namespaces/categories/tags,
save/publish via DA source + AEM admin, and a lazy, on-demand crawl to
find pages carrying a given tag.

Extracts taxonomy location resolving, sheet fetching, and row<->tree
parsing into tools/apps/tags/taxonomy.js, which the tags plugin now
imports directly instead of duplicating, so both share one canonical
implementation of the taxonomy.json contract.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…odel

Replaces the nested-card/accordion tree editor with a Miller-columns UI
(namespace -> category -> ... -> tag, one column per depth, drag between
columns to move branches). Removes the separate Find-pages tab in favor
of a per-node "Find pages" action that opens a modal scoped to that
node's path, and replaces native confirm() dialogs with a modal that
requires typing the item's name before deleting it.

Unifies namespaces, categories, and tags into one node shape
(`{ name, description, children }`) - they only ever differed by depth
and whether they currently have children, so there's now a single
add/rename/edit/delete/drag path for all three instead of three parallel
ones. Namespace/category rows can now carry a Description too, which
taxonomy.json's format already had room for but nothing used.

Adds test/tools/apps/tags/taxonomy.test.js covering the parse/serialize/
flatten round-trip, following this repo's existing test/ layout.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…eaders

A Tag row after a Category header used to attach to that category until
the next header row, so a direct tag placed after a categorized one in
the same namespace silently landed in the wrong place. Category is now
read directly off each Tag row (full /-joined path, omitted for a tag
directly under the namespace), so direct and categorized tags can be
mixed in any order. Namespace stays the one inherited/stateful column.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Per-column action buttons are replaced with one toolbar (separate from
Save/Publish) that acts on the deepest selected node. No selection means
the implicit target is the namespace level, so Add stays enabled (it
creates a namespace); Delete and Find pages need an actual node and are
disabled until one is selected.

Also: only show the drill-down chevron on items that actually have
children (dropped the bold-text has-children styling), drop the "Empty"
placeholder in empty columns, and give column headers more padding.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Style column headers distinctly (uppercase "Namespaces" section label
  vs. a bold owner title+description block with its own background),
  fixing the previous plain, hard-to-scan header.
- Move the Add/Delete/Find pages toolbar into a Spectrum action-bar-style
  bar attached directly to the miller columns (shared border/radius),
  showing the selection path as context with a control to clear it.
- Replace always-editable name/description inputs with a pencil icon
  that toggles edit mode, so browsing the tree isn't full of live inputs.
- Track which nodes changed since the last save and mark them with a
  small dot (in both the item list and the column header), so the
  "Unsaved changes" message is backed by a visible diff.
- Show a drop-target indicator while dragging: an insertion line when
  reordering within the same list, a highlighted outline when moving
  into a different node's children.
- Move the save/publish result message inline with the Save/Publish
  buttons instead of above them, so it appearing doesn't shift the
  columns below.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
It sat flush against the bar's edge and didn't add information the
column header (also labeled "Namespaces") doesn't already show. The
context label now only renders once there's an actual selection to
describe.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Neither exists in nx2's styles.css (spacing jumps 100 -> 200, gray jumps
100 -> 200) — --s2-spacing-150 had no fallback so those padding/gap
declarations were silently dropped entirely; --s2-gray-150 had a
fallback so it degraded safely, but the reference itself was dead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Headers sized to their own content, so the "Namespaces" header (no
description slot) was shorter than a drilled-into node's header, and a
node without a description looked visually "incomplete" next to one
that had one. Removed the title's extra padding (it wasn't matched on
the owner-name title-row) and gave the header a min-height sized for
title+description, so the gray background fills in uniformly across
every column regardless of whether that node has a description.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The pencil previously lived in the column header, so editing a node
meant drilling into it first to reveal the next column's header. It now
lives inline on the row itself (in the column where that node is
listed) — clicking it expands just that row into a two-field editor
(name + description, with a checkmark to collapse it back), no modal
needed. The column header is now purely a read-only "where am I"
display of the node whose children that column lists.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Editing a row's name/description previously wrote straight to the node
on blur, so switching to edit a different row (without confirming)
silently committed and dirtied whatever was mid-edit. Edits are now
held in a draft and only applied on commit (the checkmark, or Enter);
starting a different edit, clicking the new Cancel button, pressing
Escape, or clicking a row to drill into it all discard the draft
instead of keeping the half-typed change.

Adding an item now drops straight into that draft-edit mode with the
name selected, instead of leaving a "New Item" placeholder to hunt
down and rename separately; Cancel on a still-unconfirmed new item
removes it entirely rather than leaving an empty node behind.

Also reworked the column headers into their own shared flex row (with
the items in a second row below, both inside one scroll container so
they still scroll together) so header heights come from natural
flexbox stretch instead of a fixed min-height guess — every header
automatically matches its tallest sibling, and a header with no
description doesn't reserve dead space for one it doesn't have.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Saved taxonomy.json was missing the `:type: "sheet"` marker AEM's
single-sheet JSON format requires, so publish failed with "invalid
sheet; unknown type". Added it along with `columns`, matching the
format documented at aem.live/developer/spreadsheets.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rows only carried the keys relevant to that row (a Tag row had no
Namespace/Category key at all), but a real spreadsheet-backed sheet is
rectangular — every row has a cell for every column. AEM/DA's column
detection doesn't reliably pick up a column that's simply absent from a
row's keys, even when it's declared in the sheet's `columns` list, so
Category and Tag were silently dropped as columns on publish. Every
row now carries all four columns, using an empty string for whichever
don't apply — parseTaxonomyTree already treats an empty string the
same as a missing key, so reading is unaffected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The chevron was only rendered for rows with children, so the pencil
before it shifted right on childless rows (nothing left to push it off
the edge). The chevron now always renders, just hidden via visibility
(not display) so it still reserves its layout space.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Widened it (420px -> 680px, matching the other modals' pattern via a
new .modal-lg modifier) and gave the results list more vertical room
(260px -> 420px) now that there's space for it. Also reworded "Subfolder
(optional)" to "Subfolder (recommended for large sites)" so it explains
why you'd want to narrow the crawl, not just that you can.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Placeholder now shows a multi-level example (/news/2026) instead of a
single-segment one (/blog), since the field isn't limited to one level.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
.miller-column-header used box-sizing: border-box (its divider border
absorbed into the declared 240px), but .miller-column didn't, so its
border-left added on top of the 240px instead — every column past the
first was 1px wider than its header. Grid/subgrid isn't needed here;
the two rows were already meant to share the same fixed 240px column
widths, just inconsistently boxed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
flattenTaxonomyTags now flattens every node (not just leaves), so a
category like `Tag Driven:catlev1` is selectable in the tags plugin
picker alongside anything nested under it. serializeTaxonomyTree
correspondingly always emits a category's own row (not only when it
carries a description), so it has something to be selected from.

Also unifies the direct-tag path separator to `Namespace:Tag` (was
`Namespace/Tag`), matching the `Namespace:Category/Tag` convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…t shape

A category is just a tag that has children — serializeTaxonomyTree now
gives every node one row (its own name in Tag, ancestors' path in
Category), then recurses into children if any, instead of emitting a
separate Category-only declaration row. Simpler and matches how you'd
naturally hand-edit the sheet. parseTaxonomyTree still accepts the old
Category-only row shape for backward compatibility.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@shsteimer
shsteimer requested a review from usman-khalid August 27, 2026 03:38
@aem-code-sync

aem-code-sync Bot commented Aug 27, 2026

Copy link
Copy Markdown

Hello, I'm the AEM Code Sync Bot and I will run some actions to deploy your branch and validate page speed.
In case there are problems, just click a checkbox below to rerun the respective action.

  • Re-run all PSI checks
  • Re-run failed PSI checks
  • Re-sync branch
Commits

@aem-code-sync

aem-code-sync Bot commented Aug 27, 2026

Copy link
Copy Markdown
Page Scores Audits Google
📱 / PERFORMANCE A11Y SEO BEST PRACTICES SI FCP LCP TBT CLS PSI
🖥️ / PERFORMANCE A11Y SEO BEST PRACTICES SI FCP LCP TBT CLS PSI

@usman-khalid

Copy link
Copy Markdown
Collaborator

Testing on https://da.live/app/adobe-rnd/aem-apps/tools/apps/tags/tags?ref=tags for scdemos/demo and aemsites/intuit-erp - both have a taxonomy at docs/library/tagging.json which it can't seem to load? Don't see any errors in console either.

2026-08-27 10 08 48

Comment thread tools/apps/tags/tags.js Outdated
<div class="miller-item-edit-row">
<input class="tax-name-input" .value=${draft.name} @keydown=${(e) => this.handleEditKeydown(e)}
@input=${(e) => this.updateDraft('name', e.target.value)} />
<button class="icon-btn" aria-label="Save changes" @click=${() => this.commitEditing()}>✓</button>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use spectrum icons here?

Comment thread tools/apps/tags/tags.js Outdated
return html`
<div class="miller-item is-editing">
<div class="miller-item-edit-row">
<input class="tax-name-input" .value=${draft.name} @keydown=${(e) => this.handleEditKeydown(e)}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use sl-input from nx2 for this and the description inputs? Other apps use that for the UI.

- use spectrum icons instead of text glyphs for inline edit/save/cancel buttons
- use sl-input for name/description edit fields, matching rest of the app
- surface a friendly error when a taxonomy sheet doesn't match the expected schema, instead of silently loading an empty tree

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
On schema mismatch, if the sheet looks like a flat key/value/Comments
tag list, offer a modal to convert it into a namespace tree. Purely
opt-in: only populates the in-memory tree after explicit confirmation,
and writes nothing until the user separately clicks Save to a new
path — the original file is never touched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Correct the convert-legacy-tags modal copy (converting only builds an
in-memory tree; only Save can ever write, and only to the separate
path shown, never the original). Also check whether that path is
already occupied before allowing the conversion to proceed, requiring
an explicit second click ("Convert anyway") so a later Save can't
silently clobber something already there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@shsteimer

Copy link
Copy Markdown
Collaborator Author

@usman-khalid all are adddressed. this uses a different format than that file. I updated it to detect and warn...

Screen.Recording.2026-08-28.at.4.48.41.PM.mov

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants