@allbluecn/admin-app 0.3.4 → 0.3.6
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/package.json +15 -15
- package/src/components/__tests__/user-avatar.test.tsx +39 -0
- package/src/components/admin/admin-user-menu.tsx +6 -6
- package/src/components/admin/developer-log.tsx +7 -7
- package/src/components/ai-memory/memory-facts-panel.tsx +9 -9
- package/src/components/ai-prompts/preview-panel.tsx +1 -1
- package/src/components/ai-prompts/prompt-editor.tsx +8 -8
- package/src/components/ai-prompts/prompt-table.tsx +6 -6
- package/src/components/ai-prompts/section-editor.tsx +3 -3
- package/src/components/ai-prompts/variable-panel.tsx +2 -2
- package/src/components/ai-prompts/version-history.tsx +5 -5
- package/src/components/ai-provider/model-list-editor.tsx +2 -2
- package/src/components/ai-provider/provider-form.tsx +7 -7
- package/src/components/ai-provider/provider-table.tsx +6 -6
- package/src/components/auth/admin-login-form.tsx +8 -8
- package/src/components/auth/icon-input.tsx +2 -2
- package/src/components/auth/password-input.tsx +2 -2
- package/src/components/component/component-form-dialog.tsx +8 -8
- package/src/components/component/component-import-dialog.tsx +6 -6
- package/src/components/component/component-table.tsx +3 -3
- package/{allblue-ui/src → src}/components/confirm-dialog.tsx +2 -2
- package/src/components/dependency/changelog-dialog.tsx +2 -2
- package/src/components/dependency/columns.tsx +3 -3
- package/src/components/dependency/dependency-table.tsx +7 -7
- package/src/components/dependency/edit-dialog.tsx +8 -8
- package/src/components/invitations/invitations-page.tsx +13 -13
- package/src/components/{knowledge-public → knowledge/public}/bookmark-form-dialog.tsx +10 -10
- package/src/components/{knowledge-public → knowledge/public}/compliance-form-dialog.tsx +10 -10
- package/src/components/{knowledge-public → knowledge/public}/legal-form-dialog.tsx +11 -11
- package/src/components/layout/sidebar-02/app-sidebar.tsx +1 -1
- package/src/components/layout/sidebar-02/index.tsx +1 -1
- package/src/components/layout/sidebar-02/nav-main.tsx +2 -2
- package/src/components/layout/sidebar-02/nav-notifications.tsx +3 -3
- package/src/components/market/columns.tsx +4 -4
- package/src/components/market/market-app-form.tsx +6 -6
- package/src/components/market/market-app-list.tsx +4 -4
- package/src/components/monitoring/error-list.tsx +1 -1
- package/src/components/monitoring/metrics-stats.tsx +1 -1
- package/src/components/monitoring/request-log-table.tsx +1 -1
- package/src/components/oauth-providers/provider-page.tsx +9 -9
- package/src/components/permissions/assign-dialog.tsx +5 -5
- package/src/components/permissions/create-role-dialog.tsx +6 -6
- package/{allblue-ui/src → src/components}/ui/checkbox.tsx +4 -4
- package/{allblue-ui/src → src/components}/ui/sidebar.tsx +1 -1
- package/src/components/user/columns.tsx +5 -5
- package/src/components/user/settings-activity-log.tsx +7 -7
- package/src/components/user/settings-profile/avatar-uploader.tsx +2 -2
- package/src/components/user/settings-profile/social-links.tsx +2 -2
- package/src/components/user/settings-profile.tsx +6 -6
- package/src/components/user/user-create-dialog.tsx +6 -6
- package/src/components/user/user-detail/error-boundary.tsx +1 -1
- package/src/components/user/user-detail/user-detail-dialogs.tsx +6 -6
- package/src/components/user/user-filters.tsx +3 -3
- package/{allblue-ui/src → src}/components/user-avatar.tsx +7 -4
- package/src/lib/__tests__/avatar-shape.test.ts +44 -0
- package/src/lib/auth.config.ts +1 -1
- package/{allblue-ui/src/lib/avatar.ts → src/lib/avatar-shape.ts} +15 -21
- package/src/providers/index.tsx +1 -1
- package/src/routes/__root.tsx +1 -1
- package/src/routes/_nav/audit/route.lazy.tsx +1 -1
- package/src/routes/_nav/compliance/route.lazy.tsx +3 -3
- package/src/routes/_nav/components/route.lazy.tsx +4 -4
- package/src/routes/_nav/knowledge-public/bookmarks/route.lazy.tsx +16 -16
- package/src/routes/_nav/knowledge-public/bookmarks/route.tsx +1 -1
- package/src/routes/_nav/knowledge-public/compliance/route.lazy.tsx +14 -14
- package/src/routes/_nav/knowledge-public/compliance/route.tsx +1 -1
- package/src/routes/_nav/knowledge-public/legal/route.lazy.tsx +14 -14
- package/src/routes/_nav/knowledge-public/legal/route.tsx +1 -1
- package/src/routes/_nav/licenses/$licenseId/route.lazy.tsx +3 -3
- package/src/routes/_nav/licenses/new/route.lazy.tsx +5 -5
- package/src/routes/_nav/licenses/route.lazy.tsx +1 -1
- package/src/routes/_nav/monitoring/ai-usage/route.lazy.tsx +2 -2
- package/src/routes/_nav/monitoring/errors/route.lazy.tsx +1 -1
- package/src/routes/_nav/monitoring/health/route.lazy.tsx +3 -3
- package/src/routes/_nav/monitoring/logs/route.lazy.tsx +3 -3
- package/src/routes/_nav/monitoring/metrics/route.lazy.tsx +3 -3
- package/src/routes/_nav/monitoring/route.lazy.tsx +2 -2
- package/src/routes/_nav/monitoring/sentry/route.lazy.tsx +1 -1
- package/src/routes/_nav/permissions/route.lazy.tsx +4 -4
- package/src/routes/_nav/sso/route.lazy.tsx +2 -2
- package/src/routes/_nav/users/$userId/route.lazy.tsx +9 -9
- package/src/routes/_nav/users/-components/users-table.tsx +1 -1
- package/src/routes/_nav/users/route.lazy.tsx +1 -1
- package/src/routes/login/route.lazy.tsx +1 -1
- package/src/routes/setup/route.lazy.tsx +2 -2
- package/src/server/dependency/helpers.ts +0 -1
- package/src/server/{knowledge-public → knowledge/public}/github-sync.ts +12 -2
- package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/create.ts +1 -1
- package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/list.ts +2 -1
- package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/sync-all-github.ts +3 -2
- package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/update.ts +3 -2
- package/src/server/serverFns/{knowledge-public → knowledge/public}/compliance/create.ts +1 -1
- package/src/server/serverFns/{knowledge-public → knowledge/public}/compliance/list.ts +2 -1
- package/src/server/serverFns/{knowledge-public → knowledge/public}/compliance/update.ts +3 -2
- package/src/server/serverFns/{knowledge-public → knowledge/public}/legal/create.ts +1 -1
- package/src/server/serverFns/{knowledge-public → knowledge/public}/legal/list.ts +2 -1
- package/src/server/serverFns/{knowledge-public → knowledge/public}/legal/update.ts +3 -2
- package/src/styles/globals.css +3 -3
- package/allblue-ui/package.json +0 -6
- package/allblue-ui/src/components/infinite-scroll-sentinel.tsx +0 -37
- package/allblue-ui/src/hooks/use-load-more.ts +0 -57
- package/allblue-ui/src/index.ts +0 -31
- package/allblue-ui/src/lib/utils.ts +0 -1
- /package/{allblue-ui/src → src/components}/data-table/data-table-pagination.tsx +0 -0
- /package/{allblue-ui/src → src/components}/data-table/data-table.tsx +0 -0
- /package/{allblue-ui/src → src/components}/data-table/table-detail-layout.tsx +0 -0
- /package/{allblue-ui/src → src}/components/notion-avatar.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/alert-dialog.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/alert.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/avatar.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/badge.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/button.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/card.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/collapsible.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/dialog.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/dropdown-menu.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/field.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/input-group.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/input.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/label.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/pagination.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/select.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/separator.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/sheet.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/skeleton.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/switch.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/table.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/textarea.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/toast.tsx +0 -0
- /package/{allblue-ui/src → src/components}/ui/tooltip.tsx +0 -0
- /package/{allblue-ui/src → src}/hooks/use-mobile.ts +0 -0
- /package/{allblue-ui/src → src}/lib/datetime.ts +0 -0
- /package/{allblue-ui/src → src}/lib/sanitize.ts +0 -0
- /package/src/server/{knowledge-public → knowledge/public}/canonical-id.ts +0 -0
- /package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/delete.ts +0 -0
- /package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/detail.ts +0 -0
- /package/src/server/serverFns/{knowledge-public → knowledge/public}/compliance/delete.ts +0 -0
- /package/src/server/serverFns/{knowledge-public → knowledge/public}/compliance/detail.ts +0 -0
- /package/src/server/serverFns/{knowledge-public → knowledge/public}/legal/delete.ts +0 -0
- /package/src/server/serverFns/{knowledge-public → knowledge/public}/legal/detail.ts +0 -0
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
import { createLazyFileRoute } from '@tanstack/react-router'
|
|
19
19
|
import { m } from '@/paraglide/messages.js'
|
|
20
20
|
import { useState, useEffect, useRef } from 'react'
|
|
21
|
-
import { formatTimestamp } from '
|
|
21
|
+
import { formatTimestamp } from '@/lib/datetime'
|
|
22
22
|
import { HeartPulse, Play, Square, RefreshCw } from 'lucide-react'
|
|
23
23
|
import { PageHeader } from '@/components/common/page-header'
|
|
24
24
|
import { HealthCards } from '@/components/monitoring/health-cards'
|
|
25
|
-
import { DataTable } from '
|
|
25
|
+
import { DataTable } from '@/components/data-table/data-table'
|
|
26
26
|
import { getHealthStatus } from '@/server/serverFns/monitoring/get-health'
|
|
27
27
|
import { getHealthCheckSettings, updateHealthCheckSettings } from '@/server/serverFns/monitoring/get-health-settings'
|
|
28
|
-
import { toast } from '
|
|
28
|
+
import { toast } from '@/components/ui/toast'
|
|
29
29
|
import { jsonify } from '@/lib/loader-serial'
|
|
30
30
|
|
|
31
31
|
export const Route = createLazyFileRoute('/_nav/monitoring/health')({
|
|
@@ -21,11 +21,11 @@ import { useState, useEffect, useRef } from 'react'
|
|
|
21
21
|
import { Activity, Filter, RefreshCw, Trash2 } from 'lucide-react'
|
|
22
22
|
import { PageHeader } from '@/components/common/page-header'
|
|
23
23
|
import { RequestLogTable } from '@/components/monitoring/request-log-table'
|
|
24
|
-
import { Checkbox } from '
|
|
24
|
+
import { Checkbox } from '@/components/ui/checkbox'
|
|
25
25
|
import { getRequestLogs } from '@/server/serverFns/monitoring/get-request-logs'
|
|
26
26
|
import { resetMonitoring } from '@/server/serverFns/monitoring/reset'
|
|
27
|
-
import { DataTablePagination } from '
|
|
28
|
-
import { toast } from '
|
|
27
|
+
import { DataTablePagination } from '@/components/data-table/data-table-pagination'
|
|
28
|
+
import { toast } from '@/components/ui/toast'
|
|
29
29
|
import { jsonify } from '@/lib/loader-serial'
|
|
30
30
|
import { RequestLogEntry } from '@/components/monitoring/request-log-table'
|
|
31
31
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import { m } from '@/paraglide/messages.js'
|
|
19
19
|
import { getBenchmark, getBenchmarkSource, compareDuration } from '@/lib/monitoring-benchmarks'
|
|
20
|
-
import { formatTimestamp } from '
|
|
20
|
+
import { formatTimestamp } from '@/lib/datetime'
|
|
21
21
|
import { createLazyFileRoute } from '@tanstack/react-router'
|
|
22
22
|
import { useState } from 'react'
|
|
23
23
|
import { BarChart3, RefreshCw, Trash2, MemoryStick } from 'lucide-react'
|
|
@@ -27,8 +27,8 @@ import { MetricsStats } from '@/components/monitoring/metrics-stats'
|
|
|
27
27
|
import { getMetrics } from '@/server/serverFns/monitoring/get-metrics'
|
|
28
28
|
import { resetMonitoring } from '@/server/serverFns/monitoring/reset'
|
|
29
29
|
import { jsonify } from '@/lib/loader-serial'
|
|
30
|
-
import { DataTable } from '
|
|
31
|
-
import { toast } from '
|
|
30
|
+
import { DataTable } from '@/components/data-table/data-table'
|
|
31
|
+
import { toast } from '@/components/ui/toast'
|
|
32
32
|
|
|
33
33
|
export const Route = createLazyFileRoute('/_nav/monitoring/metrics')({
|
|
34
34
|
component: MonitoringMetrics,
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
import { createLazyFileRoute, Link, Outlet, useLocation } from '@tanstack/react-router'
|
|
19
19
|
import { m } from '@/paraglide/messages.js'
|
|
20
|
-
import { SidebarTrigger } from '
|
|
21
|
-
import { Separator } from '
|
|
20
|
+
import { SidebarTrigger } from '@/components/ui/sidebar'
|
|
21
|
+
import { Separator } from '@/components/ui/separator'
|
|
22
22
|
|
|
23
23
|
export const Route = createLazyFileRoute('/_nav/monitoring')({
|
|
24
24
|
component: MonitoringLayout,
|
|
@@ -21,7 +21,7 @@ import * as Sentry from '@sentry/tanstackstart-react'
|
|
|
21
21
|
import { BugPlay, ExternalLink, Bug, Activity, Eye, EyeOff, Save, CheckCircle2, XCircle, RefreshCw, ShieldCheck } from 'lucide-react'
|
|
22
22
|
import { IconBrandSentry } from '@tabler/icons-react';
|
|
23
23
|
import { useEffect, useState } from 'react'
|
|
24
|
-
import { toast } from '
|
|
24
|
+
import { toast } from '@/components/ui/toast'
|
|
25
25
|
import { getSentryConfig, saveSentryConfig, reconfigureSentryServer } from '@/server/serverFns/sentry/config'
|
|
26
26
|
import type { SentryConfig } from '@/server/serverFns/sentry/config'
|
|
27
27
|
|
|
@@ -2,15 +2,15 @@ import { createLazyFileRoute, Link, useLocation } from '@tanstack/react-router'
|
|
|
2
2
|
import { m } from '@/paraglide/messages.js'
|
|
3
3
|
import { getLocale } from '@/paraglide/runtime.js'
|
|
4
4
|
import { useServerFn } from '@tanstack/react-start'
|
|
5
|
-
import { toast } from '
|
|
5
|
+
import { toast } from '@/components/ui/toast'
|
|
6
6
|
import { useEffect, useState } from 'react'
|
|
7
7
|
import type React from 'react'
|
|
8
8
|
import {
|
|
9
9
|
listRolesFn,
|
|
10
10
|
deleteRoleFn,
|
|
11
11
|
} from '@/server/serverFns/permissions'
|
|
12
|
-
import { Badge } from '
|
|
13
|
-
import { Button } from '
|
|
12
|
+
import { Badge } from '@/components/ui/badge'
|
|
13
|
+
import { Button } from '@/components/ui/button'
|
|
14
14
|
import {
|
|
15
15
|
Table,
|
|
16
16
|
TableBody,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
TableHead,
|
|
19
19
|
TableHeader,
|
|
20
20
|
TableRow,
|
|
21
|
-
} from '
|
|
21
|
+
} from '@/components/ui/table'
|
|
22
22
|
import { CreateRoleDialog } from '@/components/permissions/create-role-dialog'
|
|
23
23
|
import { AssignDialog } from '@/components/permissions/assign-dialog'
|
|
24
24
|
import type { RoleItem } from '@/components/permissions/types'
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
import { createLazyFileRoute } from '@tanstack/react-router'
|
|
19
19
|
import { m } from '@/paraglide/messages.js'
|
|
20
20
|
import { useServerFn } from '@tanstack/react-start'
|
|
21
|
-
import { toast } from '
|
|
21
|
+
import { toast } from '@/components/ui/toast'
|
|
22
22
|
import type React from 'react'
|
|
23
23
|
import { deleteSsoProviderFn, toggleSsoProviderFn } from '@/server/serverFns/sso-config'
|
|
24
|
-
import { Badge } from '
|
|
24
|
+
import { Badge } from '@/components/ui/badge'
|
|
25
25
|
|
|
26
26
|
export const Route = createLazyFileRoute('/_nav/sso')({
|
|
27
27
|
pendingComponent: () => (
|
|
@@ -18,17 +18,17 @@
|
|
|
18
18
|
import { createLazyFileRoute, useNavigate } from '@tanstack/react-router'
|
|
19
19
|
import { m } from '@/paraglide/messages.js'
|
|
20
20
|
import { useState, useTransition } from 'react'
|
|
21
|
-
import { formatTimestamp } from '
|
|
21
|
+
import { formatTimestamp } from '@/lib/datetime'
|
|
22
22
|
import { getUserDetailFn } from '@/server/serverFns/user/detail'
|
|
23
23
|
import { updateUserRoleFn } from '@/server/serverFns/user/update-role'
|
|
24
24
|
import { updateUserStatusFn } from '@/server/serverFns/user/update-status'
|
|
25
25
|
import { resetUserPasswordFn } from '@/server/serverFns/user/reset-password'
|
|
26
26
|
import { deleteUserFn } from '@/server/serverFns/user/delete'
|
|
27
|
-
import { TableDetailLayout } from '
|
|
28
|
-
import { Badge } from '
|
|
29
|
-
import { Separator } from '
|
|
30
|
-
import { Button } from '
|
|
31
|
-
import { UserAvatar } from '
|
|
27
|
+
import { TableDetailLayout } from '@/components/data-table/table-detail-layout'
|
|
28
|
+
import { Badge } from '@/components/ui/badge'
|
|
29
|
+
import { Separator } from '@/components/ui/separator'
|
|
30
|
+
import { Button } from '@/components/ui/button'
|
|
31
|
+
import { UserAvatar } from '@/components/user-avatar'
|
|
32
32
|
|
|
33
33
|
const STATUS_LABELS: Record<string, () => string> = {
|
|
34
34
|
active: m['admin-users_status_active'],
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
ShoppingBagIcon,
|
|
49
49
|
ShieldCheckIcon,
|
|
50
50
|
} from 'lucide-react'
|
|
51
|
-
import { toast } from '
|
|
51
|
+
import { toast } from '@/components/ui/toast'
|
|
52
52
|
import { parseUserAgent, formatParsedUA } from '@allbluecn/kernel'
|
|
53
53
|
import type { AvatarConfig } from '@allbluecn/kernel'
|
|
54
54
|
import SettingsActivityLog, {
|
|
@@ -61,7 +61,7 @@ import {
|
|
|
61
61
|
CardDescription,
|
|
62
62
|
CardHeader,
|
|
63
63
|
CardTitle,
|
|
64
|
-
} from '
|
|
64
|
+
} from '@/components/ui/card'
|
|
65
65
|
import { AdminUserErrorBoundary } from '@/components/user/user-detail/error-boundary'
|
|
66
66
|
import {
|
|
67
67
|
UserDeleteDialog,
|
|
@@ -132,7 +132,7 @@ function UserDetailPage() {
|
|
|
132
132
|
avatar={
|
|
133
133
|
<UserAvatar
|
|
134
134
|
avatarConfig={user.avatarConfig as AvatarConfig | null}
|
|
135
|
-
bgShape={user.bgShape
|
|
135
|
+
bgShape={user.bgShape}
|
|
136
136
|
bgColor={user.bgColor}
|
|
137
137
|
name={user.username}
|
|
138
138
|
size="lg"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
import { DataTable } from "
|
|
19
|
+
import { DataTable } from "@/components/data-table/data-table"
|
|
20
20
|
import { getUserColumns } from "@/components/user/columns"
|
|
21
21
|
import type { UserRow } from "@/components/user/columns"
|
|
22
22
|
import { useNavigate } from "@tanstack/react-router"
|
|
@@ -21,7 +21,7 @@ import { useState } from 'react'
|
|
|
21
21
|
import { UsersTable } from './-components/users-table'
|
|
22
22
|
import { UserFilters } from '@/components/user/user-filters'
|
|
23
23
|
import { UserCreateDialog } from '@/components/user/user-create-dialog'
|
|
24
|
-
import { Button } from '
|
|
24
|
+
import { Button } from '@/components/ui/button'
|
|
25
25
|
import { PlusIcon } from 'lucide-react'
|
|
26
26
|
|
|
27
27
|
export const Route = createLazyFileRoute('/_nav/users')({
|
|
@@ -34,7 +34,7 @@ function AdminLoginPage() {
|
|
|
34
34
|
name: session.user.name,
|
|
35
35
|
email: session.user.email,
|
|
36
36
|
avatarConfig: (session.user as any).avatarConfig as AvatarConfig | undefined,
|
|
37
|
-
bgShape: (session.user as
|
|
37
|
+
bgShape: (session.user as { bgShape?: string | null }).bgShape ?? undefined,
|
|
38
38
|
bgColor: (session.user as any).bgColor as string | undefined,
|
|
39
39
|
}
|
|
40
40
|
: null
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
import { createLazyFileRoute, useNavigate } from '@tanstack/react-router'
|
|
19
19
|
import { m } from '@/paraglide/messages.js'
|
|
20
20
|
import { useState } from 'react'
|
|
21
|
-
import { toast } from '
|
|
21
|
+
import { toast } from '@/components/ui/toast'
|
|
22
22
|
import { Loader2, ShieldCheck, User, Mail, Database } from 'lucide-react'
|
|
23
23
|
import { AuthLayout, AuthLayoutLeft, AuthLayoutRight } from '@/components/auth/auth-layout'
|
|
24
24
|
import { AuthHeader } from '@/components/auth/auth-header'
|
|
25
25
|
import { AuthBrandPanel } from '@/components/auth/auth-brand-panel'
|
|
26
26
|
import { PasswordInput } from '@/components/auth/password-input'
|
|
27
27
|
import { IconInput } from '@/components/auth/icon-input'
|
|
28
|
-
import { Button } from '
|
|
28
|
+
import { Button } from '@/components/ui/button'
|
|
29
29
|
import { setupAdminFn } from '@/server/serverFns/auth/setup'
|
|
30
30
|
|
|
31
31
|
export const Route = createLazyFileRoute('/setup')({
|
|
@@ -24,6 +24,16 @@ export interface GithubData {
|
|
|
24
24
|
versionDate: Date | null
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
interface GithubRepoJson {
|
|
28
|
+
stargazers_count?: number
|
|
29
|
+
updated_at?: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface GithubReleaseJson {
|
|
33
|
+
tag_name?: string
|
|
34
|
+
published_at?: string
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
const API = 'https://api.github.com'
|
|
28
38
|
const HEADERS: HeadersInit = {
|
|
29
39
|
Accept: 'application/vnd.github+json',
|
|
@@ -39,14 +49,14 @@ export async function fetchGithubData(
|
|
|
39
49
|
): Promise<GithubData | null> {
|
|
40
50
|
const repoRes = await fetch(`${API}/repos/${owner}/${repo}`, { headers: HEADERS })
|
|
41
51
|
if (!repoRes.ok) return null
|
|
42
|
-
const repoJson:
|
|
52
|
+
const repoJson: GithubRepoJson = await repoRes.json()
|
|
43
53
|
|
|
44
54
|
let latestVersion: string | null = null
|
|
45
55
|
let versionDate: Date | null = null
|
|
46
56
|
try {
|
|
47
57
|
const relRes = await fetch(`${API}/repos/${owner}/${repo}/releases/latest`, { headers: HEADERS })
|
|
48
58
|
if (relRes.ok) {
|
|
49
|
-
const relJson:
|
|
59
|
+
const relJson: GithubReleaseJson = await relRes.json()
|
|
50
60
|
latestVersion = relJson.tag_name ?? null
|
|
51
61
|
versionDate = relJson.published_at ? new Date(relJson.published_at) : null
|
|
52
62
|
}
|
|
@@ -19,7 +19,7 @@ import { createServerFn } from '@tanstack/react-start'
|
|
|
19
19
|
import { z } from 'zod'
|
|
20
20
|
import { getPrisma } from '@allbluecn/database/get-prisma'
|
|
21
21
|
import { requireAdmin } from '@/server/auth-helpers'
|
|
22
|
-
import { bookmarkCanonicalId, parseGithubUrl } from '@/server/knowledge
|
|
22
|
+
import { bookmarkCanonicalId, parseGithubUrl } from '@/server/knowledge/public/canonical-id'
|
|
23
23
|
|
|
24
24
|
const createSchema = z.object({
|
|
25
25
|
title: z.string().min(1).max(200),
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import { createServerFn } from '@tanstack/react-start'
|
|
19
19
|
import { z } from 'zod'
|
|
20
20
|
import { getPrisma } from '@allbluecn/database/get-prisma'
|
|
21
|
+
import { Prisma } from '@allbluecn/database'
|
|
21
22
|
import { requireAdmin } from '@/server/auth-helpers'
|
|
22
23
|
|
|
23
24
|
const listSchema = z.object({
|
|
@@ -33,7 +34,7 @@ export const adminListBookmarksFn = createServerFn({ method: 'GET' })
|
|
|
33
34
|
.handler(async ({ data }) => {
|
|
34
35
|
const prisma = await getPrisma()
|
|
35
36
|
await requireAdmin()
|
|
36
|
-
const where:
|
|
37
|
+
const where: Prisma.WebsiteBookmarkWhereInput = { visibility: 'public', isDeleted: false }
|
|
37
38
|
if (data.search) {
|
|
38
39
|
where.OR = [
|
|
39
40
|
{ title: { contains: data.search, mode: 'insensitive' } },
|
package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/sync-all-github.ts
RENAMED
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
import { createServerFn } from '@tanstack/react-start'
|
|
19
19
|
import { z } from 'zod'
|
|
20
20
|
import { getPrisma } from '@allbluecn/database/get-prisma'
|
|
21
|
+
import { Prisma } from '@allbluecn/database'
|
|
21
22
|
import { requireAdmin } from '@/server/auth-helpers'
|
|
22
|
-
import { syncBookmarkGithub } from '@/server/knowledge
|
|
23
|
+
import { syncBookmarkGithub } from '@/server/knowledge/public/github-sync'
|
|
23
24
|
|
|
24
25
|
const syncSchema = z.object({
|
|
25
26
|
force: z.boolean().default(false),
|
|
@@ -30,7 +31,7 @@ export const adminSyncAllGithubFn = createServerFn({ method: 'POST' })
|
|
|
30
31
|
.handler(async ({ data }) => {
|
|
31
32
|
const prisma = await getPrisma()
|
|
32
33
|
await requireAdmin()
|
|
33
|
-
const where:
|
|
34
|
+
const where: Prisma.WebsiteBookmarkWhereInput = { isGithub: true, isDeleted: false }
|
|
34
35
|
if (!data.force) {
|
|
35
36
|
const sixHoursAgo = new Date(Date.now() - 6 * 60 * 60 * 1000)
|
|
36
37
|
where.OR = [
|
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
import { createServerFn } from '@tanstack/react-start'
|
|
19
19
|
import { z } from 'zod'
|
|
20
20
|
import { getPrisma } from '@allbluecn/database/get-prisma'
|
|
21
|
+
import { Prisma } from '@allbluecn/database'
|
|
21
22
|
import { requireAdmin } from '@/server/auth-helpers'
|
|
22
|
-
import { bookmarkCanonicalId, parseGithubUrl } from '@/server/knowledge
|
|
23
|
+
import { bookmarkCanonicalId, parseGithubUrl } from '@/server/knowledge/public/canonical-id'
|
|
23
24
|
|
|
24
25
|
const updateSchema = z.object({
|
|
25
26
|
id: z.string(),
|
|
@@ -38,7 +39,7 @@ export const adminUpdateBookmarkFn = createServerFn({ method: 'POST' })
|
|
|
38
39
|
const { id, ...rest } = data
|
|
39
40
|
const existing = await prisma.websiteBookmark.findUnique({ where: { id } })
|
|
40
41
|
if (!existing) throw new Error('未找到')
|
|
41
|
-
const updateData:
|
|
42
|
+
const updateData: Prisma.WebsiteBookmarkUncheckedUpdateInput = { ...rest }
|
|
42
43
|
const urlChanged = data.url !== undefined && data.url !== existing.url
|
|
43
44
|
if (urlChanged && data.url) {
|
|
44
45
|
const gh = parseGithubUrl(data.url)
|
|
@@ -19,7 +19,7 @@ import { createServerFn } from '@tanstack/react-start'
|
|
|
19
19
|
import { z } from 'zod'
|
|
20
20
|
import { getPrisma } from '@allbluecn/database/get-prisma'
|
|
21
21
|
import { requireAdmin } from '@/server/auth-helpers'
|
|
22
|
-
import { complianceCanonicalId } from '@/server/knowledge
|
|
22
|
+
import { complianceCanonicalId } from '@/server/knowledge/public/canonical-id'
|
|
23
23
|
|
|
24
24
|
const createSchema = z.object({
|
|
25
25
|
title: z.string().min(1).max(200),
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import { createServerFn } from '@tanstack/react-start'
|
|
19
19
|
import { z } from 'zod'
|
|
20
20
|
import { getPrisma } from '@allbluecn/database/get-prisma'
|
|
21
|
+
import { Prisma } from '@allbluecn/database'
|
|
21
22
|
import { requireAdmin } from '@/server/auth-helpers'
|
|
22
23
|
|
|
23
24
|
const listSchema = z.object({
|
|
@@ -33,7 +34,7 @@ export const adminListComplianceFn = createServerFn({ method: 'GET' })
|
|
|
33
34
|
.handler(async ({ data }) => {
|
|
34
35
|
const prisma = await getPrisma()
|
|
35
36
|
await requireAdmin()
|
|
36
|
-
const where:
|
|
37
|
+
const where: Prisma.IndustryComplianceWhereInput = { visibility: 'public', isDeleted: false }
|
|
37
38
|
if (data.search) {
|
|
38
39
|
where.OR = [
|
|
39
40
|
{ title: { contains: data.search, mode: 'insensitive' } },
|
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
import { createServerFn } from '@tanstack/react-start'
|
|
19
19
|
import { z } from 'zod'
|
|
20
20
|
import { getPrisma } from '@allbluecn/database/get-prisma'
|
|
21
|
+
import { Prisma } from '@allbluecn/database'
|
|
21
22
|
import { requireAdmin } from '@/server/auth-helpers'
|
|
22
|
-
import { complianceCanonicalId } from '@/server/knowledge
|
|
23
|
+
import { complianceCanonicalId } from '@/server/knowledge/public/canonical-id'
|
|
23
24
|
|
|
24
25
|
const updateSchema = z.object({
|
|
25
26
|
id: z.string(),
|
|
@@ -43,7 +44,7 @@ export const adminUpdateComplianceFn = createServerFn({ method: 'POST' })
|
|
|
43
44
|
const { id, code, ...rest } = data
|
|
44
45
|
const existing = await prisma.industryCompliance.findUnique({ where: { id } })
|
|
45
46
|
if (!existing) throw new Error('未找到')
|
|
46
|
-
const updateData:
|
|
47
|
+
const updateData: Prisma.IndustryComplianceUncheckedUpdateInput = { ...rest }
|
|
47
48
|
if (code !== undefined || data.title !== undefined) {
|
|
48
49
|
updateData.canonicalId = complianceCanonicalId({
|
|
49
50
|
title: data.title ?? existing.title,
|
|
@@ -19,7 +19,7 @@ import { createServerFn } from '@tanstack/react-start'
|
|
|
19
19
|
import { z } from 'zod'
|
|
20
20
|
import { getPrisma } from '@allbluecn/database/get-prisma'
|
|
21
21
|
import { requireAdmin } from '@/server/auth-helpers'
|
|
22
|
-
import { legalCanonicalId } from '@/server/knowledge
|
|
22
|
+
import { legalCanonicalId } from '@/server/knowledge/public/canonical-id'
|
|
23
23
|
|
|
24
24
|
const createSchema = z.object({
|
|
25
25
|
title: z.string().min(1).max(200),
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import { createServerFn } from '@tanstack/react-start'
|
|
19
19
|
import { z } from 'zod'
|
|
20
20
|
import { getPrisma } from '@allbluecn/database/get-prisma'
|
|
21
|
+
import { Prisma } from '@allbluecn/database'
|
|
21
22
|
import { requireAdmin } from '@/server/auth-helpers'
|
|
22
23
|
|
|
23
24
|
const listSchema = z.object({
|
|
@@ -33,7 +34,7 @@ export const adminListLegalFn = createServerFn({ method: 'GET' })
|
|
|
33
34
|
.handler(async ({ data }) => {
|
|
34
35
|
const prisma = await getPrisma()
|
|
35
36
|
await requireAdmin()
|
|
36
|
-
const where:
|
|
37
|
+
const where: Prisma.LegalRegulationWhereInput = { visibility: 'public', isDeleted: false }
|
|
37
38
|
if (data.search) {
|
|
38
39
|
where.OR = [
|
|
39
40
|
{ title: { contains: data.search, mode: 'insensitive' } },
|
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
import { createServerFn } from '@tanstack/react-start'
|
|
19
19
|
import { z } from 'zod'
|
|
20
20
|
import { getPrisma } from '@allbluecn/database/get-prisma'
|
|
21
|
+
import { Prisma } from '@allbluecn/database'
|
|
21
22
|
import { requireAdmin } from '@/server/auth-helpers'
|
|
22
|
-
import { legalCanonicalId } from '@/server/knowledge
|
|
23
|
+
import { legalCanonicalId } from '@/server/knowledge/public/canonical-id'
|
|
23
24
|
|
|
24
25
|
const updateSchema = z.object({
|
|
25
26
|
id: z.string(),
|
|
@@ -45,7 +46,7 @@ export const adminUpdateLegalFn = createServerFn({ method: 'POST' })
|
|
|
45
46
|
const { id, code, ...rest } = data
|
|
46
47
|
const existing = await prisma.legalRegulation.findUnique({ where: { id } })
|
|
47
48
|
if (!existing) throw new Error('未找到')
|
|
48
|
-
const updateData:
|
|
49
|
+
const updateData: Prisma.LegalRegulationUncheckedUpdateInput = { ...rest }
|
|
49
50
|
if (code !== undefined || data.title !== undefined) {
|
|
50
51
|
updateData.canonicalId = legalCanonicalId({
|
|
51
52
|
title: data.title ?? existing.title,
|
package/src/styles/globals.css
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
@import "tailwindcss";
|
|
5
5
|
|
|
6
|
-
/*
|
|
7
|
-
|
|
8
|
-
@source "
|
|
6
|
+
/* src 源码类名扫描(含 components/ui 内联组件,
|
|
7
|
+
Tailwind v4 自动探测不覆盖的路径由此显式声明) */
|
|
8
|
+
@source "../";
|
|
9
9
|
|
|
10
10
|
@import "tw-animate-css";
|
|
11
11
|
|
package/allblue-ui/package.json
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
-
// AllBlue - 理想之海
|
|
3
|
-
// Copyright (C) 2026 AllBlue Contributors
|
|
4
|
-
|
|
5
|
-
import { useLoadMore } from "../hooks/use-load-more"
|
|
6
|
-
|
|
7
|
-
interface InfiniteScrollSentinelProps {
|
|
8
|
-
onLoadMore: () => void | Promise<void>
|
|
9
|
-
hasMore: boolean
|
|
10
|
-
rootRef?: React.RefObject<HTMLElement | null>
|
|
11
|
-
/** 全部加载完后的提示文案(调用方传入,组件内不做 i18n) */
|
|
12
|
-
loadedAllLabel: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* 无限滚动哨兵:滚动到底部附近触发 onLoadMore,展示三点脉冲 loading 与
|
|
17
|
-
* 「已全部加载」提示。加载状态机见 useLoadMore。
|
|
18
|
-
*/
|
|
19
|
-
export function InfiniteScrollSentinel({ onLoadMore, hasMore, rootRef, loadedAllLabel }: InfiniteScrollSentinelProps) {
|
|
20
|
-
const { sentinelRef, loading } = useLoadMore(onLoadMore, hasMore, rootRef)
|
|
21
|
-
|
|
22
|
-
return (
|
|
23
|
-
<div className="flex h-7 items-center justify-center">
|
|
24
|
-
<div ref={sentinelRef} className="h-1" />
|
|
25
|
-
{loading && (
|
|
26
|
-
<div className="flex items-center gap-1">
|
|
27
|
-
<div className="h-1.5 w-1.5 animate-pulse rounded-full bg-primary/60" />
|
|
28
|
-
<div className="h-1.5 w-1.5 animate-pulse rounded-full bg-primary/60 delay-75" />
|
|
29
|
-
<div className="h-1.5 w-1.5 animate-pulse rounded-full bg-primary/60 delay-150" />
|
|
30
|
-
</div>
|
|
31
|
-
)}
|
|
32
|
-
{!loading && !hasMore && (
|
|
33
|
-
<span className="text-xs text-muted-foreground">{loadedAllLabel}</span>
|
|
34
|
-
)}
|
|
35
|
-
</div>
|
|
36
|
-
)
|
|
37
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
-
// AllBlue - 理想之海
|
|
3
|
-
// Copyright (C) 2026 AllBlue Contributors
|
|
4
|
-
|
|
5
|
-
import { useEffect, useRef, useState } from "react";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* 无限滚动加载状态机:IntersectionObserver 哨兵 + loading 防重入。
|
|
9
|
-
*
|
|
10
|
-
* 哨兵进入视口且 hasMore 时触发 onLoadMore;返回 Promise 时 resolve 后解除
|
|
11
|
-
* loading,同步返回则由调用方经 hasMore/数据更新间接解除。供
|
|
12
|
-
* InfiniteScrollSentinel 等无限滚动组件复用。
|
|
13
|
-
*/
|
|
14
|
-
export function useLoadMore(
|
|
15
|
-
onLoadMore: () => void | Promise<void>,
|
|
16
|
-
hasMore: boolean,
|
|
17
|
-
rootRef?: React.RefObject<HTMLElement | null>,
|
|
18
|
-
): {
|
|
19
|
-
/** 挂到滚动末端哨兵元素上 */
|
|
20
|
-
sentinelRef: React.RefObject<HTMLDivElement | null>;
|
|
21
|
-
loading: boolean;
|
|
22
|
-
} {
|
|
23
|
-
const sentinelRef = useRef<HTMLDivElement>(null);
|
|
24
|
-
const observerRef = useRef<IntersectionObserver | null>(null);
|
|
25
|
-
const [loading, setLoading] = useState(false);
|
|
26
|
-
const loadingRef = useRef(false);
|
|
27
|
-
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
loadingRef.current = loading;
|
|
30
|
-
}, [loading]);
|
|
31
|
-
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (!sentinelRef.current || !hasMore) return;
|
|
34
|
-
|
|
35
|
-
if (observerRef.current) observerRef.current.disconnect();
|
|
36
|
-
|
|
37
|
-
const observer = new IntersectionObserver(
|
|
38
|
-
(entries) => {
|
|
39
|
-
if (entries[0]?.isIntersecting && !loadingRef.current) {
|
|
40
|
-
setLoading(true);
|
|
41
|
-
const result = onLoadMore();
|
|
42
|
-
if (result && typeof (result as Promise<void>).then === "function") {
|
|
43
|
-
(result as Promise<void>).then(() => setLoading(false));
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
{ root: rootRef?.current ?? null, rootMargin: "80px" },
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
observer.observe(sentinelRef.current);
|
|
51
|
-
observerRef.current = observer;
|
|
52
|
-
return () => observer.disconnect();
|
|
53
|
-
// onLoadMore 由调用方保证稳定(多为 useCallback),与原实现一致仅依赖 hasMore/rootRef
|
|
54
|
-
}, [hasMore, rootRef]);
|
|
55
|
-
|
|
56
|
-
return { sentinelRef, loading };
|
|
57
|
-
}
|
package/allblue-ui/src/index.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
export * from "./ui/alert"
|
|
2
|
-
export * from "./ui/alert-dialog"
|
|
3
|
-
export * from "./ui/avatar"
|
|
4
|
-
export * from "./ui/badge"
|
|
5
|
-
export * from "./ui/button"
|
|
6
|
-
export * from "./ui/card"
|
|
7
|
-
export * from "./ui/checkbox"
|
|
8
|
-
export * from "./ui/collapsible"
|
|
9
|
-
export * from "./ui/dialog"
|
|
10
|
-
export * from "./ui/dropdown-menu"
|
|
11
|
-
export * from "./ui/field"
|
|
12
|
-
export * from "./ui/input"
|
|
13
|
-
export * from "./ui/input-group"
|
|
14
|
-
export * from "./ui/label"
|
|
15
|
-
export * from "./ui/pagination"
|
|
16
|
-
export * from "./ui/select"
|
|
17
|
-
export * from "./ui/separator"
|
|
18
|
-
export * from "./ui/sheet"
|
|
19
|
-
export * from "./ui/sidebar"
|
|
20
|
-
export * from "./ui/skeleton"
|
|
21
|
-
export * from "./ui/switch"
|
|
22
|
-
export * from "./ui/table"
|
|
23
|
-
export * from "./ui/textarea"
|
|
24
|
-
export * from "./ui/toast"
|
|
25
|
-
export * from "./ui/tooltip"
|
|
26
|
-
export { ConfirmDialog, type ConfirmDialogProps } from "./components/confirm-dialog"
|
|
27
|
-
export { InfiniteScrollSentinel } from "./components/infinite-scroll-sentinel"
|
|
28
|
-
export { useLoadMore } from "./hooks/use-load-more"
|
|
29
|
-
export { useIsMobile } from "./hooks/use-mobile"
|
|
30
|
-
export { getBoringAvatarUrl, getAvatarFallback, type AvatarOptions } from "./lib/avatar"
|
|
31
|
-
export { cn } from "./lib/utils"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { cn } from "cn"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|