@happyvertical/smrt-users 0.30.0
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/AGENTS.md +85 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/README.md +459 -0
- package/dist/__smrt-register__.d.ts +2 -0
- package/dist/__smrt-register__.d.ts.map +1 -0
- package/dist/chunks/TerminalAuthService-DoAMQ_yn.js +5118 -0
- package/dist/chunks/TerminalAuthService-DoAMQ_yn.js.map +1 -0
- package/dist/chunks/index-DkoYIvIu.js +169 -0
- package/dist/chunks/index-DkoYIvIu.js.map +1 -0
- package/dist/collections/CliAuthRequestCollection.d.ts +19 -0
- package/dist/collections/CliAuthRequestCollection.d.ts.map +1 -0
- package/dist/collections/GroupCollection.d.ts +17 -0
- package/dist/collections/GroupCollection.d.ts.map +1 -0
- package/dist/collections/GroupMemberCollection.d.ts +43 -0
- package/dist/collections/GroupMemberCollection.d.ts.map +1 -0
- package/dist/collections/GroupRoleCollection.d.ts +33 -0
- package/dist/collections/GroupRoleCollection.d.ts.map +1 -0
- package/dist/collections/MagicLinkTokenCollection.d.ts +26 -0
- package/dist/collections/MagicLinkTokenCollection.d.ts.map +1 -0
- package/dist/collections/MembershipCollection.d.ts +38 -0
- package/dist/collections/MembershipCollection.d.ts.map +1 -0
- package/dist/collections/MembershipOverrideCollection.d.ts +55 -0
- package/dist/collections/MembershipOverrideCollection.d.ts.map +1 -0
- package/dist/collections/PermissionCollection.d.ts +34 -0
- package/dist/collections/PermissionCollection.d.ts.map +1 -0
- package/dist/collections/RoleCollection.d.ts +29 -0
- package/dist/collections/RoleCollection.d.ts.map +1 -0
- package/dist/collections/RolePermissionCollection.d.ts +33 -0
- package/dist/collections/RolePermissionCollection.d.ts.map +1 -0
- package/dist/collections/SessionCollection.d.ts +82 -0
- package/dist/collections/SessionCollection.d.ts.map +1 -0
- package/dist/collections/TenantCollection.d.ts +119 -0
- package/dist/collections/TenantCollection.d.ts.map +1 -0
- package/dist/collections/TenantPermissionOverrideCollection.d.ts +111 -0
- package/dist/collections/TenantPermissionOverrideCollection.d.ts.map +1 -0
- package/dist/collections/UserCollection.d.ts +116 -0
- package/dist/collections/UserCollection.d.ts.map +1 -0
- package/dist/collections/index.d.ts +19 -0
- package/dist/collections/index.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1482 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.json +5216 -0
- package/dist/models/CliAuthRequest.d.ts +25 -0
- package/dist/models/CliAuthRequest.d.ts.map +1 -0
- package/dist/models/Group.d.ts +34 -0
- package/dist/models/Group.d.ts.map +1 -0
- package/dist/models/GroupMember.d.ts +29 -0
- package/dist/models/GroupMember.d.ts.map +1 -0
- package/dist/models/GroupRole.d.ts +29 -0
- package/dist/models/GroupRole.d.ts.map +1 -0
- package/dist/models/MagicLinkToken.d.ts +22 -0
- package/dist/models/MagicLinkToken.d.ts.map +1 -0
- package/dist/models/Membership.d.ts +48 -0
- package/dist/models/Membership.d.ts.map +1 -0
- package/dist/models/MembershipOverride.d.ts +50 -0
- package/dist/models/MembershipOverride.d.ts.map +1 -0
- package/dist/models/Permission.d.ts +79 -0
- package/dist/models/Permission.d.ts.map +1 -0
- package/dist/models/Role.d.ts +67 -0
- package/dist/models/Role.d.ts.map +1 -0
- package/dist/models/RolePermission.d.ts +29 -0
- package/dist/models/RolePermission.d.ts.map +1 -0
- package/dist/models/Session.d.ts +105 -0
- package/dist/models/Session.d.ts.map +1 -0
- package/dist/models/Tenant.d.ts +138 -0
- package/dist/models/Tenant.d.ts.map +1 -0
- package/dist/models/TenantPermissionOverride.d.ts +74 -0
- package/dist/models/TenantPermissionOverride.d.ts.map +1 -0
- package/dist/models/User.d.ts +72 -0
- package/dist/models/User.d.ts.map +1 -0
- package/dist/models/index.d.ts +19 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/playground.d.ts +2 -0
- package/dist/playground.d.ts.map +1 -0
- package/dist/playground.js +139 -0
- package/dist/playground.js.map +1 -0
- package/dist/services/MagicLinkService.d.ts +84 -0
- package/dist/services/MagicLinkService.d.ts.map +1 -0
- package/dist/services/OidcLoginService.d.ts +134 -0
- package/dist/services/OidcLoginService.d.ts.map +1 -0
- package/dist/services/PermissionCatalogService.d.ts +62 -0
- package/dist/services/PermissionCatalogService.d.ts.map +1 -0
- package/dist/services/PermissionResolver.d.ts +150 -0
- package/dist/services/PermissionResolver.d.ts.map +1 -0
- package/dist/services/PostgresPermissionPolicies.d.ts +29 -0
- package/dist/services/PostgresPermissionPolicies.d.ts.map +1 -0
- package/dist/services/SessionPermissionContext.d.ts +43 -0
- package/dist/services/SessionPermissionContext.d.ts.map +1 -0
- package/dist/services/SessionService.d.ts +139 -0
- package/dist/services/SessionService.d.ts.map +1 -0
- package/dist/services/TenantService.d.ts +135 -0
- package/dist/services/TenantService.d.ts.map +1 -0
- package/dist/services/TerminalAuthService.d.ts +189 -0
- package/dist/services/TerminalAuthService.d.ts.map +1 -0
- package/dist/services/index.d.ts +14 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +2744 -0
- package/dist/svelte/components/InviteUserModal.svelte +351 -0
- package/dist/svelte/components/InviteUserModal.svelte.d.ts +17 -0
- package/dist/svelte/components/InviteUserModal.svelte.d.ts.map +1 -0
- package/dist/svelte/components/UserAvatar.svelte +105 -0
- package/dist/svelte/components/UserAvatar.svelte.d.ts +10 -0
- package/dist/svelte/components/UserAvatar.svelte.d.ts.map +1 -0
- package/dist/svelte/components/UserCard.svelte +179 -0
- package/dist/svelte/components/UserCard.svelte.d.ts +18 -0
- package/dist/svelte/components/UserCard.svelte.d.ts.map +1 -0
- package/dist/svelte/components/UserForm.svelte +194 -0
- package/dist/svelte/components/UserForm.svelte.d.ts +18 -0
- package/dist/svelte/components/UserForm.svelte.d.ts.map +1 -0
- package/dist/svelte/components/UserList.svelte +107 -0
- package/dist/svelte/components/UserList.svelte.d.ts +20 -0
- package/dist/svelte/components/UserList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/UserMenu.svelte +326 -0
- package/dist/svelte/components/UserMenu.svelte.d.ts +33 -0
- package/dist/svelte/components/UserMenu.svelte.d.ts.map +1 -0
- package/dist/svelte/components/__tests__/InviteUserModal.test.js +54 -0
- package/dist/svelte/components/__tests__/UserAvatar.test.js +31 -0
- package/dist/svelte/components/__tests__/UserCard.test.js +39 -0
- package/dist/svelte/components/__tests__/UserForm.test.js +50 -0
- package/dist/svelte/components/__tests__/UserList.test.js +48 -0
- package/dist/svelte/components/__tests__/UserMenu.test.js +38 -0
- package/dist/svelte/i18n.d.ts +15 -0
- package/dist/svelte/i18n.d.ts.map +1 -0
- package/dist/svelte/i18n.js +15 -0
- package/dist/svelte/index.d.ts +23 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +27 -0
- package/dist/svelte/playground.d.ts +151 -0
- package/dist/svelte/playground.d.ts.map +1 -0
- package/dist/svelte/playground.js +134 -0
- package/dist/sveltekit/index.d.ts +379 -0
- package/dist/sveltekit/index.d.ts.map +1 -0
- package/dist/sveltekit/resource-list-handler.d.ts +127 -0
- package/dist/sveltekit/resource-list-handler.d.ts.map +1 -0
- package/dist/sveltekit/types.d.ts +31 -0
- package/dist/sveltekit/types.d.ts.map +1 -0
- package/dist/sveltekit.d.ts +2 -0
- package/dist/sveltekit.d.ts.map +1 -0
- package/dist/sveltekit.js +978 -0
- package/dist/sveltekit.js.map +1 -0
- package/dist/types/index.d.ts +61 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/ui.d.ts +10 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +75 -0
- package/dist/ui.js.map +1 -0
- package/package.json +97 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserMenu.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/UserMenu.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAM5D,uCAAuC;AACvC,MAAM,WAAW,KAAK;IACpB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8DAA8D;IAC9D,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,uBAAuB;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA+HD,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
/**
|
|
3
|
+
* Component coverage for InviteUserModal via the shared S11 harness (#1416).
|
|
4
|
+
*/
|
|
5
|
+
import { fireEvent, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
|
|
6
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import InviteUserModal from '../InviteUserModal.svelte';
|
|
8
|
+
const baseProps = (over = {}) => ({
|
|
9
|
+
open: true,
|
|
10
|
+
tenant: { name: 'Acme' },
|
|
11
|
+
roles: [{ id: 'r1', slug: 'member', name: 'Member' }],
|
|
12
|
+
onsubmit: vi.fn(),
|
|
13
|
+
onclose: vi.fn(),
|
|
14
|
+
...over,
|
|
15
|
+
});
|
|
16
|
+
describe('InviteUserModal', () => {
|
|
17
|
+
it('renders the invite dialog scoped to the tenant when open', () => {
|
|
18
|
+
render(InviteUserModal, { props: baseProps() });
|
|
19
|
+
expect(screen.getByRole('heading', { name: 'Invite User to Acme' })).toBeInTheDocument();
|
|
20
|
+
expect(screen.getByLabelText('Email address')).toBeInTheDocument();
|
|
21
|
+
expect(screen.getByRole('button', { name: 'Send Invite' })).toBeInTheDocument();
|
|
22
|
+
});
|
|
23
|
+
it('renders nothing when closed', () => {
|
|
24
|
+
render(InviteUserModal, { props: baseProps({ open: false }) });
|
|
25
|
+
expect(screen.queryByRole('dialog')).toBeNull();
|
|
26
|
+
});
|
|
27
|
+
it('shows the JS validation error when submitted with no email', async () => {
|
|
28
|
+
const onsubmit = vi.fn();
|
|
29
|
+
const { container } = render(InviteUserModal, {
|
|
30
|
+
props: baseProps({ onsubmit }),
|
|
31
|
+
});
|
|
32
|
+
// Submit the form directly to exercise the component's own guard — a button
|
|
33
|
+
// click would be pre-empted by the input's native `required` constraint.
|
|
34
|
+
const form = container.querySelector('form');
|
|
35
|
+
if (!form)
|
|
36
|
+
throw new Error('form not found');
|
|
37
|
+
await fireEvent.submit(form);
|
|
38
|
+
expect(screen.getByText('Email is required')).toBeInTheDocument();
|
|
39
|
+
expect(onsubmit).not.toHaveBeenCalled();
|
|
40
|
+
});
|
|
41
|
+
it('submits the email and default role', async () => {
|
|
42
|
+
const onsubmit = vi.fn();
|
|
43
|
+
render(InviteUserModal, { props: baseProps({ onsubmit }) });
|
|
44
|
+
await userEvent.type(screen.getByLabelText('Email address'), 'ada@example.com');
|
|
45
|
+
await userEvent.click(screen.getByRole('button', { name: 'Send Invite' }));
|
|
46
|
+
expect(onsubmit).toHaveBeenCalledWith(expect.objectContaining({ email: 'ada@example.com', roleId: 'r1' }));
|
|
47
|
+
});
|
|
48
|
+
it('closes via the Cancel button', async () => {
|
|
49
|
+
const onclose = vi.fn();
|
|
50
|
+
render(InviteUserModal, { props: baseProps({ onclose }) });
|
|
51
|
+
await userEvent.click(screen.getByRole('button', { name: 'Cancel' }));
|
|
52
|
+
expect(onclose).toHaveBeenCalledTimes(1);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
/**
|
|
3
|
+
* First component test in smrt-users via the shared S11 harness (#1416): the
|
|
4
|
+
* Testing-Library + axe surface comes from `@happyvertical/smrt-vitest` and the
|
|
5
|
+
* jsdom + jest-dom setup from the shared `svelte-setup` wired in vitest.config.
|
|
6
|
+
*/
|
|
7
|
+
import { expectNoA11yViolations, render, screen, } from '@happyvertical/smrt-vitest/svelte';
|
|
8
|
+
import { describe, expect, it } from 'vitest';
|
|
9
|
+
import UserAvatar from '../UserAvatar.svelte';
|
|
10
|
+
// UserAvatar only reads `profile.name`, so a minimal stub is enough to drive it.
|
|
11
|
+
const profile = { name: 'Ada Lovelace' };
|
|
12
|
+
describe('UserAvatar', () => {
|
|
13
|
+
it('renders the initials derived from the profile name', () => {
|
|
14
|
+
render(UserAvatar, { props: { profile } });
|
|
15
|
+
expect(screen.getByText('AL')).toBeInTheDocument();
|
|
16
|
+
});
|
|
17
|
+
it('renders the full name when showName is set', () => {
|
|
18
|
+
render(UserAvatar, { props: { profile, showName: true } });
|
|
19
|
+
expect(screen.getByText('Ada Lovelace')).toBeInTheDocument();
|
|
20
|
+
});
|
|
21
|
+
it('falls back to "U" initials for a profile with no name', () => {
|
|
22
|
+
render(UserAvatar, { props: { profile: {} } });
|
|
23
|
+
expect(screen.getByText('U')).toBeInTheDocument();
|
|
24
|
+
});
|
|
25
|
+
it('is axe-clean', async () => {
|
|
26
|
+
const { container } = render(UserAvatar, {
|
|
27
|
+
props: { profile, showName: true },
|
|
28
|
+
});
|
|
29
|
+
await expectNoA11yViolations(container);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
/**
|
|
3
|
+
* Component coverage for UserCard via the shared S11 harness (#1416).
|
|
4
|
+
*/
|
|
5
|
+
import { expectNoA11yViolations, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
|
|
6
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import UserCard from '../UserCard.svelte';
|
|
8
|
+
const baseProps = (over = {}) => ({
|
|
9
|
+
user: { id: 'u1', email: 'ada@example.com', status: 'active' },
|
|
10
|
+
profile: { name: 'Ada Lovelace' },
|
|
11
|
+
role: 'admin',
|
|
12
|
+
status: 'active',
|
|
13
|
+
...over,
|
|
14
|
+
});
|
|
15
|
+
describe('UserCard', () => {
|
|
16
|
+
it('renders the name, email, role, and status', () => {
|
|
17
|
+
render(UserCard, { props: baseProps() });
|
|
18
|
+
expect(screen.getByText('Ada Lovelace')).toBeInTheDocument();
|
|
19
|
+
expect(screen.getByText('ada@example.com')).toBeInTheDocument();
|
|
20
|
+
expect(screen.getByText('admin')).toBeInTheDocument();
|
|
21
|
+
expect(screen.getByText('active')).toBeInTheDocument();
|
|
22
|
+
});
|
|
23
|
+
it('invokes onclick when the card is activated', async () => {
|
|
24
|
+
const onclick = vi.fn();
|
|
25
|
+
render(UserCard, { props: baseProps({ onclick }) });
|
|
26
|
+
await userEvent.click(screen.getByRole('button'));
|
|
27
|
+
expect(onclick).toHaveBeenCalledTimes(1);
|
|
28
|
+
});
|
|
29
|
+
it('is a disabled, non-interactive card without an onclick', () => {
|
|
30
|
+
render(UserCard, { props: baseProps() });
|
|
31
|
+
expect(screen.getByRole('button')).toBeDisabled();
|
|
32
|
+
});
|
|
33
|
+
it('is axe-clean', async () => {
|
|
34
|
+
const { container } = render(UserCard, {
|
|
35
|
+
props: baseProps({ onclick: vi.fn() }),
|
|
36
|
+
});
|
|
37
|
+
await expectNoA11yViolations(container);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
/**
|
|
3
|
+
* Component coverage for UserForm via the shared S11 harness (#1416).
|
|
4
|
+
*/
|
|
5
|
+
import { expectNoA11yViolations, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
|
|
6
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import UserForm from '../UserForm.svelte';
|
|
8
|
+
describe('UserForm', () => {
|
|
9
|
+
it('renders create-mode fields and a Create button', () => {
|
|
10
|
+
render(UserForm, { props: { onsubmit: vi.fn() } });
|
|
11
|
+
expect(screen.getByLabelText('Name')).toBeInTheDocument();
|
|
12
|
+
expect(screen.getByLabelText('Email')).toBeInTheDocument();
|
|
13
|
+
expect(screen.getByLabelText('Status')).toBeInTheDocument();
|
|
14
|
+
expect(screen.getByRole('button', { name: 'Create User' })).toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
it('submits the entered name and email', async () => {
|
|
17
|
+
const onsubmit = vi.fn();
|
|
18
|
+
render(UserForm, { props: { onsubmit } });
|
|
19
|
+
await userEvent.type(screen.getByLabelText('Name'), 'Ada Lovelace');
|
|
20
|
+
await userEvent.type(screen.getByLabelText('Email'), 'ada@example.com');
|
|
21
|
+
await userEvent.click(screen.getByRole('button', { name: 'Create User' }));
|
|
22
|
+
expect(onsubmit).toHaveBeenCalledWith(expect.objectContaining({
|
|
23
|
+
name: 'Ada Lovelace',
|
|
24
|
+
email: 'ada@example.com',
|
|
25
|
+
}));
|
|
26
|
+
});
|
|
27
|
+
it('locks the email and switches to update mode for an existing user', () => {
|
|
28
|
+
render(UserForm, {
|
|
29
|
+
props: {
|
|
30
|
+
onsubmit: vi.fn(),
|
|
31
|
+
user: { email: 'ada@example.com', status: 'active' },
|
|
32
|
+
profile: { name: 'Ada Lovelace' },
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
expect(screen.getByLabelText('Email')).toBeDisabled();
|
|
36
|
+
expect(screen.getByRole('button', { name: 'Update User' })).toBeInTheDocument();
|
|
37
|
+
});
|
|
38
|
+
it('invokes oncancel from the Cancel button', async () => {
|
|
39
|
+
const oncancel = vi.fn();
|
|
40
|
+
render(UserForm, { props: { onsubmit: vi.fn(), oncancel } });
|
|
41
|
+
await userEvent.click(screen.getByRole('button', { name: 'Cancel' }));
|
|
42
|
+
expect(oncancel).toHaveBeenCalledTimes(1);
|
|
43
|
+
});
|
|
44
|
+
it('is axe-clean', async () => {
|
|
45
|
+
const { container } = render(UserForm, {
|
|
46
|
+
props: { onsubmit: vi.fn(), oncancel: vi.fn() },
|
|
47
|
+
});
|
|
48
|
+
await expectNoA11yViolations(container);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
/**
|
|
3
|
+
* Component coverage for UserList via the shared S11 harness (#1416).
|
|
4
|
+
*/
|
|
5
|
+
import { expectNoA11yViolations, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
|
|
6
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import UserList from '../UserList.svelte';
|
|
8
|
+
const users = [
|
|
9
|
+
{
|
|
10
|
+
user: { id: 'u1', email: 'ada@example.com', status: 'active' },
|
|
11
|
+
profile: { name: 'Ada Lovelace' },
|
|
12
|
+
role: 'admin',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
user: { id: 'u2', email: 'alan@example.com', status: 'pending' },
|
|
16
|
+
profile: { name: 'Alan Turing' },
|
|
17
|
+
role: 'member',
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
describe('UserList', () => {
|
|
21
|
+
it('renders a card per user', () => {
|
|
22
|
+
render(UserList, { props: { users } });
|
|
23
|
+
expect(screen.getByText('Ada Lovelace')).toBeInTheDocument();
|
|
24
|
+
expect(screen.getByText('Alan Turing')).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
it('forwards the selected user through onselect', async () => {
|
|
27
|
+
const onselect = vi.fn();
|
|
28
|
+
render(UserList, { props: { users, onselect } });
|
|
29
|
+
await userEvent.click(screen.getByText('Alan Turing'));
|
|
30
|
+
expect(onselect).toHaveBeenCalledWith(expect.objectContaining({ id: 'u2' }));
|
|
31
|
+
});
|
|
32
|
+
it('shows the empty message when there are no users', () => {
|
|
33
|
+
render(UserList, {
|
|
34
|
+
props: { users: [], emptyMessage: 'Nobody here' },
|
|
35
|
+
});
|
|
36
|
+
expect(screen.getByText('Nobody here')).toBeInTheDocument();
|
|
37
|
+
});
|
|
38
|
+
it('shows a loading state', () => {
|
|
39
|
+
render(UserList, { props: { users: [], loading: true } });
|
|
40
|
+
expect(screen.getByText('Loading users...')).toBeInTheDocument();
|
|
41
|
+
});
|
|
42
|
+
it('is axe-clean', async () => {
|
|
43
|
+
const { container } = render(UserList, {
|
|
44
|
+
props: { users, onselect: vi.fn() },
|
|
45
|
+
});
|
|
46
|
+
await expectNoA11yViolations(container);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
/**
|
|
3
|
+
* Component coverage for UserMenu via the shared S11 harness (#1416), plus the
|
|
4
|
+
* S12 a11y remediation (#1417): the open dropdown now has its own id (no longer
|
|
5
|
+
* duplicating the wrapper) and `aria-labelledby` resolves to the trigger, so axe
|
|
6
|
+
* is asserted on both the collapsed and open states.
|
|
7
|
+
*/
|
|
8
|
+
import { expectNoA11yViolations, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
|
|
9
|
+
import { describe, expect, it } from 'vitest';
|
|
10
|
+
import UserMenu from '../UserMenu.svelte';
|
|
11
|
+
describe('UserMenu', () => {
|
|
12
|
+
it('renders a collapsed trigger labelled with the display name', () => {
|
|
13
|
+
render(UserMenu, { props: { user: { name: 'Ada Lovelace' } } });
|
|
14
|
+
const trigger = screen.getByRole('button', { name: 'User menu' });
|
|
15
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
16
|
+
expect(screen.getByText('Ada Lovelace')).toBeInTheDocument();
|
|
17
|
+
expect(screen.queryByRole('menu')).toBeNull();
|
|
18
|
+
});
|
|
19
|
+
it('opens the menu with profile/settings/sign-out items on click', async () => {
|
|
20
|
+
render(UserMenu, {
|
|
21
|
+
props: { user: { name: 'Ada Lovelace', email: 'ada@example.com' } },
|
|
22
|
+
});
|
|
23
|
+
await userEvent.click(screen.getByRole('button', { name: 'User menu' }));
|
|
24
|
+
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
25
|
+
expect(screen.getByRole('menuitem', { name: 'Profile' })).toBeInTheDocument();
|
|
26
|
+
expect(screen.getByRole('menuitem', { name: 'Settings' })).toBeInTheDocument();
|
|
27
|
+
expect(screen.getByRole('menuitem', { name: 'Sign out' })).toBeInTheDocument();
|
|
28
|
+
});
|
|
29
|
+
it('is axe-clean while collapsed and when open', async () => {
|
|
30
|
+
const { container } = render(UserMenu, {
|
|
31
|
+
props: { user: { name: 'Ada Lovelace', email: 'ada@example.com' } },
|
|
32
|
+
});
|
|
33
|
+
await expectNoA11yViolations(container);
|
|
34
|
+
await userEvent.click(screen.getByRole('button', { name: 'User menu' }));
|
|
35
|
+
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
36
|
+
await expectNoA11yViolations(container);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const M: {
|
|
2
|
+
readonly 'users.invite_user_modal.close_invite_dialog': "users.invite_user_modal.close_invite_dialog";
|
|
3
|
+
readonly 'users.invite_user_modal.title': "users.invite_user_modal.title";
|
|
4
|
+
readonly 'users.invite_user_modal.close': "users.invite_user_modal.close";
|
|
5
|
+
readonly 'users.invite_user_modal.email_address': "users.invite_user_modal.email_address";
|
|
6
|
+
readonly 'users.invite_user_modal.email_placeholder': "users.invite_user_modal.email_placeholder";
|
|
7
|
+
readonly 'users.invite_user_modal.send_invitation_email': "users.invite_user_modal.send_invitation_email";
|
|
8
|
+
readonly 'users.invite_user_modal.pending_hint': "users.invite_user_modal.pending_hint";
|
|
9
|
+
readonly 'users.invite_user_modal.sending': "users.invite_user_modal.sending";
|
|
10
|
+
readonly 'users.invite_user_modal.send_invite': "users.invite_user_modal.send_invite";
|
|
11
|
+
readonly 'users.user_form.email_cannot_be_changed': "users.user_form.email_cannot_be_changed";
|
|
12
|
+
readonly 'users.user_list.loading_users': "users.user_list.loading_users";
|
|
13
|
+
readonly 'users.user_menu.sign_out': "users.user_menu.sign_out";
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=i18n.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/svelte/i18n.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,CAAC;;;;;;;;;;;;;CAeZ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineMessages } from '@happyvertical/smrt-ui/i18n';
|
|
2
|
+
export const M = defineMessages({
|
|
3
|
+
'users.invite_user_modal.close_invite_dialog': 'Close invite dialog',
|
|
4
|
+
'users.invite_user_modal.title': 'Invite User to {tenantName}',
|
|
5
|
+
'users.invite_user_modal.close': 'Close',
|
|
6
|
+
'users.invite_user_modal.email_address': 'Email address',
|
|
7
|
+
'users.invite_user_modal.email_placeholder': 'user@example.com',
|
|
8
|
+
'users.invite_user_modal.send_invitation_email': 'Send invitation email',
|
|
9
|
+
'users.invite_user_modal.pending_hint': 'The user will be added with pending status. Share the invite link manually.',
|
|
10
|
+
'users.invite_user_modal.sending': 'Sending...',
|
|
11
|
+
'users.invite_user_modal.send_invite': 'Send Invite',
|
|
12
|
+
'users.user_form.email_cannot_be_changed': 'Email cannot be changed after creation',
|
|
13
|
+
'users.user_list.loading_users': 'Loading users...',
|
|
14
|
+
'users.user_menu.sign_out': 'Sign out',
|
|
15
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Users Module Svelte Components
|
|
3
|
+
*
|
|
4
|
+
* Optional Svelte UI components for user and tenant management.
|
|
5
|
+
* Auto-registers components with ModuleUIRegistry on import.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import type { ComponentProps } from 'svelte';
|
|
10
|
+
import InviteUserModal from './components/InviteUserModal.svelte';
|
|
11
|
+
import UserAvatar from './components/UserAvatar.svelte';
|
|
12
|
+
import UserCard from './components/UserCard.svelte';
|
|
13
|
+
import UserForm from './components/UserForm.svelte';
|
|
14
|
+
import UserList from './components/UserList.svelte';
|
|
15
|
+
import UserMenu from './components/UserMenu.svelte';
|
|
16
|
+
export { InviteUserModal, UserAvatar, UserCard, UserForm, UserList, UserMenu };
|
|
17
|
+
export type InviteUserModalProps = ComponentProps<typeof InviteUserModal>;
|
|
18
|
+
export type UserAvatarProps = ComponentProps<typeof UserAvatar>;
|
|
19
|
+
export type UserCardProps = ComponentProps<typeof UserCard>;
|
|
20
|
+
export type UserFormProps = ComponentProps<typeof UserForm>;
|
|
21
|
+
export type UserListProps = ComponentProps<typeof UserList>;
|
|
22
|
+
export type UserMenuProps = ComponentProps<typeof UserMenu>;
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/svelte/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAI7C,OAAO,eAAe,MAAM,qCAAqC,CAAC;AAClE,OAAO,UAAU,MAAM,gCAAgC,CAAC;AACxD,OAAO,QAAQ,MAAM,8BAA8B,CAAC;AACpD,OAAO,QAAQ,MAAM,8BAA8B,CAAC;AACpD,OAAO,QAAQ,MAAM,8BAA8B,CAAC;AACpD,OAAO,QAAQ,MAAM,8BAA8B,CAAC;AAGpD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAG/E,MAAM,MAAM,oBAAoB,GAAG,cAAc,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1E,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,UAAU,CAAC,CAAC;AAChE,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5D,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5D,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5D,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,QAAQ,CAAC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Users Module Svelte Components
|
|
3
|
+
*
|
|
4
|
+
* Optional Svelte UI components for user and tenant management.
|
|
5
|
+
* Auto-registers components with ModuleUIRegistry on import.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import { ModuleUIRegistry } from '@happyvertical/smrt-ui/registry';
|
|
10
|
+
import { USERS_MODULE_META } from '../ui.js';
|
|
11
|
+
// Import components
|
|
12
|
+
import InviteUserModal from './components/InviteUserModal.svelte';
|
|
13
|
+
import UserAvatar from './components/UserAvatar.svelte';
|
|
14
|
+
import UserCard from './components/UserCard.svelte';
|
|
15
|
+
import UserForm from './components/UserForm.svelte';
|
|
16
|
+
import UserList from './components/UserList.svelte';
|
|
17
|
+
import UserMenu from './components/UserMenu.svelte';
|
|
18
|
+
// Export components
|
|
19
|
+
export { InviteUserModal, UserAvatar, UserCard, UserForm, UserList, UserMenu };
|
|
20
|
+
// Auto-register with ModuleUIRegistry
|
|
21
|
+
ModuleUIRegistry.registerModule(USERS_MODULE_META);
|
|
22
|
+
ModuleUIRegistry.register('@happyvertical/smrt-users', 'invite-user-modal', InviteUserModal);
|
|
23
|
+
ModuleUIRegistry.register('@happyvertical/smrt-users', 'user-avatar', UserAvatar);
|
|
24
|
+
ModuleUIRegistry.register('@happyvertical/smrt-users', 'user-card', UserCard);
|
|
25
|
+
ModuleUIRegistry.register('@happyvertical/smrt-users', 'user-form', UserForm);
|
|
26
|
+
ModuleUIRegistry.register('@happyvertical/smrt-users', 'user-list', UserList);
|
|
27
|
+
ModuleUIRegistry.register('@happyvertical/smrt-users', 'user-menu', UserMenu);
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
packageName: string;
|
|
3
|
+
displayName: string;
|
|
4
|
+
description: string | undefined;
|
|
5
|
+
moduleMeta: import("@happyvertical/smrt-types").SmrtModuleMeta;
|
|
6
|
+
entries: ({
|
|
7
|
+
id: string;
|
|
8
|
+
title: string;
|
|
9
|
+
description: string;
|
|
10
|
+
loadComponent: () => Promise<typeof import("./components/UserList.svelte")>;
|
|
11
|
+
order: number;
|
|
12
|
+
props: {
|
|
13
|
+
users: {
|
|
14
|
+
user: {
|
|
15
|
+
id: string;
|
|
16
|
+
email: string;
|
|
17
|
+
status: string;
|
|
18
|
+
};
|
|
19
|
+
profile: {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
email: string;
|
|
23
|
+
};
|
|
24
|
+
role: string;
|
|
25
|
+
}[];
|
|
26
|
+
selectedId: string;
|
|
27
|
+
onselect: () => void;
|
|
28
|
+
user?: undefined;
|
|
29
|
+
profile?: undefined;
|
|
30
|
+
onsubmit?: undefined;
|
|
31
|
+
oncancel?: undefined;
|
|
32
|
+
open?: undefined;
|
|
33
|
+
tenant?: undefined;
|
|
34
|
+
roles?: undefined;
|
|
35
|
+
onclose?: undefined;
|
|
36
|
+
profileUrl?: undefined;
|
|
37
|
+
settingsUrl?: undefined;
|
|
38
|
+
signoutUrl?: undefined;
|
|
39
|
+
};
|
|
40
|
+
modes: {
|
|
41
|
+
mock: {
|
|
42
|
+
label: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
} | {
|
|
46
|
+
id: string;
|
|
47
|
+
title: string;
|
|
48
|
+
description: string;
|
|
49
|
+
loadComponent: () => Promise<typeof import("./components/UserForm.svelte")>;
|
|
50
|
+
order: number;
|
|
51
|
+
props: {
|
|
52
|
+
user: {
|
|
53
|
+
id: string;
|
|
54
|
+
email: string;
|
|
55
|
+
status: string;
|
|
56
|
+
};
|
|
57
|
+
profile: {
|
|
58
|
+
id: string;
|
|
59
|
+
name: string;
|
|
60
|
+
email: string;
|
|
61
|
+
};
|
|
62
|
+
onsubmit: () => void;
|
|
63
|
+
oncancel: () => void;
|
|
64
|
+
users?: undefined;
|
|
65
|
+
selectedId?: undefined;
|
|
66
|
+
onselect?: undefined;
|
|
67
|
+
open?: undefined;
|
|
68
|
+
tenant?: undefined;
|
|
69
|
+
roles?: undefined;
|
|
70
|
+
onclose?: undefined;
|
|
71
|
+
profileUrl?: undefined;
|
|
72
|
+
settingsUrl?: undefined;
|
|
73
|
+
signoutUrl?: undefined;
|
|
74
|
+
};
|
|
75
|
+
modes: {
|
|
76
|
+
mock: {
|
|
77
|
+
label: string;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
} | {
|
|
81
|
+
id: string;
|
|
82
|
+
title: string;
|
|
83
|
+
description: string;
|
|
84
|
+
loadComponent: () => Promise<typeof import("./components/InviteUserModal.svelte")>;
|
|
85
|
+
order: number;
|
|
86
|
+
props: {
|
|
87
|
+
open: boolean;
|
|
88
|
+
tenant: {
|
|
89
|
+
id: string;
|
|
90
|
+
name: string;
|
|
91
|
+
slug: string;
|
|
92
|
+
status: string;
|
|
93
|
+
};
|
|
94
|
+
roles: {
|
|
95
|
+
id: string;
|
|
96
|
+
slug: string;
|
|
97
|
+
name: string;
|
|
98
|
+
description: string;
|
|
99
|
+
}[];
|
|
100
|
+
onsubmit: () => void;
|
|
101
|
+
onclose: () => void;
|
|
102
|
+
users?: undefined;
|
|
103
|
+
selectedId?: undefined;
|
|
104
|
+
onselect?: undefined;
|
|
105
|
+
user?: undefined;
|
|
106
|
+
profile?: undefined;
|
|
107
|
+
oncancel?: undefined;
|
|
108
|
+
profileUrl?: undefined;
|
|
109
|
+
settingsUrl?: undefined;
|
|
110
|
+
signoutUrl?: undefined;
|
|
111
|
+
};
|
|
112
|
+
modes: {
|
|
113
|
+
mock: {
|
|
114
|
+
label: string;
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
} | {
|
|
118
|
+
id: string;
|
|
119
|
+
title: string;
|
|
120
|
+
description: string;
|
|
121
|
+
loadComponent: () => Promise<typeof import("./components/UserMenu.svelte")>;
|
|
122
|
+
order: number;
|
|
123
|
+
props: {
|
|
124
|
+
profile: {
|
|
125
|
+
id: string;
|
|
126
|
+
name: string;
|
|
127
|
+
email: string;
|
|
128
|
+
};
|
|
129
|
+
profileUrl: string;
|
|
130
|
+
settingsUrl: string;
|
|
131
|
+
signoutUrl: string;
|
|
132
|
+
users?: undefined;
|
|
133
|
+
selectedId?: undefined;
|
|
134
|
+
onselect?: undefined;
|
|
135
|
+
user?: undefined;
|
|
136
|
+
onsubmit?: undefined;
|
|
137
|
+
oncancel?: undefined;
|
|
138
|
+
open?: undefined;
|
|
139
|
+
tenant?: undefined;
|
|
140
|
+
roles?: undefined;
|
|
141
|
+
onclose?: undefined;
|
|
142
|
+
};
|
|
143
|
+
modes: {
|
|
144
|
+
mock: {
|
|
145
|
+
label: string;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
})[];
|
|
149
|
+
};
|
|
150
|
+
export default _default;
|
|
151
|
+
//# sourceMappingURL=playground.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playground.d.ts","sourceRoot":"","sources":["../../src/svelte/playground.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4DA,wBAkFE"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { USERS_MODULE_META } from '../ui.js';
|
|
2
|
+
const noop = () => { };
|
|
3
|
+
const sampleTenant = {
|
|
4
|
+
id: 'tenant-riverstone',
|
|
5
|
+
name: 'Riverstone Newsroom',
|
|
6
|
+
slug: 'riverstone-newsroom',
|
|
7
|
+
status: 'active',
|
|
8
|
+
};
|
|
9
|
+
const sampleRoles = [
|
|
10
|
+
{
|
|
11
|
+
id: 'role-member',
|
|
12
|
+
slug: 'member',
|
|
13
|
+
name: 'Member',
|
|
14
|
+
description: 'Can collaborate on editorial work.',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: 'role-editor',
|
|
18
|
+
slug: 'editor',
|
|
19
|
+
name: 'Editor',
|
|
20
|
+
description: 'Can approve and publish content.',
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
const sampleUsers = [
|
|
24
|
+
{
|
|
25
|
+
user: {
|
|
26
|
+
id: 'user-taylor',
|
|
27
|
+
email: 'taylor@example.com',
|
|
28
|
+
status: 'active',
|
|
29
|
+
},
|
|
30
|
+
profile: {
|
|
31
|
+
id: 'profile-taylor',
|
|
32
|
+
name: 'Taylor Rowan',
|
|
33
|
+
email: 'taylor@example.com',
|
|
34
|
+
},
|
|
35
|
+
role: 'Editor',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
user: {
|
|
39
|
+
id: 'user-jordan',
|
|
40
|
+
email: 'jordan@example.com',
|
|
41
|
+
status: 'pending',
|
|
42
|
+
},
|
|
43
|
+
profile: {
|
|
44
|
+
id: 'profile-jordan',
|
|
45
|
+
name: 'Jordan Lee',
|
|
46
|
+
email: 'jordan@example.com',
|
|
47
|
+
},
|
|
48
|
+
role: 'Contributor',
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
const loadInviteUserModal = () => import('./components/InviteUserModal.svelte');
|
|
52
|
+
const loadUserForm = () => import('./components/UserForm.svelte');
|
|
53
|
+
const loadUserList = () => import('./components/UserList.svelte');
|
|
54
|
+
const loadUserMenu = () => import('./components/UserMenu.svelte');
|
|
55
|
+
export default {
|
|
56
|
+
packageName: '@happyvertical/smrt-users',
|
|
57
|
+
displayName: USERS_MODULE_META.displayName,
|
|
58
|
+
description: USERS_MODULE_META.description,
|
|
59
|
+
moduleMeta: USERS_MODULE_META,
|
|
60
|
+
entries: [
|
|
61
|
+
{
|
|
62
|
+
id: 'user-list',
|
|
63
|
+
title: 'User List',
|
|
64
|
+
description: 'Role-aware list of users with selection and profile display.',
|
|
65
|
+
loadComponent: loadUserList,
|
|
66
|
+
order: 1,
|
|
67
|
+
props: {
|
|
68
|
+
users: sampleUsers,
|
|
69
|
+
selectedId: 'user-taylor',
|
|
70
|
+
onselect: noop,
|
|
71
|
+
},
|
|
72
|
+
modes: {
|
|
73
|
+
mock: {
|
|
74
|
+
label: 'Mock',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'user-form',
|
|
80
|
+
title: 'User Form',
|
|
81
|
+
description: 'Create and edit form for user records and account status.',
|
|
82
|
+
loadComponent: loadUserForm,
|
|
83
|
+
order: 2,
|
|
84
|
+
props: {
|
|
85
|
+
user: sampleUsers[0].user,
|
|
86
|
+
profile: sampleUsers[0].profile,
|
|
87
|
+
onsubmit: noop,
|
|
88
|
+
oncancel: noop,
|
|
89
|
+
},
|
|
90
|
+
modes: {
|
|
91
|
+
mock: {
|
|
92
|
+
label: 'Mock',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: 'invite-user-modal',
|
|
98
|
+
title: 'Invite User Modal',
|
|
99
|
+
description: 'Invitation flow for adding a tenant member with a role assignment.',
|
|
100
|
+
loadComponent: loadInviteUserModal,
|
|
101
|
+
order: 3,
|
|
102
|
+
props: {
|
|
103
|
+
open: false,
|
|
104
|
+
tenant: sampleTenant,
|
|
105
|
+
roles: sampleRoles,
|
|
106
|
+
onsubmit: noop,
|
|
107
|
+
onclose: noop,
|
|
108
|
+
},
|
|
109
|
+
modes: {
|
|
110
|
+
mock: {
|
|
111
|
+
label: 'Mock',
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'user-menu',
|
|
117
|
+
title: 'User Menu',
|
|
118
|
+
description: 'Authenticated account menu for profile, settings, and sign-out actions.',
|
|
119
|
+
loadComponent: loadUserMenu,
|
|
120
|
+
order: 4,
|
|
121
|
+
props: {
|
|
122
|
+
profile: sampleUsers[0].profile,
|
|
123
|
+
profileUrl: '/settings/profile',
|
|
124
|
+
settingsUrl: '/settings',
|
|
125
|
+
signoutUrl: '/auth/signout',
|
|
126
|
+
},
|
|
127
|
+
modes: {
|
|
128
|
+
mock: {
|
|
129
|
+
label: 'Mock',
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
};
|