@checkstack/catalog-frontend 0.10.6 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +157 -0
- package/package.json +16 -15
- package/src/api.ts +6 -1
- package/src/components/CatalogConfigPage.tsx +337 -271
- package/src/components/CatalogPage.tsx +172 -11
- package/src/components/EnvironmentEditor.tsx +220 -0
- package/src/components/EnvironmentPreviewPicker.tsx +61 -0
- package/src/components/SystemDetailPage.tsx +47 -34
- package/src/components/SystemEditor.tsx +6 -0
- package/src/components/SystemEnvironmentsEditor.tsx +98 -0
- package/src/components/browse/CatalogBrowseHealth.tsx +36 -0
- package/src/components/browse/CatalogBrowseToolbar.tsx +173 -0
- package/src/components/browse/CatalogGroupSection.tsx +165 -0
- package/src/components/browse/CatalogSystemRow.tsx +63 -0
- package/src/components/browse/browseState.logic.test.ts +125 -0
- package/src/components/browse/browseState.logic.ts +158 -0
- package/src/components/browse/filterEntities.logic.test.ts +479 -0
- package/src/components/browse/filterEntities.logic.ts +360 -0
- package/src/components/browse/healthRollup.logic.test.ts +126 -0
- package/src/components/browse/healthRollup.logic.ts +120 -0
- package/src/components/browse/healthStatuses.logic.test.ts +39 -0
- package/src/components/browse/healthStatuses.logic.ts +29 -0
- package/src/components/environment-fields.logic.test.ts +111 -0
- package/src/components/environment-fields.logic.ts +98 -0
- package/src/components/environment-preview.logic.test.ts +76 -0
- package/src/components/environment-preview.logic.ts +61 -0
- package/src/components/manage/AssignMenu.tsx +78 -0
- package/src/components/manage/EnvironmentsTab.tsx +230 -0
- package/src/components/manage/GroupsTab.tsx +274 -0
- package/src/components/manage/SystemsTab.tsx +430 -0
- package/src/hooks/useCatalogBrowseState.ts +107 -0
- package/src/hooks/useDebouncedValue.ts +21 -0
- package/src/index.tsx +32 -20
- package/src/utils/formatDate.logic.test.ts +44 -0
- package/src/utils/formatDate.logic.ts +27 -0
- package/src/utils/normalizeMetadata.logic.test.ts +67 -0
- package/src/utils/normalizeMetadata.logic.ts +53 -0
- package/src/components/DraggableSystem.tsx +0 -200
- package/src/components/DroppableGroup.tsx +0 -174
- package/src/components/UserMenuItems.tsx +0 -31
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import { useDroppable } from "@dnd-kit/core";
|
|
2
|
-
import { EditableText, Button, cn, usePerformance } from "@checkstack/ui";
|
|
3
|
-
import { Trash2 } from "lucide-react";
|
|
4
|
-
import {
|
|
5
|
-
useProvenanceLock,
|
|
6
|
-
useProvenanceLocks,
|
|
7
|
-
GitOpsSourceBadge,
|
|
8
|
-
} from "@checkstack/gitops-frontend";
|
|
9
|
-
import type { Group, System } from "../api";
|
|
10
|
-
|
|
11
|
-
interface DroppableGroupProps {
|
|
12
|
-
group: Group;
|
|
13
|
-
systems: System[];
|
|
14
|
-
isOver: boolean;
|
|
15
|
-
isDragging: boolean;
|
|
16
|
-
draggingSystemAlreadyInGroup: boolean;
|
|
17
|
-
newlyAddedSystemId?: string;
|
|
18
|
-
onDeleteGroup: (id: string) => void;
|
|
19
|
-
onUpdateGroupName: (id: string, name: string) => void;
|
|
20
|
-
onRemoveSystem: (groupId: string, systemId: string) => void;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* A droppable group card for the Catalog Management page.
|
|
25
|
-
*
|
|
26
|
-
* When a system is being dragged over, the card highlights. If the system
|
|
27
|
-
* is already assigned to this group, the drop zone shows a "Already in group"
|
|
28
|
-
* indicator and the drop is blocked visually.
|
|
29
|
-
*/
|
|
30
|
-
export const DroppableGroup = ({
|
|
31
|
-
group,
|
|
32
|
-
systems,
|
|
33
|
-
isOver,
|
|
34
|
-
isDragging,
|
|
35
|
-
draggingSystemAlreadyInGroup,
|
|
36
|
-
newlyAddedSystemId,
|
|
37
|
-
onDeleteGroup,
|
|
38
|
-
onUpdateGroupName,
|
|
39
|
-
onRemoveSystem,
|
|
40
|
-
}: DroppableGroupProps) => {
|
|
41
|
-
const { isLowPower } = usePerformance();
|
|
42
|
-
const { setNodeRef } = useDroppable({ id: group.id });
|
|
43
|
-
|
|
44
|
-
const { isLocked, provenance } = useProvenanceLock({
|
|
45
|
-
kind: "Group",
|
|
46
|
-
entityId: group.id,
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
const { getLock } = useProvenanceLocks();
|
|
50
|
-
|
|
51
|
-
const groupSystems = (group.systemIds ?? [])
|
|
52
|
-
.map((sysId) => systems.find((s) => s.id === sysId))
|
|
53
|
-
.filter((sys): sys is System => !!sys);
|
|
54
|
-
|
|
55
|
-
const dropzoneActive = isDragging;
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<div
|
|
59
|
-
ref={setNodeRef}
|
|
60
|
-
className={cn(
|
|
61
|
-
"p-3 rounded-lg border space-y-2",
|
|
62
|
-
!isLowPower && "transition-all duration-150",
|
|
63
|
-
isOver && !draggingSystemAlreadyInGroup
|
|
64
|
-
? "border-primary bg-primary/5 shadow-md shadow-primary/10"
|
|
65
|
-
: isOver && draggingSystemAlreadyInGroup
|
|
66
|
-
? "border-muted-foreground/40 bg-muted/10"
|
|
67
|
-
: dropzoneActive
|
|
68
|
-
? "border-border/60 bg-muted/20 border-dashed"
|
|
69
|
-
: "border-border bg-muted/30",
|
|
70
|
-
)}
|
|
71
|
-
>
|
|
72
|
-
{/* Group header */}
|
|
73
|
-
<div className="flex items-center justify-between">
|
|
74
|
-
<div className="flex items-center gap-2 flex-1">
|
|
75
|
-
{isLocked && provenance && (
|
|
76
|
-
<GitOpsSourceBadge provenance={provenance} />
|
|
77
|
-
)}
|
|
78
|
-
<div className="flex-1">
|
|
79
|
-
<EditableText
|
|
80
|
-
value={group.name}
|
|
81
|
-
onSave={(newName) => onUpdateGroupName(group.id, newName)}
|
|
82
|
-
className="font-medium text-foreground"
|
|
83
|
-
disabled={isLocked}
|
|
84
|
-
/>
|
|
85
|
-
<p className="text-xs text-muted-foreground font-mono">{group.id}</p>
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|
|
88
|
-
<Button
|
|
89
|
-
variant="ghost"
|
|
90
|
-
className="text-destructive hover:text-destructive/90 hover:bg-destructive/10 h-8 w-8 p-0"
|
|
91
|
-
onClick={() => onDeleteGroup(group.id)}
|
|
92
|
-
disabled={isLocked}
|
|
93
|
-
title={isLocked ? "Managed by GitOps" : undefined}
|
|
94
|
-
aria-label={`Delete group ${group.name}`}
|
|
95
|
-
>
|
|
96
|
-
<Trash2 className="w-4 h-4" />
|
|
97
|
-
</Button>
|
|
98
|
-
</div>
|
|
99
|
-
|
|
100
|
-
{/* Drop zone label */}
|
|
101
|
-
{isOver && (
|
|
102
|
-
<div
|
|
103
|
-
className={`text-xs text-center py-1 rounded transition-colors ${
|
|
104
|
-
draggingSystemAlreadyInGroup
|
|
105
|
-
? "text-muted-foreground"
|
|
106
|
-
: "text-primary font-medium"
|
|
107
|
-
}`}
|
|
108
|
-
>
|
|
109
|
-
{draggingSystemAlreadyInGroup
|
|
110
|
-
? "Already in this group"
|
|
111
|
-
: "Drop to add"}
|
|
112
|
-
</div>
|
|
113
|
-
)}
|
|
114
|
-
|
|
115
|
-
{/* Systems in this group */}
|
|
116
|
-
{groupSystems.length > 0 ? (
|
|
117
|
-
<div className="pl-2 space-y-1">
|
|
118
|
-
{groupSystems.map((sys) => {
|
|
119
|
-
const isNew = newlyAddedSystemId === sys.id;
|
|
120
|
-
const systemLock = getLock({ kind: "System", entityId: sys.id });
|
|
121
|
-
const systemLocked = systemLock.isLocked;
|
|
122
|
-
return (
|
|
123
|
-
<div
|
|
124
|
-
key={sys.id}
|
|
125
|
-
className={cn(
|
|
126
|
-
"flex items-center justify-between text-sm bg-background p-2 rounded border",
|
|
127
|
-
!isLowPower && "transition-all duration-700",
|
|
128
|
-
isNew
|
|
129
|
-
? "border-green-500/60 shadow-sm shadow-green-500/30"
|
|
130
|
-
: "border-border shadow-none",
|
|
131
|
-
)}
|
|
132
|
-
>
|
|
133
|
-
<span className="text-foreground truncate flex items-center gap-1.5">
|
|
134
|
-
{systemLocked && systemLock.provenance ? (
|
|
135
|
-
<GitOpsSourceBadge
|
|
136
|
-
provenance={systemLock.provenance}
|
|
137
|
-
iconClassName="w-3 h-3 text-primary"
|
|
138
|
-
/>
|
|
139
|
-
) : null}
|
|
140
|
-
{sys.name}
|
|
141
|
-
</span>
|
|
142
|
-
<Button
|
|
143
|
-
variant="ghost"
|
|
144
|
-
className="text-destructive/60 hover:text-destructive h-6 w-6 p-0 flex-shrink-0"
|
|
145
|
-
onClick={() => onRemoveSystem(group.id, sys.id)}
|
|
146
|
-
disabled={systemLocked}
|
|
147
|
-
title={
|
|
148
|
-
systemLocked
|
|
149
|
-
? "Managed by GitOps"
|
|
150
|
-
: `Remove ${sys.name} from ${group.name}`
|
|
151
|
-
}
|
|
152
|
-
aria-label={`Remove ${sys.name} from ${group.name}`}
|
|
153
|
-
>
|
|
154
|
-
<Trash2 className="w-3 h-3" />
|
|
155
|
-
</Button>
|
|
156
|
-
</div>
|
|
157
|
-
);
|
|
158
|
-
})}
|
|
159
|
-
</div>
|
|
160
|
-
) : (
|
|
161
|
-
/* Empty drop zone hint */
|
|
162
|
-
<div
|
|
163
|
-
className={`text-xs text-center py-3 rounded border border-dashed transition-colors ${
|
|
164
|
-
dropzoneActive
|
|
165
|
-
? "border-primary/40 text-primary/60"
|
|
166
|
-
: "border-border text-muted-foreground/60"
|
|
167
|
-
}`}
|
|
168
|
-
>
|
|
169
|
-
{dropzoneActive ? "Drag a system here" : "No systems assigned"}
|
|
170
|
-
</div>
|
|
171
|
-
)}
|
|
172
|
-
</div>
|
|
173
|
-
);
|
|
174
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Link } from "react-router-dom";
|
|
3
|
-
import { Settings } from "lucide-react";
|
|
4
|
-
import type { UserMenuItemsContext } from "@checkstack/frontend-api";
|
|
5
|
-
import { DropdownMenuItem } from "@checkstack/ui";
|
|
6
|
-
import { resolveRoute } from "@checkstack/common";
|
|
7
|
-
import {
|
|
8
|
-
catalogRoutes,
|
|
9
|
-
catalogAccess,
|
|
10
|
-
pluginMetadata,
|
|
11
|
-
} from "@checkstack/catalog-common";
|
|
12
|
-
|
|
13
|
-
export const CatalogUserMenuItems = ({
|
|
14
|
-
accessRules: userPerms,
|
|
15
|
-
}: UserMenuItemsContext) => {
|
|
16
|
-
// Use the access rule's id directly
|
|
17
|
-
const qualifiedId = `${pluginMetadata.pluginId}.${catalogAccess.system.manage.id}`;
|
|
18
|
-
const canManage = userPerms.includes("*") || userPerms.includes(qualifiedId);
|
|
19
|
-
|
|
20
|
-
if (!canManage) {
|
|
21
|
-
return <React.Fragment />;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<Link to={resolveRoute(catalogRoutes.routes.config)}>
|
|
26
|
-
<DropdownMenuItem icon={<Settings className="h-4 w-4" />}>
|
|
27
|
-
Catalog Settings
|
|
28
|
-
</DropdownMenuItem>
|
|
29
|
-
</Link>
|
|
30
|
-
);
|
|
31
|
-
};
|