Skip to content

Feature/contacts pane redesign - #301

Merged
timea-solid merged 26 commits into
SolidOS:stagingfrom
m5x5:feature/contactsPaneRedesign
Oct 20, 2026
Merged

timea-solid merged 26 commits into
SolidOS:stagingfrom
m5x5:feature/contactsPaneRedesign

Conversation

@m5x5

@m5x5 m5x5 commented Jul 28, 2026 •

Copy link
Copy Markdown

@timea-solid

Copy link
Copy Markdown
Member

So far so good.
One remark: we decided local web components to be prefixed with the pane name - so contacts-pane-... here

@timea-solid timea-solid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

While any is a good start, we should improve it to be more specific at some point.
Good work!

type Visibility = 'public' | 'private' | null

/** Globe and lock marks for the visibility badge, sized to its text. */
const globeIcon = html`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

don't we have this icons on lucide?


/** The empty state's circled address-book icon; the wording next to it is
* plain HTML in renderEmpty. */
const emptyIllustration = html`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Pls try and use lucide icons directly as we have in solid-ui or profile-pnae

m5x5 and others added 2 commits September 2, 2026 22:22
Take staging's dependency versions, drop the legacy contactsPane.js the
redesign already replaced, and carry its add-contact dialog test over to
the Lit components.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017U9rvGpQqMM76GgeRkgjUJ
- Import lucide icons via ~icons/lucide/* in each component instead of the
  removed solid-ui/components/icons barrel, and replace the hand-drawn SVGs
  (visibility badge globe/lock, empty-state address book, fallback avatar)
  with lucide equivalents.
- Bundle ~icons imports in the build rather than leaving them external.
- Replace loose any types in the presenter, logic modules and components.
- Give the groups section its own accessible name (the heading it referred
  to lives inside the header's shadow root).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017U9rvGpQqMM76GgeRkgjUJ
@SharonStrats

Copy link
Copy Markdown
Contributor

it looks really nice! Great work!

just a couple suggestions. I realized recently you can use the solid-ui-combobox for the select and it will give the same selection style as we are using in profile-pane.

also, it would be good if the count on the groups updated when you add a contact.

Amazing!

@timea-solid timea-solid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Code looks ok to me.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Maintenance actions can mutate or report success incorrectly, and search advertises unsupported fields.

Review effort: Balanced
Findings: 1 High severity · 5 Medium severity

Open (6)
What changed in this PR

Redesigns the contacts pane for issue #295 using Lit components and Solid UI controls while migrating legacy JavaScript to TypeScript.

Changes:

  • Introduces componentized address-book, group, people, search, details, tools, and dialog interfaces.
  • Extracts maintenance logic and modernizes contact/group operations.
  • Updates styling, icons, TypeScript strictness, build configuration, and tests.
File Description
vite.config.mts Bundles generated icon modules.
tsconfig.test.json Includes ambient test declarations.
tsconfig.json Enables implicit-any checking.
test/​unit/​setup.ts Tightens mock types.
test/​unit/​pane.accessibility.test.ts Adapts pane accessibility tests.
test/​unit/​modals.accessibility.test.ts Tests new dialogs with axe.
test/​unit/​localUtils-modal.test.ts Tests dialogs and deletion controls.
test/​unit/​data-reformat-test.test.ts Adapts search interaction tests.
test/​helpers/​setup.ts Polyfills form-associated internals.
src/​webidControl.ts Adds TypeScript annotations.
src/​toolsLogic.ts Adds maintenance-tool logic.
src/​styles/​toolsPane.css Removes legacy tool styles.
src/​styles/​localUtils.css Removes legacy modal styles.
src/​styles/​individual.css Updates contact-card presentation.
src/​styles/​contactsPane.css Implements redesigned responsive layout.
src/​rdfFormsHelper.ts Types RDF form helpers.
src/​mugshotGallery.ts Types gallery and upload behavior.
src/​mintNewAddressBook.ts Refactors typed minting flow.
src/​localUtils.ts Migrates utilities and dialog integration.
src/​localUtils.js Removes legacy utility implementation.
src/​individual.ts Types individual rendering.
src/​groupMembershipControl.ts Integrates the new delete control.
src/​debug.ts Adds typed logging utilities.
src/​debug.js Removes JavaScript logging utilities.
src/​contactsPane.ts Introduces the component-based pane entry.
src/​contactLogic.ts Types contact and group operations.
src/​components/​tools/​Tools.ts Adds the maintenance-tools component.
src/​components/​tools/​Tools.styles.css Styles the tools component.
src/​components/​tools/​index.ts Exports the tools component.
src/​components/​sharing-modal/​SharingModal.ts Adds the sharing dialog.
src/​components/​sharing-modal/​SharingModal.styles.css Styles sharing content.
src/​components/​sharing-modal/​index.ts Exports the sharing dialog.
src/​components/​search/​Search.ts Adds the contact-search component.
src/​components/​search/​Search.styles.css Styles contact search.
src/​components/​search/​index.ts Exports contact search.
src/​components/​people-list/​PeopleList.ts Adds the interactive people list.
src/​components/​people-list/​PeopleList.styles.css Styles people rows and menus.
src/​components/​people-list/​index.ts Exports the people list.
src/​components/​new-group-modal/​NewGroupModal.ts Adds group-creation dialog.
src/​components/​new-group-modal/​NewGroupModal.styles.css Styles group creation.
src/​components/​new-group-modal/​index.ts Exports group creation.
src/​components/​group-bar/​index.ts Exports the group bar.
src/​components/​group-bar/​GroupBar.ts Adds group filtering and selection.
src/​components/​group-bar/​GroupBar.styles.css Styles the group column.
src/​components/​details-section/​index.ts Exports contact details.
src/​components/​details-section/​DetailsSection.ts Manages details-pane states.
src/​components/​delete-button/​index.ts Exports deletion controls.
src/​components/​delete-button/​DeleteButton.ts Adds reusable confirmed deletion.
src/​components/​delete-button/​DeleteButton.styles.css Styles the delete control.
src/​components/​confirm-modal/​index.ts Exports confirmation dialogs.
src/​components/​confirm-modal/​ConfirmModal.ts Adds the confirmation dialog.
src/​components/​confirm-modal/​ConfirmModal.styles.css Styles confirmation dialogs.
src/​components/​alert-modal/​index.ts Exports alert dialogs.
src/​components/​alert-modal/​AlertModal.ts Adds the alert dialog.
src/​components/​alert-modal/​AlertModal.styles.css Styles alert dialogs.
src/​components/​address-book/​index.ts Exports the address-book component.
src/​components/​address-book/​AddressBook.ts Coordinates the redesigned view.
src/​components/​address-book-header/​index.ts Exports the address-book header.
src/​components/​address-book-header/​AddressBookHeader.ts Adds header actions and visibility.
src/​components/​address-book-header/​AddressBookHeader.styles.css Styles the redesigned header.
src/​components/​add-contact-modal/​AddContactModal.ts Types and renames contact creation.
src/​addressBookPresenter.ts Migrates presenter behavior to TypeScript.
src/​addressBookPresenter.js Removes the JavaScript presenter.
package.json Adds icon tooling dependencies.
package-lock.json Locks icon tooling dependencies.
eslint.config.mjs Enforces modern TypeScript syntax.
declarations.d.ts Declares generated icon modules.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/toolsLogic.ts
Comment on lines +88 to +91
} catch (e) {
debug.error('Error loading groups. Stack: ' + e)
log('Error loading groups or name index. If it persists, contact your admin.')
}
<h2 id="addressBook-heading" tabindex="-1">${this.selectedGroupName ?? 'All Contacts'}</h2>
${this.renderVisibilityBadge()}
</div>
<p>Search contacts by name, email, WebID, or profile URL</p>
Comment thread src/toolsLogic.ts Outdated
log('' + totalContacts + ' contacts loaded. ')
const groups = dedupedGroups(book)
log('' + groups.length + ' total groups. ')
log('' + Object.keys(selectedGroups).length + ' selected groups. ')
Comment thread src/toolsLogic.ts Outdated
Comment on lines +50 to +52
export function checkAccess (selectedGroups: Record<string, boolean>, log: Log) {
function doCard (card: NamedNode) {
UI.acl.fixIndividualCardACL(card, (message: string) => log(message), (ok: boolean, message: any) => {
Comment thread src/toolsLogic.ts Outdated
Comment on lines +129 to +138
let groupOfUngrouped: any = null
try {
groupOfUngrouped = await saveNewGroup(book, 'No group')
} catch (_e) {
// The group may exist already; adding below still works then.
}

if (!(await confirm(`Add the ${groupless.length} contacts without groups to a 'No group' group?`))) {
return false
}
Comment thread src/toolsLogic.ts
Comment on lines +345 to +347
} catch (e) {
log('Error saving uniques: ' + e)
}
@timea-solid

Copy link
Copy Markdown
Member

@m5x5 do you have time to address the copilot findings?

timea-solid and others added 3 commits October 19, 2026 21:48
kb.any/kb.each return Node | null, but fetcher.load only takes named
nodes, so the "as NamedNode" casts hid a missing or literal index.

- Add an isNamedNode guard that wraps rdflib's and narrows to rdflib's
  NamedNode class, so it can be swapped for rdflib's once that narrows
  to the class itself.
- Add bookIndex(), which takes the first named node for the name or
  group index and throws when there is none, instead of loading null.
- Filter group and card lists with isNamedNode instead of casting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Addresses the Copilot review on toolsLogic.ts.

- findGroupless: rethrow when the index or a group fails to load. A
  partial store reported grouped contacts as groupless, and
  "Put all individuals with no group..." then moved them.
- checkAccess: return a promise that settles once every card's ACL
  repair has finished, and fail when any of them failed, so the Tools
  button stops loading only at the end. solid-ui's fixIndividualACL
  never calls back when the ACL is already right, so its
  "Nice - same ACL" log line also counts as done.
- fixGroupless: ask before creating the "No group" group, so Cancel
  leaves the book untouched, and let creation errors propagate.
- saveCleanPeople / saveCleanGroup: rethrow after logging, so a failed
  PUT is no longer reported as "Done!".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
m5x5 and others added 8 commits October 19, 2026 23:44
GroupBar keeps a deselected group as a false entry in selectedGroups,
so Statistics over-reported the selection and "Check individual
contact access" also walked deselected groups. Addresses the Copilot
review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The header promised these fields, but the filter only matched names
(Copilot review).

- Match every word of the query against the name, all email addresses,
  every vcard:url and any owl:sameAs of the contact.
- Update the search placeholder to say the same as the header.

Emails and URLs come from each card, which loads in the background, so
right after opening a book a contact may only be found by name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The new member changes the counts in the group bar, which other
handlers already refresh. Suggested in review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Matches the type pickers in profile-pane's edit dialogs, as suggested
in review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Show the tools in a contacts-pane-tools-modal dialog instead of the
details section, with the log below the buttons. The dialog's width is
fixed and its content scrolls, so a growing log does not resize it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@timea-solid
timea-solid marked this pull request as ready for review October 20, 2026 14:30
@timea-solid
timea-solid merged commit be4a965 into SolidOS:staging Oct 20, 2026
8 checks passed
@github-project-automation github-project-automation Bot moved this from In progress to Done in SolidOS NLNet UI Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants