@locusai/web 0.1.7 → 0.2.2
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 +26 -0
- package/next.config.js +15 -2
- package/package.json +26 -3
- package/src/app/(auth)/invite/page.tsx +109 -0
- package/src/app/(auth)/layout.tsx +19 -0
- package/src/app/(auth)/login/page.tsx +65 -0
- package/src/app/(auth)/onboarding/workspace/page.tsx +46 -0
- package/src/app/(auth)/register/page.tsx +165 -0
- package/src/app/(dashboard)/activity/page.tsx +7 -0
- package/src/app/(dashboard)/backlog/page.tsx +195 -0
- package/src/app/(dashboard)/board/page.tsx +141 -0
- package/src/app/(dashboard)/layout.tsx +32 -0
- package/src/app/(dashboard)/page.tsx +14 -0
- package/src/app/(dashboard)/settings/page.tsx +161 -0
- package/src/app/(dashboard)/settings/team/page.tsx +75 -0
- package/src/app/globals.css +259 -0
- package/src/app/layout.tsx +10 -20
- package/src/app/providers.tsx +26 -3
- package/src/components/AuthLayoutUI.tsx +53 -0
- package/src/components/BoardFilter.tsx +75 -74
- package/src/components/CreateModal/CreateModal.tsx +142 -0
- package/src/components/CreateModal/index.ts +1 -0
- package/src/components/Editor.tsx +279 -0
- package/src/components/Header.tsx +99 -12
- package/src/components/PageLayout.tsx +69 -0
- package/src/components/PropertyItem.tsx +55 -9
- package/src/components/Sidebar.tsx +280 -36
- package/src/components/SprintCreateModal.tsx +84 -0
- package/src/components/TaskCard.tsx +196 -78
- package/src/components/TaskCreateModal.tsx +181 -178
- package/src/components/TaskPanel.tsx +140 -692
- package/src/components/WorkspaceCreateModal.tsx +97 -0
- package/src/components/WorkspaceProtected.tsx +91 -0
- package/src/components/auth/InviteSteps.tsx +220 -0
- package/src/components/auth/LoginSteps.tsx +86 -0
- package/src/components/auth/RegisterSteps.tsx +371 -0
- package/src/components/auth/index.ts +3 -0
- package/src/components/backlog/BacklogList.tsx +92 -0
- package/src/components/backlog/BacklogSection.tsx +137 -0
- package/src/components/backlog/CompletedSprintItem.tsx +95 -0
- package/src/components/backlog/CompletedSprintsSection.tsx +77 -0
- package/src/components/backlog/SprintSection.tsx +155 -0
- package/src/components/backlog/constants.ts +26 -0
- package/src/components/board/BoardColumn.tsx +97 -0
- package/src/components/board/BoardContent.tsx +84 -0
- package/src/components/board/BoardEmptyState.tsx +82 -0
- package/src/components/board/BoardHeader.tsx +47 -0
- package/src/components/board/SprintMindmap.tsx +65 -0
- package/src/components/board/constants.ts +40 -0
- package/src/components/board/index.ts +5 -0
- package/src/components/common/ErrorState.tsx +124 -0
- package/src/components/common/LoadingState.tsx +83 -0
- package/src/components/common/index.ts +40 -0
- package/src/components/dashboard/ActivityFeed.tsx +77 -0
- package/src/components/dashboard/ActivityItem.tsx +207 -0
- package/src/components/dashboard/QuickActions.tsx +50 -0
- package/src/components/dashboard/StatCard.tsx +79 -0
- package/src/components/dnd/index.tsx +51 -0
- package/src/components/docs/DocsEditorArea.tsx +87 -0
- package/src/components/docs/DocsHeaderActions.tsx +121 -0
- package/src/components/docs/DocsSidebar.tsx +351 -0
- package/src/components/index.ts +7 -0
- package/src/components/onboarding/StepProgress.tsx +21 -0
- package/src/components/onboarding/index.ts +1 -0
- package/src/components/settings/ApiKeyConfirmationModal.tsx +81 -0
- package/src/components/settings/ApiKeyCreatedModal.tsx +96 -0
- package/src/components/settings/ApiKeysList.tsx +143 -0
- package/src/components/settings/ApiKeysSettings.tsx +144 -0
- package/src/components/settings/InviteMemberModal.tsx +106 -0
- package/src/components/settings/ProjectSetupGuide.tsx +147 -0
- package/src/components/settings/SettingItem.tsx +32 -0
- package/src/components/settings/SettingSection.tsx +50 -0
- package/src/components/settings/TeamInvitationsList.tsx +90 -0
- package/src/components/settings/TeamMembersList.tsx +95 -0
- package/src/components/settings/index.ts +8 -0
- package/src/components/task-panel/TaskActivity.tsx +127 -0
- package/src/components/task-panel/TaskChecklist.tsx +142 -0
- package/src/components/task-panel/TaskDescription.tsx +201 -0
- package/src/components/task-panel/TaskDocs.tsx +137 -0
- package/src/components/task-panel/TaskHeader.tsx +125 -0
- package/src/components/task-panel/TaskProperties.tsx +111 -0
- package/src/components/task-panel/index.ts +12 -0
- package/src/components/typography/EmptyStateText.tsx +59 -0
- package/src/components/typography/MetadataText.tsx +65 -0
- package/src/components/typography/SecondaryText.tsx +60 -0
- package/src/components/typography/SectionLabel.tsx +60 -0
- package/src/components/typography/index.ts +14 -0
- package/src/components/typography-scales.tsx +218 -0
- package/src/components/ui/Avatar.tsx +123 -0
- package/src/components/ui/Badge.tsx +69 -2
- package/src/components/ui/Button.tsx +71 -30
- package/src/components/ui/Checkbox.tsx +34 -0
- package/src/components/ui/Dropdown.tsx +67 -1
- package/src/components/ui/EmptyState.tsx +129 -0
- package/src/components/ui/Input.tsx +53 -6
- package/src/components/ui/Modal.tsx +45 -12
- package/src/components/ui/OtpInput.tsx +148 -0
- package/src/components/ui/Skeleton.tsx +36 -0
- package/src/components/ui/Spinner.tsx +112 -0
- package/src/components/ui/Textarea.tsx +28 -3
- package/src/components/ui/Toast.tsx +99 -0
- package/src/components/ui/Toggle.tsx +63 -0
- package/src/components/ui/constants.ts +108 -0
- package/src/components/ui/index.ts +7 -0
- package/src/context/AuthContext.tsx +140 -0
- package/src/context/index.ts +1 -0
- package/src/hooks/backlog/index.ts +13 -0
- package/src/hooks/backlog/useBacklogActions.ts +144 -0
- package/src/hooks/backlog/useBacklogComposite.ts +73 -0
- package/src/hooks/backlog/useBacklogData.ts +74 -0
- package/src/hooks/backlog/useBacklogDragDrop.ts +118 -0
- package/src/hooks/backlog/useBacklogUI.ts +74 -0
- package/src/hooks/index.ts +22 -0
- package/src/hooks/task-panel/index.ts +13 -0
- package/src/hooks/task-panel/useTaskActions.ts +200 -0
- package/src/hooks/task-panel/useTaskComputedValues.ts +30 -0
- package/src/hooks/task-panel/useTaskData.ts +78 -0
- package/src/hooks/task-panel/useTaskPanelComposite.ts +161 -0
- package/src/hooks/task-panel/useTaskUIState.ts +80 -0
- package/src/hooks/useAuthLayoutLogic.ts +43 -0
- package/src/hooks/useAuthenticatedUser.ts +36 -0
- package/src/hooks/useAuthenticatedUserWithOrg.ts +41 -0
- package/src/hooks/useBacklog.ts +303 -0
- package/src/hooks/useBoard.ts +230 -0
- package/src/hooks/useDashboardLayout.ts +49 -0
- package/src/hooks/useDocs.ts +279 -0
- package/src/hooks/useDocsQuery.ts +99 -0
- package/src/hooks/useDocsSidebarState.ts +104 -0
- package/src/hooks/useFormState.ts +40 -0
- package/src/hooks/useGlobalKeydowns.ts +52 -0
- package/src/hooks/useInviteForm.ts +122 -0
- package/src/hooks/useLoginForm.ts +84 -0
- package/src/hooks/useMutationWithToast.ts +56 -0
- package/src/hooks/useOrganizationQuery.ts +55 -0
- package/src/hooks/useRegisterForm.ts +216 -0
- package/src/hooks/useSprintsQuery.ts +38 -0
- package/src/hooks/useTaskDescription.ts +102 -0
- package/src/hooks/useTaskPanel.ts +341 -0
- package/src/hooks/useTasksQuery.ts +39 -0
- package/src/hooks/useTeamManagement.ts +92 -0
- package/src/hooks/useWorkspaceCreateForm.ts +70 -0
- package/src/hooks/useWorkspaceId.ts +29 -0
- package/src/lib/api-client.ts +40 -23
- package/src/lib/config.ts +25 -0
- package/src/lib/constants.ts +83 -0
- package/src/lib/options.ts +96 -0
- package/src/lib/query-keys.ts +91 -0
- package/src/lib/typography.ts +103 -0
- package/src/lib/utils.ts +4 -0
- package/src/lib/validation.ts +192 -0
- package/src/services/index.ts +7 -3
- package/src/services/notifications.ts +80 -0
- package/src/utils/env.utils.ts +15 -0
- package/src/views/ActivityView.tsx +123 -0
- package/src/views/Dashboard.tsx +126 -0
- package/src/views/Docs.tsx +98 -612
- package/tsconfig.tsbuildinfo +1 -1
- package/.next/BUILD_ID +0 -1
- package/.next/app-build-manifest.json +0 -55
- package/.next/app-path-routes-manifest.json +0 -8
- package/.next/build-manifest.json +0 -33
- package/.next/cache/.previewinfo +0 -1
- package/.next/cache/.rscinfo +0 -1
- package/.next/cache/.tsbuildinfo +0 -1
- package/.next/cache/config.json +0 -7
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/diagnostics/build-diagnostics.json +0 -6
- package/.next/diagnostics/framework.json +0 -1
- package/.next/export-detail.json +0 -5
- package/.next/export-marker.json +0 -6
- package/.next/images-manifest.json +0 -57
- package/.next/next-minimal-server.js.nft.json +0 -1
- package/.next/next-server.js.nft.json +0 -1
- package/.next/package.json +0 -1
- package/.next/prerender-manifest.json +0 -137
- package/.next/react-loadable-manifest.json +0 -32
- package/.next/required-server-files.json +0 -324
- package/.next/routes-manifest.json +0 -77
- package/.next/server/app/_not-found/page.js +0 -2
- package/.next/server/app/_not-found/page.js.nft.json +0 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +0 -1
- package/.next/server/app/_not-found.html +0 -1
- package/.next/server/app/_not-found.meta +0 -8
- package/.next/server/app/_not-found.rsc +0 -21
- package/.next/server/app/backlog/page.js +0 -2
- package/.next/server/app/backlog/page.js.nft.json +0 -1
- package/.next/server/app/backlog/page_client-reference-manifest.js +0 -1
- package/.next/server/app/backlog.html +0 -1
- package/.next/server/app/backlog.meta +0 -7
- package/.next/server/app/backlog.rsc +0 -25
- package/.next/server/app/docs/page.js +0 -97
- package/.next/server/app/docs/page.js.nft.json +0 -1
- package/.next/server/app/docs/page_client-reference-manifest.js +0 -1
- package/.next/server/app/docs.html +0 -1
- package/.next/server/app/docs.meta +0 -7
- package/.next/server/app/docs.rsc +0 -26
- package/.next/server/app/favicon.ico/route.js +0 -1
- package/.next/server/app/favicon.ico/route.js.nft.json +0 -1
- package/.next/server/app/favicon.ico.body +0 -0
- package/.next/server/app/favicon.ico.meta +0 -1
- package/.next/server/app/index.html +0 -1
- package/.next/server/app/index.meta +0 -7
- package/.next/server/app/index.rsc +0 -25
- package/.next/server/app/page.js +0 -2
- package/.next/server/app/page.js.nft.json +0 -1
- package/.next/server/app/page_client-reference-manifest.js +0 -1
- package/.next/server/app/settings/page.js +0 -2
- package/.next/server/app/settings/page.js.nft.json +0 -1
- package/.next/server/app/settings/page_client-reference-manifest.js +0 -1
- package/.next/server/app/settings.html +0 -1
- package/.next/server/app/settings.meta +0 -7
- package/.next/server/app/settings.rsc +0 -25
- package/.next/server/app-paths-manifest.json +0 -8
- package/.next/server/chunks/496.js +0 -6
- package/.next/server/chunks/585.js +0 -1
- package/.next/server/chunks/665.js +0 -1
- package/.next/server/chunks/699.js +0 -22
- package/.next/server/chunks/852.js +0 -7
- package/.next/server/functions-config-manifest.json +0 -4
- package/.next/server/interception-route-rewrite-manifest.js +0 -1
- package/.next/server/middleware-build-manifest.js +0 -1
- package/.next/server/middleware-manifest.json +0 -6
- package/.next/server/middleware-react-loadable-manifest.js +0 -1
- package/.next/server/next-font-manifest.js +0 -1
- package/.next/server/next-font-manifest.json +0 -1
- package/.next/server/pages/404.html +0 -1
- package/.next/server/pages/500.html +0 -1
- package/.next/server/pages/_app.js +0 -1
- package/.next/server/pages/_app.js.nft.json +0 -1
- package/.next/server/pages/_document.js +0 -1
- package/.next/server/pages/_document.js.nft.json +0 -1
- package/.next/server/pages/_error.js +0 -19
- package/.next/server/pages/_error.js.nft.json +0 -1
- package/.next/server/pages-manifest.json +0 -6
- package/.next/server/server-reference-manifest.js +0 -1
- package/.next/server/server-reference-manifest.json +0 -1
- package/.next/server/webpack-runtime.js +0 -1
- package/.next/static/D0NXe04ZCLNDckV_quc8g/_buildManifest.js +0 -1
- package/.next/static/D0NXe04ZCLNDckV_quc8g/_ssgManifest.js +0 -1
- package/.next/static/chunks/138.b98511c56423f8bb.js +0 -1
- package/.next/static/chunks/146-34259952c594a3b0.js +0 -1
- package/.next/static/chunks/337-d3bb75304d130513.js +0 -1
- package/.next/static/chunks/477.1a6ecfe53375bd9c.js +0 -1
- package/.next/static/chunks/487-1808785ba665f784.js +0 -1
- package/.next/static/chunks/544.a9569941cc886e9d.js +0 -1
- package/.next/static/chunks/87c73c54-1f4741035a95c140.js +0 -1
- package/.next/static/chunks/902-d6926825a9fe8784.js +0 -1
- package/.next/static/chunks/955-c8f8f6235ae8f8c6.js +0 -1
- package/.next/static/chunks/996.e0a334e6ae90900e.js +0 -1
- package/.next/static/chunks/app/_not-found/page-44b1804abb44a34d.js +0 -1
- package/.next/static/chunks/app/backlog/page-dce1450769bfae8f.js +0 -1
- package/.next/static/chunks/app/docs/page-1efee819f25492cb.js +0 -1
- package/.next/static/chunks/app/layout-05f504c042b9f7ee.js +0 -1
- package/.next/static/chunks/app/page-3fd91aaaa4776ced.js +0 -1
- package/.next/static/chunks/app/settings/page-84e16c9638d657e4.js +0 -1
- package/.next/static/chunks/framework-152a1bc8c81c7458.js +0 -1
- package/.next/static/chunks/main-843ab130fc1be309.js +0 -1
- package/.next/static/chunks/main-app-123e879c5a937a00.js +0 -1
- package/.next/static/chunks/pages/_app-a050a8e6e4fb04cf.js +0 -1
- package/.next/static/chunks/pages/_error-3e422ffd891594de.js +0 -1
- package/.next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
- package/.next/static/chunks/webpack-99a10a055b5bb9c4.js +0 -1
- package/.next/static/css/13e8617b72f9d3aa.css +0 -1
- package/.next/static/css/8aea088cdc4338f0.css +0 -1
- package/.next/static/css/b301ab0424111664.css +0 -1
- package/.next/static/media/24c15609eaa28576-s.woff2 +0 -0
- package/.next/static/media/2c07349e02a7b712-s.woff2 +0 -0
- package/.next/static/media/456105d6ea6d39e0-s.woff2 +0 -0
- package/.next/static/media/47cbc4e2adbc5db9-s.p.woff2 +0 -0
- package/.next/static/media/4f77bef990aad698-s.woff2 +0 -0
- package/.next/static/media/627d916fd739a539-s.woff2 +0 -0
- package/.next/static/media/63b255f18bea0ca9-s.woff2 +0 -0
- package/.next/static/media/70bd82ac89b4fa42-s.woff2 +0 -0
- package/.next/static/media/84602850c8fd81c3-s.woff2 +0 -0
- package/.next/trace +0 -46
- package/.next/types/app/backlog/page.ts +0 -84
- package/.next/types/app/docs/page.ts +0 -84
- package/.next/types/app/layout.ts +0 -84
- package/.next/types/app/page.ts +0 -84
- package/.next/types/app/settings/page.ts +0 -84
- package/.next/types/cache-life.d.ts +0 -141
- package/.next/types/package.json +0 -1
- package/next-env.d.ts +0 -5
- package/out/404.html +0 -1
- package/out/_next/static/D0NXe04ZCLNDckV_quc8g/_buildManifest.js +0 -1
- package/out/_next/static/D0NXe04ZCLNDckV_quc8g/_ssgManifest.js +0 -1
- package/out/_next/static/chunks/138.b98511c56423f8bb.js +0 -1
- package/out/_next/static/chunks/146-34259952c594a3b0.js +0 -1
- package/out/_next/static/chunks/337-d3bb75304d130513.js +0 -1
- package/out/_next/static/chunks/477.1a6ecfe53375bd9c.js +0 -1
- package/out/_next/static/chunks/487-1808785ba665f784.js +0 -1
- package/out/_next/static/chunks/544.a9569941cc886e9d.js +0 -1
- package/out/_next/static/chunks/87c73c54-1f4741035a95c140.js +0 -1
- package/out/_next/static/chunks/902-d6926825a9fe8784.js +0 -1
- package/out/_next/static/chunks/955-c8f8f6235ae8f8c6.js +0 -1
- package/out/_next/static/chunks/996.e0a334e6ae90900e.js +0 -1
- package/out/_next/static/chunks/app/_not-found/page-44b1804abb44a34d.js +0 -1
- package/out/_next/static/chunks/app/backlog/page-dce1450769bfae8f.js +0 -1
- package/out/_next/static/chunks/app/docs/page-1efee819f25492cb.js +0 -1
- package/out/_next/static/chunks/app/layout-05f504c042b9f7ee.js +0 -1
- package/out/_next/static/chunks/app/page-3fd91aaaa4776ced.js +0 -1
- package/out/_next/static/chunks/app/settings/page-84e16c9638d657e4.js +0 -1
- package/out/_next/static/chunks/framework-152a1bc8c81c7458.js +0 -1
- package/out/_next/static/chunks/main-843ab130fc1be309.js +0 -1
- package/out/_next/static/chunks/main-app-123e879c5a937a00.js +0 -1
- package/out/_next/static/chunks/pages/_app-a050a8e6e4fb04cf.js +0 -1
- package/out/_next/static/chunks/pages/_error-3e422ffd891594de.js +0 -1
- package/out/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
- package/out/_next/static/chunks/webpack-99a10a055b5bb9c4.js +0 -1
- package/out/_next/static/css/13e8617b72f9d3aa.css +0 -1
- package/out/_next/static/css/8aea088cdc4338f0.css +0 -1
- package/out/_next/static/css/b301ab0424111664.css +0 -1
- package/out/_next/static/media/24c15609eaa28576-s.woff2 +0 -0
- package/out/_next/static/media/2c07349e02a7b712-s.woff2 +0 -0
- package/out/_next/static/media/456105d6ea6d39e0-s.woff2 +0 -0
- package/out/_next/static/media/47cbc4e2adbc5db9-s.p.woff2 +0 -0
- package/out/_next/static/media/4f77bef990aad698-s.woff2 +0 -0
- package/out/_next/static/media/627d916fd739a539-s.woff2 +0 -0
- package/out/_next/static/media/63b255f18bea0ca9-s.woff2 +0 -0
- package/out/_next/static/media/70bd82ac89b4fa42-s.woff2 +0 -0
- package/out/_next/static/media/84602850c8fd81c3-s.woff2 +0 -0
- package/out/backlog.html +0 -1
- package/out/backlog.txt +0 -25
- package/out/docs.html +0 -1
- package/out/docs.txt +0 -26
- package/out/favicon.ico +0 -0
- package/out/index.html +0 -1
- package/out/index.txt +0 -25
- package/out/logo.png +0 -0
- package/out/settings.html +0 -1
- package/out/settings.txt +0 -25
- package/src/app/backlog/page.tsx +0 -19
- package/src/app/page.tsx +0 -16
- package/src/app/settings/page.tsx +0 -194
- package/src/hooks/useTasks.ts +0 -119
- package/src/services/doc.service.ts +0 -27
- package/src/services/sprint.service.ts +0 -24
- package/src/services/task.service.ts +0 -75
- package/src/views/Backlog.tsx +0 -691
- package/src/views/Board.tsx +0 -306
- /package/src/app/{docs → (dashboard)/docs}/page.tsx +0 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Check, Clipboard, Terminal } from "lucide-react";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { toast } from "sonner";
|
|
6
|
+
import { Button } from "@/components/ui";
|
|
7
|
+
import { SettingSection } from "./SettingSection";
|
|
8
|
+
|
|
9
|
+
interface ProjectSetupGuideProps {
|
|
10
|
+
hasApiKeys: boolean;
|
|
11
|
+
workspaceId?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function ProjectSetupGuide({
|
|
15
|
+
hasApiKeys,
|
|
16
|
+
workspaceId,
|
|
17
|
+
}: ProjectSetupGuideProps) {
|
|
18
|
+
const [copiedCommand, setCopiedCommand] = useState<string | null>(null);
|
|
19
|
+
|
|
20
|
+
const copyToClipboard = (text: string, id: string) => {
|
|
21
|
+
navigator.clipboard.writeText(text);
|
|
22
|
+
setCopiedCommand(id);
|
|
23
|
+
toast.success("Command copied to clipboard");
|
|
24
|
+
setTimeout(() => setCopiedCommand(null), 2000);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const steps = [
|
|
28
|
+
{
|
|
29
|
+
id: "api-key",
|
|
30
|
+
title: "1. Create an API Key",
|
|
31
|
+
description:
|
|
32
|
+
"You'll need an API key to authenticate the CLI with your organization.",
|
|
33
|
+
status: hasApiKeys ? "completed" : "pending",
|
|
34
|
+
content: hasApiKeys ? (
|
|
35
|
+
<p className="text-sm text-green-500 flex items-center gap-2">
|
|
36
|
+
<Check size={16} /> API key created
|
|
37
|
+
</p>
|
|
38
|
+
) : (
|
|
39
|
+
<p className="text-sm text-muted-foreground">
|
|
40
|
+
Go to the API Keys section above and create your first key.
|
|
41
|
+
</p>
|
|
42
|
+
),
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "install",
|
|
46
|
+
title: "2. Initialize your project",
|
|
47
|
+
description:
|
|
48
|
+
"Run this command in your project root to set up Locus configuration and CLAUDE.md.",
|
|
49
|
+
status: "action",
|
|
50
|
+
command: "npx @locusai/cli init",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "run",
|
|
54
|
+
title: "3. Start your agents",
|
|
55
|
+
description:
|
|
56
|
+
"Run this command to start an agent that will poll for tasks from your dashboard.",
|
|
57
|
+
status: "action",
|
|
58
|
+
command: `npx @locusai/cli run --api-key YOUR_API_KEY --workspace ${workspaceId || "YOUR_WORKSPACE_ID"}`,
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<SettingSection title="Project Setup Guide">
|
|
64
|
+
<div className="p-6 space-y-8">
|
|
65
|
+
{steps.map((step) => (
|
|
66
|
+
<div key={step.id} className="relative pl-8">
|
|
67
|
+
{/* Connector Line */}
|
|
68
|
+
{step.id !== "run" && (
|
|
69
|
+
<div className="absolute left-[11px] top-8 bottom-[-32px] w-[2px] bg-border/50" />
|
|
70
|
+
)}
|
|
71
|
+
|
|
72
|
+
{/* Step Indicator */}
|
|
73
|
+
<div
|
|
74
|
+
className={`absolute left-0 top-0 w-6 h-6 rounded-full flex items-center justify-center text-[10px] font-bold border-2 ${
|
|
75
|
+
step.status === "completed"
|
|
76
|
+
? "bg-green-500/10 border-green-500 text-green-500"
|
|
77
|
+
: "bg-secondary border-border text-muted-foreground"
|
|
78
|
+
}`}
|
|
79
|
+
>
|
|
80
|
+
{step.status === "completed" ? (
|
|
81
|
+
<Check size={12} />
|
|
82
|
+
) : step.id === "api-key" ? (
|
|
83
|
+
"1"
|
|
84
|
+
) : step.id === "install" ? (
|
|
85
|
+
"2"
|
|
86
|
+
) : (
|
|
87
|
+
"3"
|
|
88
|
+
)}
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<div className="space-y-3">
|
|
92
|
+
<div>
|
|
93
|
+
<h4 className="font-medium text-sm text-foreground">
|
|
94
|
+
{step.title}
|
|
95
|
+
</h4>
|
|
96
|
+
<p className="text-xs text-muted-foreground mt-1">
|
|
97
|
+
{step.description}
|
|
98
|
+
</p>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
{step.content}
|
|
102
|
+
|
|
103
|
+
{step.command && (
|
|
104
|
+
<div className="group relative">
|
|
105
|
+
<div className="bg-secondary/50 border border-border/50 rounded-xl p-3 font-mono text-xs flex items-center justify-between overflow-x-auto">
|
|
106
|
+
<code className="text-foreground whitespace-nowrap">
|
|
107
|
+
<span className="text-muted-foreground mr-2">$</span>
|
|
108
|
+
{step.command}
|
|
109
|
+
</code>
|
|
110
|
+
<Button
|
|
111
|
+
variant="ghost"
|
|
112
|
+
size="icon"
|
|
113
|
+
className="h-8 w-8 ml-2 opacity-0 group-hover:opacity-100 transition-opacity"
|
|
114
|
+
onClick={() => {
|
|
115
|
+
if (step.command) {
|
|
116
|
+
copyToClipboard(step.command, step.id);
|
|
117
|
+
}
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
{copiedCommand === step.id ? (
|
|
121
|
+
<Check size={14} className="text-green-500" />
|
|
122
|
+
) : (
|
|
123
|
+
<Clipboard size={14} />
|
|
124
|
+
)}
|
|
125
|
+
</Button>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
)}
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
))}
|
|
132
|
+
|
|
133
|
+
<div className="pt-4 flex items-center gap-3 p-4 bg-primary/5 border border-primary/10 rounded-2xl">
|
|
134
|
+
<Terminal size={18} className="text-primary" />
|
|
135
|
+
<p className="text-xs text-muted-foreground">
|
|
136
|
+
<span className="font-medium text-foreground">Pro tip:</span> You
|
|
137
|
+
can also set{" "}
|
|
138
|
+
<code className="bg-secondary px-1 rounded text-foreground">
|
|
139
|
+
LOCUS_API_KEY
|
|
140
|
+
</code>{" "}
|
|
141
|
+
environment variable to avoid passing it via flags.
|
|
142
|
+
</p>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</SettingSection>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
export interface SettingItemProps {
|
|
6
|
+
icon: React.ReactNode;
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function SettingItem({
|
|
13
|
+
icon,
|
|
14
|
+
title,
|
|
15
|
+
description,
|
|
16
|
+
children,
|
|
17
|
+
}: SettingItemProps) {
|
|
18
|
+
return (
|
|
19
|
+
<div className="flex items-center justify-between p-4 rounded-xl hover:bg-secondary/30 transition-colors">
|
|
20
|
+
<div className="flex gap-4">
|
|
21
|
+
<div className="w-10 h-10 rounded-xl bg-secondary flex items-center justify-center text-muted-foreground shrink-0">
|
|
22
|
+
{icon}
|
|
23
|
+
</div>
|
|
24
|
+
<div>
|
|
25
|
+
<h4 className="font-medium text-foreground">{title}</h4>
|
|
26
|
+
<p className="text-sm text-muted-foreground mt-0.5">{description}</p>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<div className="shrink-0 flex items-center h-full">{children}</div>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setting Section Component
|
|
3
|
+
*
|
|
4
|
+
* Reusable section wrapper for settings pages.
|
|
5
|
+
* Provides consistent styling and title display.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* <SettingSection title="Profile">
|
|
9
|
+
* <SettingItem label="Name" value={name} />
|
|
10
|
+
* </SettingSection>
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
"use client";
|
|
14
|
+
|
|
15
|
+
import React from "react";
|
|
16
|
+
import { cn } from "@/lib/utils";
|
|
17
|
+
|
|
18
|
+
interface SettingSectionProps {
|
|
19
|
+
/** Section title */
|
|
20
|
+
title: string;
|
|
21
|
+
/** Section content */
|
|
22
|
+
children: React.ReactNode;
|
|
23
|
+
/** Optional className override */
|
|
24
|
+
className?: string;
|
|
25
|
+
/** Optional title className override */
|
|
26
|
+
titleClassName?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function SettingSection({
|
|
30
|
+
title,
|
|
31
|
+
children,
|
|
32
|
+
className,
|
|
33
|
+
titleClassName,
|
|
34
|
+
}: SettingSectionProps) {
|
|
35
|
+
return (
|
|
36
|
+
<div className={cn("mb-8", className)}>
|
|
37
|
+
<h3
|
|
38
|
+
className={cn(
|
|
39
|
+
"text-xs font-bold uppercase tracking-widest text-muted-foreground mb-4",
|
|
40
|
+
titleClassName
|
|
41
|
+
)}
|
|
42
|
+
>
|
|
43
|
+
{title}
|
|
44
|
+
</h3>
|
|
45
|
+
<div className="bg-card border border-border/50 rounded-2xl overflow-hidden divide-y divide-border/50">
|
|
46
|
+
{children}
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pending invitations list component
|
|
3
|
+
* Displays pending invitations with actions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { type Invitation } from "@locusai/shared";
|
|
7
|
+
import { Copy, Mail, X } from "lucide-react";
|
|
8
|
+
import { Badge, Button } from "@/components/ui";
|
|
9
|
+
|
|
10
|
+
interface TeamInvitationsListProps {
|
|
11
|
+
invitations: Invitation[];
|
|
12
|
+
canManage: boolean;
|
|
13
|
+
onCopyLink: (token: string) => void;
|
|
14
|
+
onRevokeInvitation: (invitationId: string) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function TeamInvitationsList({
|
|
18
|
+
invitations,
|
|
19
|
+
canManage,
|
|
20
|
+
onCopyLink,
|
|
21
|
+
onRevokeInvitation,
|
|
22
|
+
}: TeamInvitationsListProps) {
|
|
23
|
+
if (invitations.length === 0) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<section className="space-y-4">
|
|
29
|
+
<div className="flex items-center justify-between px-1">
|
|
30
|
+
<h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider">
|
|
31
|
+
Pending Invitations ({invitations.length})
|
|
32
|
+
</h3>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div className="bg-card/50 border border-secondary/20 rounded-2xl overflow-hidden">
|
|
36
|
+
<div className="divide-y divide-secondary/20">
|
|
37
|
+
{invitations.map((invitation) => (
|
|
38
|
+
<div
|
|
39
|
+
key={invitation.id}
|
|
40
|
+
className="flex items-center justify-between p-4 hover:bg-secondary/10 transition-colors"
|
|
41
|
+
>
|
|
42
|
+
<div className="flex items-center gap-4">
|
|
43
|
+
<div className="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-primary">
|
|
44
|
+
<Mail size={20} />
|
|
45
|
+
</div>
|
|
46
|
+
<div>
|
|
47
|
+
<div className="font-medium">{invitation.email}</div>
|
|
48
|
+
<div className="text-sm text-muted-foreground">
|
|
49
|
+
Invited as{" "}
|
|
50
|
+
<span className="capitalize">
|
|
51
|
+
{invitation.role.toLowerCase()}
|
|
52
|
+
</span>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div className="flex items-center gap-2">
|
|
58
|
+
<Badge variant="warning" size="sm">
|
|
59
|
+
Pending
|
|
60
|
+
</Badge>
|
|
61
|
+
{canManage && (
|
|
62
|
+
<>
|
|
63
|
+
<Button
|
|
64
|
+
variant="ghost"
|
|
65
|
+
size="icon"
|
|
66
|
+
onClick={() => onCopyLink(invitation.token)}
|
|
67
|
+
className="text-muted-foreground"
|
|
68
|
+
title="Copy Invitation Link"
|
|
69
|
+
>
|
|
70
|
+
<Copy size={18} />
|
|
71
|
+
</Button>
|
|
72
|
+
<Button
|
|
73
|
+
variant="ghost"
|
|
74
|
+
size="icon"
|
|
75
|
+
onClick={() => onRevokeInvitation(invitation.id)}
|
|
76
|
+
className="text-muted-foreground hover:text-red-500 hover:bg-red-500/10"
|
|
77
|
+
title="Revoke Invitation"
|
|
78
|
+
>
|
|
79
|
+
<X size={18} />
|
|
80
|
+
</Button>
|
|
81
|
+
</>
|
|
82
|
+
)}
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
))}
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
</section>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team members list component
|
|
3
|
+
* Displays organization members with actions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { MembershipRole, type MembershipWithUser } from "@locusai/shared";
|
|
7
|
+
import { Shield, Trash2 } from "lucide-react";
|
|
8
|
+
import { Avatar, Badge, Button } from "@/components/ui";
|
|
9
|
+
|
|
10
|
+
interface TeamMembersListProps {
|
|
11
|
+
members: MembershipWithUser[];
|
|
12
|
+
currentUserId?: string;
|
|
13
|
+
canManage: boolean;
|
|
14
|
+
isLoading: boolean;
|
|
15
|
+
onRemoveMember: (userId: string) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function TeamMembersList({
|
|
19
|
+
members,
|
|
20
|
+
currentUserId,
|
|
21
|
+
canManage,
|
|
22
|
+
isLoading,
|
|
23
|
+
onRemoveMember,
|
|
24
|
+
}: TeamMembersListProps) {
|
|
25
|
+
if (isLoading) {
|
|
26
|
+
return (
|
|
27
|
+
<div className="p-8 text-center text-muted-foreground">Loading...</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (members.length === 0) {
|
|
32
|
+
return (
|
|
33
|
+
<div className="p-8 text-center text-muted-foreground">
|
|
34
|
+
No members found.
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div className="divide-y divide-secondary/20">
|
|
41
|
+
{members.map((membership) => (
|
|
42
|
+
<div
|
|
43
|
+
key={membership.id}
|
|
44
|
+
className="flex items-center justify-between p-4 hover:bg-secondary/10 transition-colors"
|
|
45
|
+
>
|
|
46
|
+
<div className="flex items-center gap-4">
|
|
47
|
+
<Avatar
|
|
48
|
+
src={membership.user.avatarUrl}
|
|
49
|
+
name={membership.user.name}
|
|
50
|
+
size="md"
|
|
51
|
+
/>
|
|
52
|
+
<div>
|
|
53
|
+
<div className="flex items-center gap-2">
|
|
54
|
+
<span className="font-medium">{membership.user.name}</span>
|
|
55
|
+
{membership.userId === currentUserId && (
|
|
56
|
+
<Badge variant="info" size="sm">
|
|
57
|
+
You
|
|
58
|
+
</Badge>
|
|
59
|
+
)}
|
|
60
|
+
</div>
|
|
61
|
+
<span className="text-sm text-muted-foreground">
|
|
62
|
+
{membership.user.email}
|
|
63
|
+
</span>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div className="flex items-center gap-6">
|
|
68
|
+
<div className="flex items-center gap-1.5 px-3 py-1 rounded-full bg-secondary/30 border border-secondary/20">
|
|
69
|
+
{membership.role === MembershipRole.OWNER ||
|
|
70
|
+
membership.role === MembershipRole.ADMIN ? (
|
|
71
|
+
<Shield size={14} className="text-primary" />
|
|
72
|
+
) : null}
|
|
73
|
+
<span className="text-xs font-medium capitalize">
|
|
74
|
+
{membership.role.toLowerCase()}
|
|
75
|
+
</span>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
{canManage &&
|
|
79
|
+
membership.userId !== currentUserId &&
|
|
80
|
+
membership.role !== MembershipRole.OWNER && (
|
|
81
|
+
<Button
|
|
82
|
+
variant="ghost"
|
|
83
|
+
size="icon"
|
|
84
|
+
onClick={() => onRemoveMember(membership.userId)}
|
|
85
|
+
className="text-muted-foreground hover:text-red-500 hover:bg-red-500/10"
|
|
86
|
+
>
|
|
87
|
+
<Trash2 size={18} />
|
|
88
|
+
</Button>
|
|
89
|
+
)}
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
))}
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./ApiKeyConfirmationModal";
|
|
2
|
+
export * from "./ApiKeyCreatedModal";
|
|
3
|
+
export * from "./ApiKeysList";
|
|
4
|
+
export * from "./ApiKeysSettings";
|
|
5
|
+
export * from "./InviteMemberModal";
|
|
6
|
+
export * from "./ProjectSetupGuide";
|
|
7
|
+
export * from "./SettingItem";
|
|
8
|
+
export * from "./SettingSection";
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { EventType, type Task, type Event as TaskEvent } from "@locusai/shared";
|
|
4
|
+
import { formatDistanceToNow } from "date-fns";
|
|
5
|
+
import {
|
|
6
|
+
CheckCircle,
|
|
7
|
+
Edit,
|
|
8
|
+
MessageSquare,
|
|
9
|
+
PlusSquare,
|
|
10
|
+
Tag,
|
|
11
|
+
} from "lucide-react";
|
|
12
|
+
import { MetadataText, SectionLabel } from "@/components/typography";
|
|
13
|
+
import { Button, EmptyState, Input } from "@/components/ui";
|
|
14
|
+
|
|
15
|
+
interface TaskActivityProps {
|
|
16
|
+
task: Task;
|
|
17
|
+
isLoading?: boolean;
|
|
18
|
+
newComment: string;
|
|
19
|
+
setNewComment: (val: string) => void;
|
|
20
|
+
handleAddComment: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function TaskActivity({
|
|
24
|
+
task,
|
|
25
|
+
isLoading = false,
|
|
26
|
+
newComment,
|
|
27
|
+
setNewComment,
|
|
28
|
+
handleAddComment,
|
|
29
|
+
}: TaskActivityProps) {
|
|
30
|
+
return (
|
|
31
|
+
<div>
|
|
32
|
+
<SectionLabel as="h4" className="mb-6 pb-2 border-b border-border/40">
|
|
33
|
+
Neural Stream
|
|
34
|
+
</SectionLabel>
|
|
35
|
+
|
|
36
|
+
<div className="flex gap-3 mb-6 bg-background/30 p-2 rounded-2xl border border-border/40 shadow-inner focus-within:border-primary/30 transition-all">
|
|
37
|
+
<Input
|
|
38
|
+
value={newComment}
|
|
39
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
40
|
+
!isLoading && setNewComment(e.target.value)
|
|
41
|
+
}
|
|
42
|
+
disabled={isLoading}
|
|
43
|
+
placeholder="Transmit logs..."
|
|
44
|
+
className="h-10 text-xs font-bold bg-transparent border-none focus:ring-0 placeholder:font-black placeholder:uppercase placeholder:text-[9px] placeholder:tracking-[0.2em]"
|
|
45
|
+
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
46
|
+
if (e.key === "Enter" && !isLoading) handleAddComment();
|
|
47
|
+
}}
|
|
48
|
+
/>
|
|
49
|
+
<Button
|
|
50
|
+
onClick={handleAddComment}
|
|
51
|
+
disabled={!newComment.trim() || isLoading}
|
|
52
|
+
variant="ghost"
|
|
53
|
+
className="h-10 w-10 p-0 rounded-xl hover:bg-primary/10 hover:text-primary transition-all group shrink-0"
|
|
54
|
+
>
|
|
55
|
+
<MessageSquare
|
|
56
|
+
size={16}
|
|
57
|
+
className="group-hover:rotate-12 transition-transform"
|
|
58
|
+
/>
|
|
59
|
+
</Button>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div className="space-y-10 max-h-[600px] overflow-y-auto pr-4 scrollbar-thin">
|
|
63
|
+
{task.activityLog.length > 0 ? (
|
|
64
|
+
task.activityLog.map((event: Task["activityLog"][number]) => (
|
|
65
|
+
<div key={event.id} className="relative flex gap-6 group">
|
|
66
|
+
<div className="absolute left-[19px] top-10 bottom-[-28px] w-px bg-border/40 group-last:hidden" />
|
|
67
|
+
<div className="h-10 w-10 rounded-2xl bg-card border border-border/60 flex items-center justify-center shrink-0 z-10 shadow-sm group-hover:border-primary/40 transition-all group-hover:scale-110">
|
|
68
|
+
{event.type === EventType.COMMENT_ADDED && (
|
|
69
|
+
<MessageSquare size={14} className="text-blue-500" />
|
|
70
|
+
)}
|
|
71
|
+
{event.type === EventType.STATUS_CHANGED && (
|
|
72
|
+
<Tag size={14} className="text-amber-500" />
|
|
73
|
+
)}
|
|
74
|
+
{event.type === EventType.TASK_CREATED && (
|
|
75
|
+
<PlusSquare size={14} className="text-emerald-400" />
|
|
76
|
+
)}
|
|
77
|
+
{event.type === EventType.TASK_UPDATED && (
|
|
78
|
+
<Edit size={14} className="text-primary" />
|
|
79
|
+
)}
|
|
80
|
+
{event.type === EventType.CI_RAN && (
|
|
81
|
+
<CheckCircle size={14} className="text-accent" />
|
|
82
|
+
)}
|
|
83
|
+
</div>
|
|
84
|
+
<div className="pt-2 min-w-0">
|
|
85
|
+
<p className="text-xs font-bold text-foreground/80 leading-snug mb-2">
|
|
86
|
+
{formatActivityEvent(event as TaskEvent)}
|
|
87
|
+
</p>
|
|
88
|
+
<MetadataText size="sm">
|
|
89
|
+
{formatDistanceToNow(new Date(event.createdAt), {
|
|
90
|
+
addSuffix: true,
|
|
91
|
+
})}
|
|
92
|
+
</MetadataText>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
))
|
|
96
|
+
) : (
|
|
97
|
+
<EmptyState
|
|
98
|
+
variant="minimal"
|
|
99
|
+
title="Silent Stream"
|
|
100
|
+
className="py-12 opacity-30"
|
|
101
|
+
/>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function formatActivityEvent(event: TaskEvent): string {
|
|
109
|
+
const { type, payload } = event;
|
|
110
|
+
const p = payload as TaskEvent["payload"];
|
|
111
|
+
switch (type) {
|
|
112
|
+
case EventType.STATUS_CHANGED:
|
|
113
|
+
return `Status moved ${p.oldStatus} ➟ ${p.newStatus}`;
|
|
114
|
+
case EventType.COMMENT_ADDED:
|
|
115
|
+
return `${p.author}: "${p.text}"`;
|
|
116
|
+
case EventType.TASK_CREATED:
|
|
117
|
+
return "Task initialized";
|
|
118
|
+
case EventType.TASK_UPDATED:
|
|
119
|
+
return "Parameters calibrated";
|
|
120
|
+
case EventType.TASK_DELETED:
|
|
121
|
+
return "Task deleted";
|
|
122
|
+
case EventType.CI_RAN:
|
|
123
|
+
return `Valuation complete: ${p.summary}`;
|
|
124
|
+
default:
|
|
125
|
+
return (type as string).replace(/_/g, " ").toLowerCase();
|
|
126
|
+
}
|
|
127
|
+
}
|