@vertesia/ui 1.6.0-dev.20260912.110338Z → 1.6.0-dev.20260918.063824Z
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/lib/env/index.d.ts +10 -4
- package/lib/env/index.d.ts.map +1 -1
- package/lib/env/index.js +8 -0
- package/lib/env/index.js.map +1 -1
- package/lib/features/agent/PayloadBuilder.d.ts.map +1 -1
- package/lib/features/agent/PayloadBuilder.js +6 -1
- package/lib/features/agent/PayloadBuilder.js.map +1 -1
- package/lib/features/agent/chat/AgentRunFeedback.d.ts +7 -0
- package/lib/features/agent/chat/AgentRunFeedback.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRunFeedback.js +13 -1
- package/lib/features/agent/chat/AgentRunFeedback.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +4 -3
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +2 -2
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +2 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentPlans.d.ts +1 -1
- package/lib/features/agent/chat/hooks/useAgentPlans.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentPlans.js +5 -5
- package/lib/features/agent/chat/hooks/useAgentPlans.js.map +1 -1
- package/lib/features/store/objects/search/DocumentSearchContext.d.ts.map +1 -1
- package/lib/features/store/objects/search/DocumentSearchContext.js +6 -1
- package/lib/features/store/objects/search/DocumentSearchContext.js.map +1 -1
- package/lib/features/user/UserInfo.d.ts +2 -0
- package/lib/features/user/UserInfo.d.ts.map +1 -1
- package/lib/session/UserSessionProvider.js +3 -3
- package/lib/session/UserSessionProvider.js.map +1 -1
- package/lib/session/auth/domainRouting.d.ts +3 -4
- package/lib/session/auth/domainRouting.d.ts.map +1 -1
- package/lib/session/auth/domainRouting.js +3 -4
- package/lib/session/auth/domainRouting.js.map +1 -1
- package/lib/session/auth/firebase.d.ts.map +1 -1
- package/lib/session/auth/firebase.js +10 -0
- package/lib/session/auth/firebase.js.map +1 -1
- package/lib/shell/login/SignInAuthPending.js +1 -1
- package/lib/shell/login/SignInAuthPending.js.map +1 -1
- package/lib/shell/login/SignInEmailStep.d.ts.map +1 -1
- package/lib/shell/login/SignInEmailStep.js +2 -2
- package/lib/shell/login/SignInEmailStep.js.map +1 -1
- package/lib/shell/login/SignInIcons.d.ts +1 -1
- package/lib/shell/login/SignInIcons.d.ts.map +1 -1
- package/lib/shell/login/signInUtils.d.ts +1 -1
- package/lib/shell/login/signInUtils.d.ts.map +1 -1
- package/lib/shell/login/signInUtils.js +5 -6
- package/lib/shell/login/signInUtils.js.map +1 -1
- package/lib/vertesia-ui-core.js +83 -41
- package/lib/vertesia-ui-core.js.map +1 -1
- package/lib/vertesia-ui-env.js +1 -1
- package/lib/vertesia-ui-env.js.map +1 -1
- package/lib/vertesia-ui-features.js +336 -317
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-layout.js +43 -19
- package/lib/vertesia-ui-layout.js.map +1 -1
- package/lib/vertesia-ui-rich-text.js +123 -74
- package/lib/vertesia-ui-rich-text.js.map +1 -1
- package/lib/vertesia-ui-router.js.map +1 -1
- package/lib/vertesia-ui-session.js +1 -1
- package/lib/vertesia-ui-session.js.map +1 -1
- package/lib/vertesia-ui-shell.js +57 -28
- package/lib/vertesia-ui-shell.js.map +1 -1
- package/lib/vertesia-ui-widgets.js +153 -97
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/lib/widgets/xml-viewer/hooks/useCollapsible.d.ts +1 -1
- package/package.json +20 -20
- package/src/env/index.test.ts +48 -0
- package/src/env/index.ts +15 -2
- package/src/features/agent/PayloadBuilder.tsx +6 -1
- package/src/features/agent/chat/AgentRunFeedback.test.tsx +18 -1
- package/src/features/agent/chat/AgentRunFeedback.tsx +13 -0
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +1 -1
- package/src/features/agent/chat/ModernAgentConversation.tsx +6 -5
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +2 -2
- package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +2 -2
- package/src/features/agent/chat/hooks/useAgentPlans.test.ts +52 -0
- package/src/features/agent/chat/hooks/useAgentPlans.ts +5 -5
- package/src/features/store/objects/search/DocumentSearchContext.ts +8 -3
- package/src/router/path.test.ts +5 -5
- package/src/session/UserSessionProvider.tsx +3 -3
- package/src/session/auth/auth-flow.md +21 -9
- package/src/session/auth/domainRouting.test.ts +1 -1
- package/src/session/auth/domainRouting.ts +3 -4
- package/src/session/auth/firebase.test.ts +25 -0
- package/src/session/auth/firebase.ts +10 -0
- package/src/shell/login/SignInAuthPending.tsx +3 -3
- package/src/shell/login/SignInEmailStep.test.tsx +32 -0
- package/src/shell/login/SignInEmailStep.tsx +13 -9
- package/src/shell/login/signInUtils.ts +12 -4
- package/src/widgets/markdown/CollaborativeMarkdownRenderer.test.tsx +11 -3
|
@@ -10,11 +10,10 @@ declare global {
|
|
|
10
10
|
/**
|
|
11
11
|
* The broker this app sends users to for sign-in and logout.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* different broker, and it keeps this default so an app that configures nothing is unaffected.
|
|
13
|
+
* A gateway or app can select a regional broker through Env.endpoints.auth.
|
|
14
|
+
* Unconfigured apps use the first-party central broker.
|
|
16
15
|
*/
|
|
17
|
-
export const DEFAULT_CENTRAL_AUTH_URL = 'https://
|
|
16
|
+
export const DEFAULT_CENTRAL_AUTH_URL = 'https://auth.vertesia.io/';
|
|
18
17
|
|
|
19
18
|
export function centralAuthUrl(): string {
|
|
20
19
|
const configured = Env.endpoints.auth;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Env } from '@vertesia/ui/env';
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { getFirebaseAuth, setFirebaseTenant } from './firebase';
|
|
4
|
+
|
|
5
|
+
vi.mock('firebase/app', () => ({ initializeApp: vi.fn(() => ({})) }));
|
|
6
|
+
vi.mock('firebase/auth', () => ({ getAuth: vi.fn(() => ({ tenantId: null })) }));
|
|
7
|
+
|
|
8
|
+
describe('configured Firebase tenant', () => {
|
|
9
|
+
afterEach(() => vi.restoreAllMocks());
|
|
10
|
+
|
|
11
|
+
it('initializes redirect handling with the tenant and skips email discovery', async () => {
|
|
12
|
+
vi.spyOn(Env, 'firebase', 'get').mockReturnValue({
|
|
13
|
+
apiKey: 'key',
|
|
14
|
+
authDomain: 'app.example.com',
|
|
15
|
+
projectId: 'project',
|
|
16
|
+
tenantId: 'fixed-tenant',
|
|
17
|
+
});
|
|
18
|
+
const fetchSpy = vi.spyOn(globalThis, 'fetch');
|
|
19
|
+
expect(getFirebaseAuth().tenantId).toBe('fixed-tenant');
|
|
20
|
+
const tenant = await setFirebaseTenant('someone@another-company.com');
|
|
21
|
+
expect(tenant?.firebaseTenantId).toBe('fixed-tenant');
|
|
22
|
+
expect(tenant?.provider).toBe('oidc');
|
|
23
|
+
expect(fetchSpy).not.toHaveBeenCalled();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -37,11 +37,21 @@ export function getFirebaseAnalytics(): Analytics {
|
|
|
37
37
|
export function getFirebaseAuth(): Auth {
|
|
38
38
|
if (!_firebaseAuth) {
|
|
39
39
|
_firebaseAuth = getAuth(getFirebaseApp());
|
|
40
|
+
_firebaseAuth.tenantId = Env.firebase?.tenantId ?? null;
|
|
40
41
|
}
|
|
41
42
|
return _firebaseAuth;
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
export async function setFirebaseTenant(tenantEmail?: string) {
|
|
46
|
+
if (Env.firebase?.tenantId) {
|
|
47
|
+
getFirebaseAuth().tenantId = Env.firebase.tenantId;
|
|
48
|
+
return {
|
|
49
|
+
firebaseTenantId: Env.firebase.tenantId,
|
|
50
|
+
provider: Env.firebase.providerType ?? 'oidc',
|
|
51
|
+
name: '',
|
|
52
|
+
label: '',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
45
55
|
if (!tenantEmail) {
|
|
46
56
|
console.log('No tenant name or email specified, skipping tenant setup');
|
|
47
57
|
return;
|
|
@@ -28,10 +28,10 @@ export default function SignInAuthPending({ provider, onCancel }: SignInAuthPend
|
|
|
28
28
|
</div>
|
|
29
29
|
|
|
30
30
|
<div className="w-full flex flex-col gap-2">
|
|
31
|
-
<
|
|
31
|
+
<div className="flex justify-center">
|
|
32
32
|
<Spinner />
|
|
33
|
-
|
|
34
|
-
</
|
|
33
|
+
</div>
|
|
34
|
+
<span>{t('auth.pending.authenticating')}</span>
|
|
35
35
|
{onCancel && (
|
|
36
36
|
<SignInStepButton variant="ghost" onClick={onCancel}>
|
|
37
37
|
{t('auth.pending.cancel')}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
2
|
+
import { afterEach, expect, it, vi } from 'vitest';
|
|
3
|
+
import SignInEmailStep from './SignInEmailStep';
|
|
4
|
+
|
|
5
|
+
const resolveTenant = vi.hoisted(() => vi.fn());
|
|
6
|
+
vi.mock('@vertesia/ui/session', () => ({ setFirebaseTenant: resolveTenant }));
|
|
7
|
+
vi.mock('@vertesia/ui/i18n', () => ({ useUITranslation: () => ({ t: (key: string) => key }) }));
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
cleanup();
|
|
10
|
+
vi.clearAllMocks();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('keeps feedback visible and prevents duplicate requests while tenant discovery is pending', async () => {
|
|
14
|
+
let finish!: () => void;
|
|
15
|
+
resolveTenant.mockReturnValue(
|
|
16
|
+
new Promise<void>((resolve) => {
|
|
17
|
+
finish = resolve;
|
|
18
|
+
}),
|
|
19
|
+
);
|
|
20
|
+
const onProceed = vi.fn();
|
|
21
|
+
render(<SignInEmailStep initialEmail="person@example.com" onProceed={onProceed} />);
|
|
22
|
+
const button = screen.getByRole('button', { name: 'auth.continue' });
|
|
23
|
+
fireEvent.click(button);
|
|
24
|
+
expect(screen.queryByRole('button', { name: 'auth.continue' })).toBeNull();
|
|
25
|
+
expect(screen.getByRole('textbox')).toBeTruthy();
|
|
26
|
+
expect(screen.getByRole('status')).toBeTruthy();
|
|
27
|
+
expect(button.contains(screen.getByRole('status'))).toBe(false);
|
|
28
|
+
fireEvent.submit(screen.getByRole('textbox').closest('form')!);
|
|
29
|
+
expect(resolveTenant).toHaveBeenCalledTimes(1);
|
|
30
|
+
finish();
|
|
31
|
+
await waitFor(() => expect(onProceed).toHaveBeenCalledWith('person@example.com', undefined));
|
|
32
|
+
});
|
|
@@ -67,16 +67,20 @@ export default function SignInEmailStep({ initialEmail, onProceed }: SignInEmail
|
|
|
67
67
|
error={submitError ? t('auth.email.invalidError') : undefined}
|
|
68
68
|
/>
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
{loading ? (
|
|
71
|
+
<div
|
|
72
|
+
role="status"
|
|
73
|
+
aria-label={t('auth.pending.authenticating')}
|
|
74
|
+
className="h-[42px] flex items-center justify-center"
|
|
75
|
+
>
|
|
72
76
|
<Spinner />
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
</div>
|
|
78
|
+
) : (
|
|
79
|
+
<SignInStepButton type="submit">
|
|
80
|
+
<span>{t('auth.continue')}</span>
|
|
81
|
+
<ArrowRight className="!size-3.5" />
|
|
82
|
+
</SignInStepButton>
|
|
83
|
+
)}
|
|
80
84
|
</form>
|
|
81
85
|
</SignInStepLayout>
|
|
82
86
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Env } from '@vertesia/ui/env';
|
|
1
2
|
import { getFirebaseAuth, setFirebaseTenant } from '@vertesia/ui/session';
|
|
2
3
|
import {
|
|
3
4
|
type AuthProvider,
|
|
@@ -197,7 +198,7 @@ export async function startSignIn(
|
|
|
197
198
|
} else {
|
|
198
199
|
// No tenant — clear any stale tenant routing from a prior attempt.
|
|
199
200
|
localStorage.removeItem('tenantName');
|
|
200
|
-
|
|
201
|
+
auth.tenantId = Env.firebase?.tenantId ?? null;
|
|
201
202
|
}
|
|
202
203
|
|
|
203
204
|
writePendingSignin({ email, provider: effectiveIdp, tenantName });
|
|
@@ -205,12 +206,19 @@ export async function startSignIn(
|
|
|
205
206
|
return { ok: true };
|
|
206
207
|
}
|
|
207
208
|
|
|
208
|
-
/** Starts
|
|
209
|
+
/** Starts sign-in without email discovery, preserving an explicitly configured tenant. */
|
|
209
210
|
export function startSignInWithoutTenant(provider: ProviderId, redirectTo?: string): void {
|
|
210
211
|
const auth = getFirebaseAuth();
|
|
211
212
|
localStorage.removeItem('tenantName');
|
|
212
|
-
|
|
213
|
-
void signInWithRedirect(
|
|
213
|
+
auth.tenantId = Env.firebase?.tenantId ?? null;
|
|
214
|
+
void signInWithRedirect(
|
|
215
|
+
auth,
|
|
216
|
+
buildFirebaseProvider(
|
|
217
|
+
Env.firebase?.tenantId ? ((Env.firebase.providerType as ProviderId) ?? 'oidc') : provider,
|
|
218
|
+
undefined,
|
|
219
|
+
redirectTo,
|
|
220
|
+
),
|
|
221
|
+
);
|
|
214
222
|
}
|
|
215
223
|
|
|
216
224
|
export function providerLabel(id: ProviderId): string {
|
|
@@ -412,11 +412,19 @@ describe('collaborative Markdown actions', () => {
|
|
|
412
412
|
await user.click(screen.getByRole('button', { name: 'Insert component after this block' }));
|
|
413
413
|
await user.click(await screen.findByRole('menuitem', { name: 'Paragraph' }));
|
|
414
414
|
|
|
415
|
-
|
|
415
|
+
// The lazy editor first renders a textarea with the same template text. Wait for
|
|
416
|
+
// the actual rich-text editor before selecting and pasting into its content.
|
|
417
|
+
const editor = await waitFor(() => {
|
|
418
|
+
const textbox = screen.getByRole('textbox');
|
|
419
|
+
expect(textbox.getAttribute('contenteditable')).toBe('true');
|
|
420
|
+
expect(textbox.textContent).toBe('Paragraph');
|
|
421
|
+
return textbox;
|
|
422
|
+
});
|
|
416
423
|
await user.click(editor);
|
|
424
|
+
await user.keyboard('{Control>}a{/Control}');
|
|
417
425
|
// Paste in one operation — char-by-char typing races ProseMirror in jsdom and drops chars.
|
|
418
426
|
await user.paste('Inserted paragraph.');
|
|
419
|
-
await waitFor(() => expect(editor.textContent
|
|
427
|
+
await waitFor(() => expect(editor.textContent).toBe('Inserted paragraph.'));
|
|
420
428
|
fireEvent.click(screen.getByRole('button', { name: 'Send' }));
|
|
421
429
|
|
|
422
430
|
await waitFor(() => expect(onAction).toHaveBeenCalledTimes(1));
|
|
@@ -425,7 +433,7 @@ describe('collaborative Markdown actions', () => {
|
|
|
425
433
|
action: 'edit',
|
|
426
434
|
user_change: {
|
|
427
435
|
before: 'Original paragraph.',
|
|
428
|
-
after:
|
|
436
|
+
after: 'Original paragraph.\n\nInserted paragraph.',
|
|
429
437
|
},
|
|
430
438
|
}),
|
|
431
439
|
);
|