@lobehub/lobehub 2.0.0-next.339 → 2.0.0-next.340
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 +25 -0
- package/changelog/v1.json +9 -0
- package/docs/self-hosting/advanced/auth/clerk-to-betterauth.mdx +366 -0
- package/docs/self-hosting/advanced/auth/clerk-to-betterauth.zh-CN.mdx +360 -0
- package/docs/self-hosting/advanced/auth/legacy.mdx +4 -0
- package/docs/self-hosting/advanced/auth/legacy.zh-CN.mdx +4 -0
- package/docs/self-hosting/advanced/auth.mdx +55 -30
- package/docs/self-hosting/advanced/auth.zh-CN.mdx +55 -30
- package/locales/ar/auth.json +1 -1
- package/locales/ar/desktop-onboarding.json +1 -0
- package/locales/ar/metadata.json +2 -2
- package/locales/ar/models.json +23 -5
- package/locales/ar/providers.json +0 -1
- package/locales/ar/setting.json +19 -0
- package/locales/bg-BG/auth.json +1 -1
- package/locales/bg-BG/desktop-onboarding.json +1 -0
- package/locales/bg-BG/metadata.json +2 -2
- package/locales/bg-BG/models.json +5 -5
- package/locales/bg-BG/providers.json +0 -1
- package/locales/bg-BG/setting.json +19 -0
- package/locales/de-DE/auth.json +1 -1
- package/locales/de-DE/desktop-onboarding.json +1 -0
- package/locales/de-DE/metadata.json +2 -2
- package/locales/de-DE/models.json +31 -10
- package/locales/de-DE/providers.json +0 -1
- package/locales/de-DE/setting.json +19 -0
- package/locales/en-US/auth.json +3 -2
- package/locales/en-US/metadata.json +2 -2
- package/locales/en-US/models.json +10 -11
- package/locales/en-US/providers.json +0 -1
- package/locales/es-ES/auth.json +1 -1
- package/locales/es-ES/desktop-onboarding.json +1 -0
- package/locales/es-ES/metadata.json +2 -2
- package/locales/es-ES/models.json +32 -5
- package/locales/es-ES/providers.json +0 -1
- package/locales/es-ES/setting.json +19 -0
- package/locales/fa-IR/auth.json +1 -1
- package/locales/fa-IR/desktop-onboarding.json +1 -0
- package/locales/fa-IR/metadata.json +2 -2
- package/locales/fa-IR/models.json +35 -5
- package/locales/fa-IR/providers.json +0 -1
- package/locales/fa-IR/setting.json +19 -0
- package/locales/fr-FR/auth.json +1 -1
- package/locales/fr-FR/desktop-onboarding.json +1 -0
- package/locales/fr-FR/metadata.json +2 -2
- package/locales/fr-FR/models.json +33 -5
- package/locales/fr-FR/providers.json +0 -1
- package/locales/fr-FR/setting.json +19 -0
- package/locales/it-IT/auth.json +1 -1
- package/locales/it-IT/desktop-onboarding.json +1 -0
- package/locales/it-IT/metadata.json +2 -2
- package/locales/it-IT/models.json +3 -8
- package/locales/it-IT/providers.json +0 -1
- package/locales/it-IT/setting.json +19 -0
- package/locales/ja-JP/auth.json +1 -1
- package/locales/ja-JP/desktop-onboarding.json +1 -0
- package/locales/ja-JP/metadata.json +2 -2
- package/locales/ja-JP/models.json +32 -5
- package/locales/ja-JP/providers.json +0 -1
- package/locales/ja-JP/setting.json +19 -0
- package/locales/ko-KR/auth.json +1 -1
- package/locales/ko-KR/desktop-onboarding.json +1 -0
- package/locales/ko-KR/metadata.json +2 -2
- package/locales/ko-KR/models.json +3 -8
- package/locales/ko-KR/providers.json +0 -1
- package/locales/ko-KR/setting.json +19 -0
- package/locales/nl-NL/auth.json +1 -1
- package/locales/nl-NL/desktop-onboarding.json +1 -0
- package/locales/nl-NL/metadata.json +2 -2
- package/locales/nl-NL/models.json +45 -4
- package/locales/nl-NL/providers.json +0 -1
- package/locales/nl-NL/setting.json +19 -0
- package/locales/pl-PL/auth.json +1 -1
- package/locales/pl-PL/desktop-onboarding.json +1 -0
- package/locales/pl-PL/metadata.json +2 -2
- package/locales/pl-PL/models.json +37 -5
- package/locales/pl-PL/providers.json +0 -1
- package/locales/pl-PL/setting.json +19 -0
- package/locales/pt-BR/auth.json +1 -1
- package/locales/pt-BR/desktop-onboarding.json +1 -0
- package/locales/pt-BR/metadata.json +2 -2
- package/locales/pt-BR/models.json +28 -4
- package/locales/pt-BR/providers.json +0 -1
- package/locales/pt-BR/setting.json +19 -0
- package/locales/ru-RU/auth.json +1 -1
- package/locales/ru-RU/desktop-onboarding.json +1 -0
- package/locales/ru-RU/metadata.json +2 -2
- package/locales/ru-RU/models.json +3 -8
- package/locales/ru-RU/providers.json +0 -1
- package/locales/ru-RU/setting.json +19 -0
- package/locales/tr-TR/auth.json +1 -1
- package/locales/tr-TR/desktop-onboarding.json +1 -0
- package/locales/tr-TR/metadata.json +2 -2
- package/locales/tr-TR/models.json +26 -7
- package/locales/tr-TR/providers.json +0 -1
- package/locales/tr-TR/setting.json +19 -0
- package/locales/vi-VN/auth.json +1 -1
- package/locales/vi-VN/desktop-onboarding.json +1 -0
- package/locales/vi-VN/metadata.json +2 -2
- package/locales/vi-VN/models.json +3 -5
- package/locales/vi-VN/providers.json +0 -1
- package/locales/vi-VN/setting.json +19 -0
- package/locales/zh-CN/auth.json +3 -3
- package/locales/zh-CN/metadata.json +2 -2
- package/locales/zh-CN/models.json +46 -6
- package/locales/zh-CN/providers.json +0 -1
- package/locales/zh-TW/auth.json +1 -1
- package/locales/zh-TW/desktop-onboarding.json +1 -0
- package/locales/zh-TW/metadata.json +2 -2
- package/locales/zh-TW/models.json +39 -6
- package/locales/zh-TW/providers.json +0 -1
- package/locales/zh-TW/setting.json +19 -0
- package/package.json +1 -1
- package/packages/const/src/url.ts +1 -1
- package/public/og/agent-og.webp +0 -0
- package/public/og/mcp-og.webp +0 -0
- package/public/og/og.webp +0 -0
- package/scripts/clerk-to-betterauth/__tests__/parseCsvLine.test.ts +21 -0
- package/scripts/clerk-to-betterauth/_internal/config.ts +55 -0
- package/scripts/clerk-to-betterauth/_internal/db.ts +32 -0
- package/scripts/clerk-to-betterauth/_internal/env.ts +6 -0
- package/scripts/clerk-to-betterauth/_internal/load-data-from-files.ts +74 -0
- package/scripts/clerk-to-betterauth/_internal/types.ts +45 -0
- package/scripts/clerk-to-betterauth/_internal/utils.ts +36 -0
- package/scripts/clerk-to-betterauth/export-clerk-users-with-api.ts +211 -0
- package/scripts/clerk-to-betterauth/index.ts +314 -0
- package/scripts/clerk-to-betterauth/prod/put_clerk_exported_users_csv_here.txt +0 -0
- package/scripts/clerk-to-betterauth/test/put_clerk_exported_users_csv_here.txt +0 -0
- package/scripts/clerk-to-betterauth/verify.ts +275 -0
- package/src/app/[variants]/(auth)/signin/SignInEmailStep.tsx +30 -2
- package/src/app/[variants]/(auth)/signin/SignInPasswordStep.tsx +1 -1
- package/src/app/[variants]/(auth)/signin/page.tsx +3 -0
- package/src/app/[variants]/(auth)/signin/useSignIn.ts +6 -2
- package/src/app/[variants]/(main)/home/features/RecentResource/Item.tsx +2 -2
- package/src/app/[variants]/(main)/home/features/index.tsx +1 -2
- package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/skill/features/Actions.tsx +8 -7
- package/src/app/[variants]/(main)/settings/skill/features/McpSkillItem.tsx +9 -11
- package/src/app/manifest.ts +4 -4
- package/src/features/AuthCard/index.tsx +1 -1
- package/src/features/SkillStore/CommunityList/Item.tsx +3 -2
- package/src/features/SkillStore/Search/index.tsx +0 -1
- package/src/locales/default/auth.ts +3 -2
- package/src/locales/default/metadata.ts +2 -2
- package/src/server/ld.ts +4 -3
- package/src/styles/global.ts +0 -6
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/apple.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/apple.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/auth0.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/auth0.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/authelia.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/authelia.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/authentik.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/authentik.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/casdoor.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/casdoor.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/cloudflare-zero-trust.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/cloudflare-zero-trust.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/cognito.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/cognito.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/feishu.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/feishu.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/generic-oidc.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/generic-oidc.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/github.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/github.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/google.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/google.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/keycloak.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/keycloak.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/logto.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/logto.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/microsoft.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/microsoft.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/okta.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/okta.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/wechat.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/wechat.zh-CN.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/zitadel.mdx +0 -0
- /package/docs/self-hosting/advanced/auth/{better-auth → providers}/zitadel.zh-CN.mdx +0 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/* eslint-disable unicorn/prefer-top-level-await */
|
|
2
|
+
import { getMigrationMode, resolveDataPaths } from './_internal/config';
|
|
3
|
+
import { db, pool, schema } from './_internal/db';
|
|
4
|
+
import { loadCSVData, loadClerkUsersFromFile } from './_internal/load-data-from-files';
|
|
5
|
+
import { ClerkExternalAccount, ClerkUser } from './_internal/types';
|
|
6
|
+
|
|
7
|
+
type ExpectedAccount = {
|
|
8
|
+
accountId?: string;
|
|
9
|
+
providerId: string;
|
|
10
|
+
scope?: string;
|
|
11
|
+
userId: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type ActualAccount = {
|
|
15
|
+
accountId: string | null;
|
|
16
|
+
providerId: string;
|
|
17
|
+
scope: string | null;
|
|
18
|
+
userId: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const MAX_SAMPLES = 5;
|
|
22
|
+
|
|
23
|
+
const formatDuration = (ms: number) => `${(ms / 1000).toFixed(1)}s`;
|
|
24
|
+
|
|
25
|
+
function providerIdFromExternal(external: ClerkExternalAccount): string {
|
|
26
|
+
return external.provider === 'credential'
|
|
27
|
+
? 'credential'
|
|
28
|
+
: external.provider.replace('oauth_', '');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function buildExpectedAccounts(
|
|
32
|
+
csvUsers: Awaited<ReturnType<typeof loadCSVData>>,
|
|
33
|
+
clerkUsers: ClerkUser[],
|
|
34
|
+
) {
|
|
35
|
+
const clerkMap = new Map(clerkUsers.map((u) => [u.id, u]));
|
|
36
|
+
|
|
37
|
+
const expectedAccounts: ExpectedAccount[] = [];
|
|
38
|
+
const expectedTwoFactorUsers = new Set<string>();
|
|
39
|
+
let passwordEnabledWithoutDigest = 0;
|
|
40
|
+
const passwordEnabledWithoutDigestSamples: string[] = [];
|
|
41
|
+
|
|
42
|
+
for (const user of csvUsers) {
|
|
43
|
+
const clerkUser = clerkMap.get(user.id);
|
|
44
|
+
const externalAccounts = clerkUser?.external_accounts as ClerkExternalAccount[] | undefined;
|
|
45
|
+
|
|
46
|
+
if (externalAccounts) {
|
|
47
|
+
for (const external of externalAccounts) {
|
|
48
|
+
expectedAccounts.push({
|
|
49
|
+
accountId: external.provider_user_id,
|
|
50
|
+
providerId: providerIdFromExternal(external),
|
|
51
|
+
scope: external.approved_scopes?.replace(/\s+/g, ','),
|
|
52
|
+
userId: user.id,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const passwordEnabled = Boolean(clerkUser?.password_enabled);
|
|
58
|
+
if (passwordEnabled && user.password_digest) {
|
|
59
|
+
expectedAccounts.push({
|
|
60
|
+
accountId: user.id,
|
|
61
|
+
providerId: 'credential',
|
|
62
|
+
scope: undefined,
|
|
63
|
+
userId: user.id,
|
|
64
|
+
});
|
|
65
|
+
} else if (passwordEnabled && !user.password_digest) {
|
|
66
|
+
passwordEnabledWithoutDigest += 1;
|
|
67
|
+
if (passwordEnabledWithoutDigestSamples.length < MAX_SAMPLES) {
|
|
68
|
+
passwordEnabledWithoutDigestSamples.push(user.id);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (user.totp_secret) {
|
|
73
|
+
expectedTwoFactorUsers.add(user.id);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
expectedAccounts,
|
|
79
|
+
expectedTwoFactorUsers,
|
|
80
|
+
passwordEnabledWithoutDigest,
|
|
81
|
+
passwordEnabledWithoutDigestSamples,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function buildAccountKey(account: {
|
|
86
|
+
accountId?: string | null;
|
|
87
|
+
providerId: string;
|
|
88
|
+
userId: string;
|
|
89
|
+
}) {
|
|
90
|
+
return `${account.userId}__${account.providerId}__${account.accountId ?? ''}`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function loadActualAccounts() {
|
|
94
|
+
const rows = await db
|
|
95
|
+
.select({
|
|
96
|
+
accountId: schema.account.accountId,
|
|
97
|
+
providerId: schema.account.providerId,
|
|
98
|
+
scope: schema.account.scope,
|
|
99
|
+
userId: schema.account.userId,
|
|
100
|
+
})
|
|
101
|
+
.from(schema.account);
|
|
102
|
+
|
|
103
|
+
return rows as ActualAccount[];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function loadActualTwoFactorUserIds() {
|
|
107
|
+
const rows = await db.select({ userId: schema.twoFactor.userId }).from(schema.twoFactor);
|
|
108
|
+
return new Set(rows.map((row) => row.userId));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function loadActualUserIds() {
|
|
112
|
+
const rows = await db.select({ id: schema.users.id }).from(schema.users);
|
|
113
|
+
return new Set(rows.map((row) => row.id));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function main() {
|
|
117
|
+
const startedAt = Date.now();
|
|
118
|
+
const mode = getMigrationMode();
|
|
119
|
+
const { clerkCsvPath, clerkUsersPath } = resolveDataPaths(mode);
|
|
120
|
+
|
|
121
|
+
console.log('');
|
|
122
|
+
console.log('╔════════════════════════════════════════════════════════════╗');
|
|
123
|
+
console.log('║ Migration Verification Script ║');
|
|
124
|
+
console.log('╠════════════════════════════════════════════════════════════╣');
|
|
125
|
+
console.log(`║ Mode: ${mode.padEnd(48)}║`);
|
|
126
|
+
console.log(`║ CSV: ${clerkCsvPath.padEnd(48)}║`);
|
|
127
|
+
console.log(`║ JSON: ${clerkUsersPath.padEnd(48)}║`);
|
|
128
|
+
console.log('╚════════════════════════════════════════════════════════════╝');
|
|
129
|
+
console.log('');
|
|
130
|
+
|
|
131
|
+
const [csvUsers, clerkUsers] = await Promise.all([
|
|
132
|
+
loadCSVData(clerkCsvPath),
|
|
133
|
+
loadClerkUsersFromFile(clerkUsersPath),
|
|
134
|
+
]);
|
|
135
|
+
|
|
136
|
+
console.log(
|
|
137
|
+
`📦 [verify] Loaded csvUsers=${csvUsers.length}, clerkUsers=${clerkUsers.length} (unique ids=${
|
|
138
|
+
new Set(clerkUsers.map((u) => u.id)).size
|
|
139
|
+
})`,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const {
|
|
143
|
+
expectedAccounts,
|
|
144
|
+
expectedTwoFactorUsers,
|
|
145
|
+
passwordEnabledWithoutDigest,
|
|
146
|
+
passwordEnabledWithoutDigestSamples,
|
|
147
|
+
} = buildExpectedAccounts(csvUsers, clerkUsers);
|
|
148
|
+
|
|
149
|
+
console.log(
|
|
150
|
+
`🧮 [verify] Expected accounts=${expectedAccounts.length}, expected 2FA users=${expectedTwoFactorUsers.size}, passwordEnabledWithoutDigest=${passwordEnabledWithoutDigest} sample=${
|
|
151
|
+
passwordEnabledWithoutDigestSamples.join(', ') || 'n/a'
|
|
152
|
+
}`,
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const [actualAccounts, actualTwoFactorUserIds, actualUserIds] = await Promise.all([
|
|
156
|
+
loadActualAccounts(),
|
|
157
|
+
loadActualTwoFactorUserIds(),
|
|
158
|
+
loadActualUserIds(),
|
|
159
|
+
]);
|
|
160
|
+
|
|
161
|
+
console.log(
|
|
162
|
+
`🗄️ [verify] DB snapshot: users=${actualUserIds.size}, accounts=${actualAccounts.length}, twoFactor=${actualTwoFactorUserIds.size}`,
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
let missingUsers = 0;
|
|
166
|
+
const missingUserSamples: string[] = [];
|
|
167
|
+
for (const user of csvUsers) {
|
|
168
|
+
if (!actualUserIds.has(user.id)) {
|
|
169
|
+
missingUsers += 1;
|
|
170
|
+
if (missingUserSamples.length < MAX_SAMPLES) missingUserSamples.push(user.id);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const expectedAccountSet = new Set(expectedAccounts.map(buildAccountKey));
|
|
175
|
+
const actualAccountSet = new Set(actualAccounts.map(buildAccountKey));
|
|
176
|
+
|
|
177
|
+
let missingAccounts = 0;
|
|
178
|
+
const missingAccountSamples: string[] = [];
|
|
179
|
+
for (const account of expectedAccounts) {
|
|
180
|
+
const key = buildAccountKey(account);
|
|
181
|
+
if (!actualAccountSet.has(key)) {
|
|
182
|
+
missingAccounts += 1;
|
|
183
|
+
if (missingAccountSamples.length < MAX_SAMPLES) missingAccountSamples.push(account.userId);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let unexpectedAccounts = 0;
|
|
188
|
+
const unexpectedAccountSamples: string[] = [];
|
|
189
|
+
for (const account of actualAccounts) {
|
|
190
|
+
const key = buildAccountKey(account);
|
|
191
|
+
if (!expectedAccountSet.has(key)) {
|
|
192
|
+
unexpectedAccounts += 1;
|
|
193
|
+
if (unexpectedAccountSamples.length < MAX_SAMPLES)
|
|
194
|
+
unexpectedAccountSamples.push(account.userId);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
let missingTwoFactor = 0;
|
|
199
|
+
const missingTwoFactorSamples: string[] = [];
|
|
200
|
+
for (const userId of expectedTwoFactorUsers) {
|
|
201
|
+
if (!actualTwoFactorUserIds.has(userId)) {
|
|
202
|
+
missingTwoFactor += 1;
|
|
203
|
+
if (missingTwoFactorSamples.length < MAX_SAMPLES) missingTwoFactorSamples.push(userId);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
let missingScopeNonCredential = 0;
|
|
208
|
+
let missingAccountIdNonCredential = 0;
|
|
209
|
+
const sampleMissingScope: string[] = [];
|
|
210
|
+
const sampleMissingAccountId: string[] = [];
|
|
211
|
+
|
|
212
|
+
for (const account of actualAccounts) {
|
|
213
|
+
if (account.providerId !== 'credential') {
|
|
214
|
+
if (!account.scope) {
|
|
215
|
+
missingScopeNonCredential += 1;
|
|
216
|
+
if (sampleMissingScope.length < MAX_SAMPLES) sampleMissingScope.push(account.userId);
|
|
217
|
+
}
|
|
218
|
+
if (!account.accountId) {
|
|
219
|
+
missingAccountIdNonCredential += 1;
|
|
220
|
+
if (sampleMissingAccountId.length < MAX_SAMPLES)
|
|
221
|
+
sampleMissingAccountId.push(account.userId);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const expectedProviderCounts: Record<string, number> = {};
|
|
227
|
+
const actualProviderCounts: Record<string, number> = {};
|
|
228
|
+
|
|
229
|
+
for (const account of expectedAccounts) {
|
|
230
|
+
expectedProviderCounts[account.providerId] =
|
|
231
|
+
(expectedProviderCounts[account.providerId] ?? 0) + 1;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
for (const account of actualAccounts) {
|
|
235
|
+
actualProviderCounts[account.providerId] = (actualProviderCounts[account.providerId] ?? 0) + 1;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const formatCounts = (counts: Record<string, number>) =>
|
|
239
|
+
Object.entries(counts)
|
|
240
|
+
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
|
|
241
|
+
.map(([providerId, count]) => `${providerId}=${count}`)
|
|
242
|
+
.join(', ');
|
|
243
|
+
|
|
244
|
+
console.log(
|
|
245
|
+
`📊 [verify] Expected provider counts: ${formatCounts(expectedProviderCounts) || 'n/a'}`,
|
|
246
|
+
);
|
|
247
|
+
console.log(
|
|
248
|
+
`📊 [verify] Actual provider counts: ${formatCounts(actualProviderCounts) || 'n/a'}`,
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
console.log(
|
|
252
|
+
`✅ [verify] Missing users=${missingUsers} sample=${missingUserSamples.join(', ') || 'n/a'}, missing accounts=${missingAccounts} sample=${missingAccountSamples.join(', ') || 'n/a'}, unexpected accounts=${unexpectedAccounts} sample=${unexpectedAccountSamples.join(', ') || 'n/a'}`,
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
console.log(
|
|
256
|
+
`🔐 [verify] Two-factor missing=${missingTwoFactor} sample=${missingTwoFactorSamples.join(', ') || 'n/a'}`,
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
console.log(
|
|
260
|
+
`⚠️ [verify] Non-credential missing scope=${missingScopeNonCredential} sample=${sampleMissingScope.join(', ') || 'n/a'}, missing account_id=${missingAccountIdNonCredential} sample=${sampleMissingAccountId.join(', ') || 'n/a'}`,
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
console.log('');
|
|
264
|
+
console.log(`✅ Verification success! (${formatDuration(Date.now() - startedAt)})`);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
void main()
|
|
268
|
+
.catch((error) => {
|
|
269
|
+
console.log('');
|
|
270
|
+
console.error('❌ Verification failed:', error);
|
|
271
|
+
process.exitCode = 1;
|
|
272
|
+
})
|
|
273
|
+
.finally(async () => {
|
|
274
|
+
await pool.end();
|
|
275
|
+
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { BRANDING_NAME } from '@lobechat/business-const';
|
|
2
|
-
import { Button, Flexbox, Icon, Input, Skeleton, Text } from '@lobehub/ui';
|
|
2
|
+
import { Alert, Button, Flexbox, Icon, Input, Skeleton, Text } from '@lobehub/ui';
|
|
3
3
|
import { Divider, Form } from 'antd';
|
|
4
4
|
import type { FormInstance, InputRef } from 'antd';
|
|
5
|
+
import { createStaticStyles } from 'antd-style';
|
|
5
6
|
import { ChevronRight, Mail } from 'lucide-react';
|
|
6
7
|
import { useEffect, useRef } from 'react';
|
|
7
8
|
import { Trans, useTranslation } from 'react-i18next';
|
|
@@ -11,14 +12,24 @@ import { PRIVACY_URL, TERMS_URL } from '@/const/url';
|
|
|
11
12
|
|
|
12
13
|
import AuthCard from '../../../../features/AuthCard';
|
|
13
14
|
|
|
15
|
+
const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
16
|
+
setPasswordLink: css`
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
color: ${cssVar.colorPrimary};
|
|
19
|
+
text-decoration: underline;
|
|
20
|
+
`,
|
|
21
|
+
}));
|
|
22
|
+
|
|
14
23
|
export const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
15
24
|
export const USERNAME_REGEX = /^\w+$/;
|
|
16
25
|
|
|
17
26
|
export interface SignInEmailStepProps {
|
|
18
27
|
form: FormInstance<{ email: string }>;
|
|
28
|
+
isSocialOnly: boolean;
|
|
19
29
|
loading: boolean;
|
|
20
30
|
oAuthSSOProviders: string[];
|
|
21
31
|
onCheckUser: (values: { email: string }) => Promise<void>;
|
|
32
|
+
onSetPassword: () => void;
|
|
22
33
|
onSocialSignIn: (provider: string) => void;
|
|
23
34
|
serverConfigInit: boolean;
|
|
24
35
|
socialLoading: string | null;
|
|
@@ -26,11 +37,13 @@ export interface SignInEmailStepProps {
|
|
|
26
37
|
|
|
27
38
|
export const SignInEmailStep = ({
|
|
28
39
|
form,
|
|
40
|
+
isSocialOnly,
|
|
29
41
|
loading,
|
|
30
42
|
oAuthSSOProviders,
|
|
31
43
|
serverConfigInit,
|
|
32
44
|
socialLoading,
|
|
33
45
|
onCheckUser,
|
|
46
|
+
onSetPassword,
|
|
34
47
|
onSocialSignIn,
|
|
35
48
|
}: SignInEmailStepProps) => {
|
|
36
49
|
const { t } = useTranslation('auth');
|
|
@@ -88,7 +101,7 @@ export const SignInEmailStep = ({
|
|
|
88
101
|
<AuthCard
|
|
89
102
|
footer={footer}
|
|
90
103
|
subtitle={t('signin.subtitle', { appName: BRANDING_NAME })}
|
|
91
|
-
title={
|
|
104
|
+
title={'Agent teams that grow with you'}
|
|
92
105
|
>
|
|
93
106
|
{!serverConfigInit && (
|
|
94
107
|
<Flexbox gap={12}>
|
|
@@ -172,6 +185,21 @@ export const SignInEmailStep = ({
|
|
|
172
185
|
/>
|
|
173
186
|
</Form.Item>
|
|
174
187
|
</Form>
|
|
188
|
+
{isSocialOnly && (
|
|
189
|
+
<Alert
|
|
190
|
+
description={
|
|
191
|
+
<>
|
|
192
|
+
{t('betterAuth.signin.socialOnlyHint')}{' '}
|
|
193
|
+
<a className={styles.setPasswordLink} onClick={onSetPassword}>
|
|
194
|
+
{t('betterAuth.signin.setPassword')}
|
|
195
|
+
</a>
|
|
196
|
+
</>
|
|
197
|
+
}
|
|
198
|
+
showIcon
|
|
199
|
+
style={{ marginTop: 12 }}
|
|
200
|
+
type="info"
|
|
201
|
+
/>
|
|
202
|
+
)}
|
|
175
203
|
</AuthCard>
|
|
176
204
|
);
|
|
177
205
|
};
|
|
@@ -17,6 +17,7 @@ const SignInPage = () => {
|
|
|
17
17
|
handleForgotPassword,
|
|
18
18
|
handleSignIn,
|
|
19
19
|
handleSocialSignIn,
|
|
20
|
+
isSocialOnly,
|
|
20
21
|
loading,
|
|
21
22
|
oAuthSSOProviders,
|
|
22
23
|
serverConfigInit,
|
|
@@ -29,9 +30,11 @@ const SignInPage = () => {
|
|
|
29
30
|
{step === 'email' ? (
|
|
30
31
|
<SignInEmailStep
|
|
31
32
|
form={form as any}
|
|
33
|
+
isSocialOnly={isSocialOnly}
|
|
32
34
|
loading={loading}
|
|
33
35
|
oAuthSSOProviders={oAuthSSOProviders}
|
|
34
36
|
onCheckUser={handleCheckUser}
|
|
37
|
+
onSetPassword={handleForgotPassword}
|
|
35
38
|
onSocialSignIn={handleSocialSignIn}
|
|
36
39
|
serverConfigInit={serverConfigInit}
|
|
37
40
|
socialLoading={socialLoading}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ENABLE_BUSINESS_FEATURES } from '@lobechat/business-const';
|
|
2
2
|
import { Form } from 'antd';
|
|
3
|
-
import { useRouter, useSearchParams } from '@/libs/next/navigation';
|
|
4
3
|
import { useEffect, useState } from 'react';
|
|
5
4
|
import { useTranslation } from 'react-i18next';
|
|
6
5
|
|
|
@@ -10,6 +9,7 @@ import { useBusinessSignin } from '@/business/client/hooks/useBusinessSignin';
|
|
|
10
9
|
import { message } from '@/components/AntdStaticMethods';
|
|
11
10
|
import { requestPasswordReset, signIn } from '@/libs/better-auth/auth-client';
|
|
12
11
|
import { isBuiltinProvider, normalizeProviderId } from '@/libs/better-auth/utils/client';
|
|
12
|
+
import { useRouter, useSearchParams } from '@/libs/next/navigation';
|
|
13
13
|
import { useServerConfigStore } from '@/store/serverConfig';
|
|
14
14
|
import { serverConfigSelectors } from '@/store/serverConfig/selectors';
|
|
15
15
|
|
|
@@ -37,6 +37,7 @@ export const useSignIn = () => {
|
|
|
37
37
|
const [socialLoading, setSocialLoading] = useState<string | null>(null);
|
|
38
38
|
const [step, setStep] = useState<Step>('email');
|
|
39
39
|
const [email, setEmail] = useState('');
|
|
40
|
+
const [isSocialOnly, setIsSocialOnly] = useState(false);
|
|
40
41
|
const serverConfigInit = useServerConfigStore((s) => s.serverConfigInit);
|
|
41
42
|
const oAuthSSOProviders = useServerConfigStore((s) => s.serverConfig.oAuthSSOProviders) || [];
|
|
42
43
|
const { ssoProviders, preSocialSigninCheck, getAdditionalData } = useBusinessSignin();
|
|
@@ -142,7 +143,8 @@ export const useSignIn = () => {
|
|
|
142
143
|
return;
|
|
143
144
|
}
|
|
144
145
|
|
|
145
|
-
|
|
146
|
+
// User has no password and magic link is disabled, they can only sign in via social
|
|
147
|
+
setIsSocialOnly(true);
|
|
146
148
|
} catch (error) {
|
|
147
149
|
console.error('Error checking user:', error);
|
|
148
150
|
message.error(t('betterAuth.signin.error'));
|
|
@@ -215,6 +217,7 @@ export const useSignIn = () => {
|
|
|
215
217
|
const handleBackToEmail = () => {
|
|
216
218
|
setStep('email');
|
|
217
219
|
setEmail('');
|
|
220
|
+
setIsSocialOnly(false);
|
|
218
221
|
};
|
|
219
222
|
|
|
220
223
|
const handleGoToSignup = () => {
|
|
@@ -247,6 +250,7 @@ export const useSignIn = () => {
|
|
|
247
250
|
handleGoToSignup,
|
|
248
251
|
handleSignIn,
|
|
249
252
|
handleSocialSignIn,
|
|
253
|
+
isSocialOnly,
|
|
250
254
|
loading,
|
|
251
255
|
oAuthSSOProviders: ENABLE_BUSINESS_FEATURES ? ssoProviders : oAuthSSOProviders,
|
|
252
256
|
serverConfigInit: ENABLE_BUSINESS_FEATURES ? true : serverConfigInit,
|
|
@@ -40,7 +40,7 @@ const RecentResourceItem = memo<RecentResourceItemProps>(({ file }) => {
|
|
|
40
40
|
>
|
|
41
41
|
<Center
|
|
42
42
|
flex={'none'}
|
|
43
|
-
height={
|
|
43
|
+
height={148}
|
|
44
44
|
style={{ background: cssVar.colorFillTertiary, overflow: 'hidden' }}
|
|
45
45
|
>
|
|
46
46
|
{isImage && file.url ? (
|
|
@@ -63,7 +63,7 @@ const RecentResourceItem = memo<RecentResourceItemProps>(({ file }) => {
|
|
|
63
63
|
|
|
64
64
|
{/* File Info */}
|
|
65
65
|
<Flexbox flex={1} gap={6} justify={'space-between'} padding={12}>
|
|
66
|
-
<Text ellipsis
|
|
66
|
+
<Text ellipsis fontSize={13} style={{ lineHeight: 1.4 }} weight={500}>
|
|
67
67
|
{file.name}
|
|
68
68
|
</Text>
|
|
69
69
|
<Flexbox align={'center'} gap={8} horizontal>
|
|
@@ -8,7 +8,6 @@ import { useUserStore } from '@/store/user';
|
|
|
8
8
|
import { authSelectors } from '@/store/user/slices/auth/selectors';
|
|
9
9
|
|
|
10
10
|
import CommunityAgents from './CommunityAgents';
|
|
11
|
-
import FeaturedPlugins from './FeaturedPlugins';
|
|
12
11
|
import InputArea from './InputArea';
|
|
13
12
|
import RecentPage from './RecentPage';
|
|
14
13
|
import RecentResource from './RecentResource';
|
|
@@ -32,7 +31,7 @@ const Home = memo(() => {
|
|
|
32
31
|
</>
|
|
33
32
|
)}
|
|
34
33
|
<CommunityAgents />
|
|
35
|
-
|
|
34
|
+
{/*<FeaturedPlugins />*/}
|
|
36
35
|
{isLogin && <RecentResource />}
|
|
37
36
|
</Flexbox>
|
|
38
37
|
);
|
|
@@ -62,8 +62,6 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
|
62
62
|
form: css`
|
|
63
63
|
.${prefixCls}-form-item-control:has(.${prefixCls}-input,.${prefixCls}-select) {
|
|
64
64
|
flex: none;
|
|
65
|
-
width: min(70%, 800px);
|
|
66
|
-
min-width: min(70%, 800px) !important;
|
|
67
65
|
}
|
|
68
66
|
${responsive.sm} {
|
|
69
67
|
width: 100%;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { App } from 'antd';
|
|
3
|
-
import {
|
|
1
|
+
import { Button, DropdownMenu, Flexbox, Icon } from '@lobehub/ui';
|
|
2
|
+
import { App, Space } from 'antd';
|
|
3
|
+
import { MoreHorizontalIcon, Trash2 } from 'lucide-react';
|
|
4
4
|
import { memo, useState } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
7
|
import McpSettingsModal from '@/features/MCP/MCPSettings/McpSettingsModal';
|
|
8
8
|
import PluginDetailModal from '@/features/PluginDetailModal';
|
|
9
|
-
import EditCustomPlugin from './EditCustomPlugin';
|
|
10
9
|
import { useAgentStore } from '@/store/agent';
|
|
11
10
|
import { agentSelectors } from '@/store/agent/selectors';
|
|
12
11
|
import { useServerConfigStore } from '@/store/serverConfig';
|
|
@@ -14,6 +13,8 @@ import { pluginHelpers, useToolStore } from '@/store/tool';
|
|
|
14
13
|
import { pluginSelectors, pluginStoreSelectors } from '@/store/tool/selectors';
|
|
15
14
|
import { type LobeToolType } from '@/types/tool/tool';
|
|
16
15
|
|
|
16
|
+
import EditCustomPlugin from './EditCustomPlugin';
|
|
17
|
+
|
|
17
18
|
interface ActionsProps {
|
|
18
19
|
identifier: string;
|
|
19
20
|
isMCP?: boolean;
|
|
@@ -73,7 +74,7 @@ const Actions = memo<ActionsProps>(({ identifier, type, isMCP }) => {
|
|
|
73
74
|
<>
|
|
74
75
|
<Flexbox align={'center'} gap={8} horizontal onClick={(e) => e.stopPropagation()}>
|
|
75
76
|
{installed ? (
|
|
76
|
-
|
|
77
|
+
<Space.Compact>
|
|
77
78
|
{showConfigureButton &&
|
|
78
79
|
(isCustomPlugin ? (
|
|
79
80
|
<EditCustomPlugin identifier={identifier} onOpenChange={setModal} open={showModal}>
|
|
@@ -108,9 +109,9 @@ const Actions = memo<ActionsProps>(({ identifier, type, isMCP }) => {
|
|
|
108
109
|
]}
|
|
109
110
|
placement="bottomRight"
|
|
110
111
|
>
|
|
111
|
-
<
|
|
112
|
+
<Button icon={MoreHorizontalIcon} loading={installing} />
|
|
112
113
|
</DropdownMenu>
|
|
113
|
-
|
|
114
|
+
</Space.Compact>
|
|
114
115
|
) : (
|
|
115
116
|
<Button
|
|
116
117
|
loading={installing}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { Flexbox, Modal } from '@lobehub/ui';
|
|
3
|
+
import { Block, Flexbox, Modal } from '@lobehub/ui';
|
|
4
4
|
import { createStyles } from 'antd-style';
|
|
5
5
|
import { memo, useState } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
|
|
8
8
|
import PluginAvatar from '@/components/Plugins/PluginAvatar';
|
|
9
9
|
import PluginTag from '@/components/Plugins/PluginTag';
|
|
10
|
-
import PluginDetailModal from '@/features/PluginDetailModal';
|
|
11
|
-
import Actions from './Actions';
|
|
12
10
|
import McpDetail from '@/features/MCP/MCPDetail';
|
|
11
|
+
import PluginDetailModal from '@/features/PluginDetailModal';
|
|
13
12
|
import { useToolStore } from '@/store/tool';
|
|
14
13
|
import { pluginSelectors } from '@/store/tool/selectors';
|
|
15
14
|
import { type LobeToolType } from '@/types/tool/tool';
|
|
16
15
|
|
|
16
|
+
import Actions from './Actions';
|
|
17
|
+
|
|
17
18
|
const useStyles = createStyles(({ css, token }) => ({
|
|
18
19
|
container: css`
|
|
19
20
|
padding-block: 12px;
|
|
@@ -25,11 +26,8 @@ const useStyles = createStyles(({ css, token }) => ({
|
|
|
25
26
|
align-items: center;
|
|
26
27
|
justify-content: center;
|
|
27
28
|
|
|
28
|
-
width:
|
|
29
|
-
height:
|
|
30
|
-
border-radius: 12px;
|
|
31
|
-
|
|
32
|
-
background: ${token.colorFillTertiary};
|
|
29
|
+
width: 40px;
|
|
30
|
+
height: 40px;
|
|
33
31
|
`,
|
|
34
32
|
title: css`
|
|
35
33
|
cursor: pointer;
|
|
@@ -72,10 +70,10 @@ const McpSkillItem = memo<McpSkillItemProps>(
|
|
|
72
70
|
horizontal
|
|
73
71
|
justify="space-between"
|
|
74
72
|
>
|
|
75
|
-
<Flexbox align="center" gap={
|
|
76
|
-
<
|
|
73
|
+
<Flexbox align="center" gap={12} horizontal style={{ flex: 1, overflow: 'hidden' }}>
|
|
74
|
+
<Block className={styles.icon} variant={'outlined'}>
|
|
77
75
|
<PluginAvatar avatar={avatar} size={32} />
|
|
78
|
-
</
|
|
76
|
+
</Block>
|
|
79
77
|
<Flexbox align="center" gap={8} horizontal style={{ overflow: 'hidden' }}>
|
|
80
78
|
<span className={styles.title} onClick={() => setDetailOpen(true)}>
|
|
81
79
|
{title}
|
package/src/app/manifest.ts
CHANGED
|
@@ -5,7 +5,7 @@ const manifest = async (): Promise<MetadataRoute.Manifest> => {
|
|
|
5
5
|
if (process.env.NODE_ENV === 'development') {
|
|
6
6
|
return {
|
|
7
7
|
background_color: '#000000',
|
|
8
|
-
description: '
|
|
8
|
+
description: 'LobeHub Development',
|
|
9
9
|
display: 'standalone',
|
|
10
10
|
icons: [
|
|
11
11
|
{
|
|
@@ -14,8 +14,8 @@ const manifest = async (): Promise<MetadataRoute.Manifest> => {
|
|
|
14
14
|
type: 'image/png',
|
|
15
15
|
},
|
|
16
16
|
],
|
|
17
|
-
name: '
|
|
18
|
-
short_name: '
|
|
17
|
+
name: 'LobeHub',
|
|
18
|
+
short_name: 'LobeHub',
|
|
19
19
|
start_url: '/',
|
|
20
20
|
theme_color: '#000000',
|
|
21
21
|
};
|
|
@@ -30,7 +30,7 @@ const manifest = async (): Promise<MetadataRoute.Manifest> => {
|
|
|
30
30
|
|
|
31
31
|
// @ts-expect-error - manifestModule.generate returns extended manifest with custom properties
|
|
32
32
|
return manifestModule.generate({
|
|
33
|
-
description: `${BRANDING_NAME}
|
|
33
|
+
description: `${BRANDING_NAME} is a work-and-lifestyle space to find, build, and collaborate with agent teams that grow with you.`,
|
|
34
34
|
icons: [
|
|
35
35
|
{
|
|
36
36
|
purpose: 'any',
|
|
@@ -11,7 +11,7 @@ export interface AuthCardProps extends Omit<FlexboxProps, 'title'> {
|
|
|
11
11
|
|
|
12
12
|
export const AuthCard = memo<AuthCardProps>(({ children, title, subtitle, footer, ...rest }) => {
|
|
13
13
|
return (
|
|
14
|
-
<Flexbox width={'min(100%,
|
|
14
|
+
<Flexbox width={'min(100%,440px)'} {...rest}>
|
|
15
15
|
<Flexbox gap={16}>
|
|
16
16
|
{title && (
|
|
17
17
|
<Text fontSize={28} style={{ lineHeight: 1.4 }} weight={'bold'}>
|
|
@@ -8,8 +8,8 @@ import React, { memo, useState } from 'react';
|
|
|
8
8
|
import { useTranslation } from 'react-i18next';
|
|
9
9
|
|
|
10
10
|
import PluginAvatar from '@/components/Plugins/PluginAvatar';
|
|
11
|
-
import MCPInstallProgress from '@/features/MCP/MCPInstallProgress';
|
|
12
11
|
import McpDetail from '@/features/MCP/MCPDetail';
|
|
12
|
+
import MCPInstallProgress from '@/features/MCP/MCPInstallProgress';
|
|
13
13
|
import { useMarketAuth } from '@/layout/AuthProvider/MarketAuth';
|
|
14
14
|
import { useAgentStore } from '@/store/agent';
|
|
15
15
|
import { agentSelectors } from '@/store/agent/selectors';
|
|
@@ -117,13 +117,14 @@ const Item = memo<DiscoverMcpItem>(({ name, description, icon, identifier }) =>
|
|
|
117
117
|
<Flexbox className={styles.container} gap={0}>
|
|
118
118
|
<Block
|
|
119
119
|
align={'center'}
|
|
120
|
+
clickable
|
|
120
121
|
gap={12}
|
|
121
122
|
horizontal
|
|
122
123
|
onClick={() => setDetailOpen(true)}
|
|
123
124
|
paddingBlock={12}
|
|
124
125
|
paddingInline={12}
|
|
125
126
|
style={{ cursor: 'pointer' }}
|
|
126
|
-
variant={'
|
|
127
|
+
variant={'outlined'}
|
|
127
128
|
>
|
|
128
129
|
<PluginAvatar avatar={icon} size={40} />
|
|
129
130
|
<Flexbox flex={1} gap={4} style={{ minWidth: 0, overflow: 'hidden' }}>
|
|
@@ -97,10 +97,11 @@ export default {
|
|
|
97
97
|
'betterAuth.signin.orContinueWith': 'OR',
|
|
98
98
|
'betterAuth.signin.passwordPlaceholder': 'Enter your password',
|
|
99
99
|
'betterAuth.signin.passwordStep.subtitle': 'Enter your password to continue',
|
|
100
|
+
'betterAuth.signin.setPassword': 'set a password',
|
|
100
101
|
'betterAuth.signin.signupLink': 'Sign up now',
|
|
101
102
|
'betterAuth.signin.socialError': 'Social sign in failed, please try again',
|
|
102
103
|
'betterAuth.signin.socialOnlyHint':
|
|
103
|
-
'This email was registered
|
|
104
|
+
'This email was registered via a third-party social account. Sign in with that provider, or',
|
|
104
105
|
'betterAuth.signin.submit': 'Sign In',
|
|
105
106
|
'betterAuth.signup.confirmPasswordPlaceholder': 'Confirm your password',
|
|
106
107
|
'betterAuth.signup.emailPlaceholder': 'Enter your email address',
|
|
@@ -200,7 +201,7 @@ export default {
|
|
|
200
201
|
'profile.usernameRule': 'Username can only contain letters, numbers, or underscores',
|
|
201
202
|
'profile.usernameUpdateFailed': 'Failed to update username, please try again later',
|
|
202
203
|
'signin.subtitle': 'Sign up or log in to your {{appName}} account',
|
|
203
|
-
'signin.title': '
|
|
204
|
+
'signin.title': 'Agent teams that grow with you',
|
|
204
205
|
'signout': 'Log Out',
|
|
205
206
|
'signup': 'Sign Up',
|
|
206
207
|
'stats.aiheatmaps': 'Activity Index',
|