@dloizides/ui-access-admin 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/LICENSE +21 -0
- package/README.md +136 -0
- package/dist/index.d.mts +544 -0
- package/dist/index.d.ts +544 -0
- package/dist/index.js +576 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +558 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +121 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@dloizides/ui-access-admin` are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the
|
|
6
|
+
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2026-07-22
|
|
9
|
+
|
|
10
|
+
Initial release. Promoted out of `kefi-web`'s organizer promoter roster, which had the
|
|
11
|
+
only working implementation of scoped capability links in the fleet — and had it welded
|
|
12
|
+
to a `PromoterDto`.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **`AccessLinkPanel`** — mint / copy / share / revoke a scoped capability link for one
|
|
17
|
+
subject. Scoped to a single subject on purpose: these links are bearer tokens, so a
|
|
18
|
+
screen listing every subject's live link would itself be a high-value secret.
|
|
19
|
+
- **`AccountLinkPanel`** — bind a subject to its sign-in account, or unbind it. Unlinking
|
|
20
|
+
is a separate press from the picker so a mis-tap cannot detach someone from their work.
|
|
21
|
+
- **`useCapabilityLinkMint`** / **`useSubjectAccountLink`** — the headless halves, for
|
|
22
|
+
hosts that want their own chrome.
|
|
23
|
+
- **Expiry policy** (`capabilityExpiryDays`, `capabilityExpiryDate`, `daysUntilAnchor`) —
|
|
24
|
+
`anchorDate + tailDays`, clamped to the host API's accepted range. No code path returns
|
|
25
|
+
"never".
|
|
26
|
+
- **`ACCESS_ADMIN_I18N`** — the machine-readable i18n manifest hosts bind a missing-key
|
|
27
|
+
guard to, following the `LAYOUT_I18N` / `TABLE_I18N` precedent. `accessAdminI18n.test.ts`
|
|
28
|
+
fails the build if a component resolves a raw key literal, or if the map carries an
|
|
29
|
+
unused entry.
|
|
30
|
+
- **`ACCESS_ADMIN_TEST_IDS`** plus a `testIDPrefix` on both panels, so an adopting app
|
|
31
|
+
keeps its existing Playwright selectors.
|
|
32
|
+
- **`useAccessAdminPalette`** — maps the host's `UiProvider` theme onto the colour roles
|
|
33
|
+
the panels need. No colour literals in the package.
|
|
34
|
+
|
|
35
|
+
### Notes on the extraction
|
|
36
|
+
|
|
37
|
+
- **No host domain types cross the boundary.** `AccessSubject` is `{ id, displayName }`.
|
|
38
|
+
Resolving WHICH subject an API's link row belongs to is the host's job, done once when
|
|
39
|
+
it normalizes its DTOs — which keeps a product's data-model compromise (kefi matches on
|
|
40
|
+
recipient name, because its wire format omits the binding) out of the shared filter.
|
|
41
|
+
- **No API calls, no react-query.** Mint, link and unlink are injected async callbacks.
|
|
42
|
+
- **A failed link-list load is never conflated with an empty one.** `linksFailed` exists
|
|
43
|
+
because "we could not load this" rendered as "this person has no live link" invites
|
|
44
|
+
minting a second live capability and hides that there is something to revoke.
|
|
45
|
+
- **A refused clipboard write after a successful mint is reported as an ERROR**, not a
|
|
46
|
+
warning: the URL is readable exactly once, so a green toast over an empty clipboard
|
|
47
|
+
costs a revoke-and-re-mint.
|
|
48
|
+
- `CheckboxField` was considered for extraction and deliberately **not** taken — the kit
|
|
49
|
+
already ships `FormCheckbox` in `@dloizides/ui-forms`, carrying both the `aria-checked`
|
|
50
|
+
fix and a keyboard-activation fix. Adding a third copy here would have been the bug this
|
|
51
|
+
package exists to avoid.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 dloizides
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# @dloizides/ui-access-admin
|
|
2
|
+
|
|
3
|
+
Brand-agnostic React Native (RN-web) **user & access administration UI** for the
|
|
4
|
+
dloizides.com shared kit.
|
|
5
|
+
|
|
6
|
+
The frontend counterpart to what `Identity.Abstractions` already shares on the backend
|
|
7
|
+
(`IUserManagementService`, `TenantManagedRoleSet`). It ships the two screens every
|
|
8
|
+
product ends up rebuilding:
|
|
9
|
+
|
|
10
|
+
- **`AccessLinkPanel`** — mint, copy, share and revoke a **scoped capability link** for
|
|
11
|
+
one subject, always with an expiry.
|
|
12
|
+
- **`AccountLinkPanel`** — bind a subject to the account it signs in with, or unbind it.
|
|
13
|
+
|
|
14
|
+
Promoted out of `kefi-web`, with every Kefi noun removed.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## The two rules that make it reusable
|
|
19
|
+
|
|
20
|
+
**1. No host domain types in the public API.** The package knows about a `AccessSubject`
|
|
21
|
+
(`{ id, displayName }`), a `CapabilityLink`, and a `LinkableAccount`. Nothing else. A
|
|
22
|
+
survey respondent, a menu editor and a party promoter are all subjects.
|
|
23
|
+
|
|
24
|
+
**2. No API calls.** Every write is an injected `async` callback. There is no
|
|
25
|
+
`react-query` dependency and no client. You wire your own endpoints and your own cache
|
|
26
|
+
invalidation.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install @dloizides/ui-access-admin
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Peers: `@dloizides/ui-feedback`, `@dloizides/ui-buttons`, `@dloizides/ui-forms`,
|
|
37
|
+
`@dloizides/ui-layout`, `react`, `react-native`.
|
|
38
|
+
|
|
39
|
+
Mount a `UiProvider` (from `@dloizides/ui-feedback`) above these panels — it supplies both
|
|
40
|
+
the theme and `t`.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Quick start
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { AccessLinkPanel, type CapabilityLink } from '@dloizides/ui-access-admin';
|
|
48
|
+
|
|
49
|
+
<AccessLinkPanel
|
|
50
|
+
subject={{ id: promoter.externalId, displayName: promoter.name }}
|
|
51
|
+
policy={{ anchorDate: eventDate, tailDays: 14, minDays: 1, maxDays: 365 }}
|
|
52
|
+
links={links} // normalized to CapabilityLink by YOUR adapter
|
|
53
|
+
linksFailed={linksQuery.isError} // never conflated with "there are none"
|
|
54
|
+
mint={async ({ subject, expiresInDays }) => toCapabilityLink(
|
|
55
|
+
await createLink.mutateAsync(buildRequest(subject, expiresInDays)),
|
|
56
|
+
)}
|
|
57
|
+
describeError={(error) => FM(mutationErrorKey(error))}
|
|
58
|
+
renderLinkActions={(link) => <MyRevokeButton linkId={link.id} />}
|
|
59
|
+
onClose={close}
|
|
60
|
+
onResult={(message, tone) => setBanner({ message, tone })}
|
|
61
|
+
/>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### The expiry policy
|
|
65
|
+
|
|
66
|
+
`capabilityExpiryDays` resolves `anchorDate + tailDays`, clamped into `[minDays, maxDays]`.
|
|
67
|
+
|
|
68
|
+
**There is no code path that returns "never."** A missing, unparseable or past anchor
|
|
69
|
+
yields the bare tail, not an unbounded link. These URLs are bearer tokens pasted into chat
|
|
70
|
+
apps; the expiry is the only thing limiting the blast radius of a forward.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## i18n — read this before adopting
|
|
75
|
+
|
|
76
|
+
The package is **fallback-free**. `t` is your resolver, and a missing key renders the raw
|
|
77
|
+
dotted name to the user.
|
|
78
|
+
|
|
79
|
+
`ACCESS_ADMIN_I18N` is a machine-readable manifest of every key the package resolves.
|
|
80
|
+
**Bind your missing-key guard to it**, the way `kefi-web/src/localization/kitTranslationKeys.ts`
|
|
81
|
+
already binds `LAYOUT_I18N` and `TABLE_I18N`:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { ACCESS_ADMIN_I18N } from '@dloizides/ui-access-admin';
|
|
85
|
+
|
|
86
|
+
const ACCESS_ADMIN_KEYS: readonly string[] = Object.values(ACCESS_ADMIN_I18N);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Then an upgrade that adds a string **fails your test suite** instead of shipping raw key
|
|
90
|
+
text. `accessAdminI18n.test.ts` keeps the manifest itself honest: it fails if any component
|
|
91
|
+
resolves a raw literal, and if the map carries an entry nothing uses.
|
|
92
|
+
|
|
93
|
+
The package owns the key **names**; you own the **wording**. That split is what lets one
|
|
94
|
+
product keep warm, specific copy under a key another product reuses with its own.
|
|
95
|
+
|
|
96
|
+
Every key is namespaced under `accessAdmin.*`, so it drops into a locale file as one block.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## testIDs
|
|
101
|
+
|
|
102
|
+
Both panels take a `testIDPrefix`; every child derives from it. Adopting apps already have
|
|
103
|
+
Playwright selectors, and a shared component is not a good enough reason to rewrite an E2E
|
|
104
|
+
suite.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Theming
|
|
109
|
+
|
|
110
|
+
Colours come from your `UiProvider` theme (`@dloizides/design-tokens`). The package defines
|
|
111
|
+
**no colour literals** — `useAccessAdminPalette` maps the theme onto the roles the panels
|
|
112
|
+
need, so a rebrand reaches them for free.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## API
|
|
117
|
+
|
|
118
|
+
| Export | What it is |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `AccessLinkPanel` | The capability-link panel for one subject |
|
|
121
|
+
| `AccountLinkPanel` | The account picker for one subject |
|
|
122
|
+
| `useCapabilityLinkMint` | Mint-and-copy state (headless) |
|
|
123
|
+
| `useSubjectAccountLink` | Selection + submit state for account linking (headless) |
|
|
124
|
+
| `capabilityExpiryDays` / `capabilityExpiryDate` / `daysUntilAnchor` | The expiry policy |
|
|
125
|
+
| `linksForSubject` / `activeLinksForSubject` / `formatLinkDate` | Pure link helpers |
|
|
126
|
+
| `buildCapabilityLinkMailto` | `mailto:` compose URL (no recipient — see the source) |
|
|
127
|
+
| `buildAccountOptions` / `accountDisplayLabel` | Pure picker helpers |
|
|
128
|
+
| `useAccessAdminPalette` | Theme → colour roles |
|
|
129
|
+
| `ACCESS_ADMIN_I18N` / `ACCESS_ADMIN_TEST_IDS` | The host contracts |
|
|
130
|
+
| `AccessResultTone` | `Success` \| `Error` |
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT
|