Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions ui/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ COPY package.json ./
# Copy library config files
COPY tsconfig.json ./
COPY rollup.config.mjs ./
COPY tailwind.config.js ./
COPY postcss.config.js ./

# Copy source files for the library
COPY src/ ./src/
Expand Down
162 changes: 93 additions & 69 deletions ui/example/app/routes/resource-history.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ import { EventDetailModal } from "~/components/EventDetailModal";
export default function ResourceHistoryPage() {
const [searchParams, setSearchParams] = useSearchParams();
const [client, setClient] = useState<ActivityApiClient | null>(null);
const [selectedActivity, setSelectedActivity] = useState<Activity | null>(null);
const [selectedActivity, setSelectedActivity] = useState<Activity | null>(
null,
);

// Read initial values from URL search params
const initialApiGroup = searchParams.get("apiGroup") || "";
Expand Down Expand Up @@ -66,7 +68,9 @@ export default function ResourceHistoryPage() {
}, [initialApiGroup, initialKind, initialNamespace, initialName, initialUid]);

// Submitted filter - initialized from URL params
const [submittedFilter, setSubmittedFilter] = useState<ResourceFilter | null>(filterFromParams);
const [submittedFilter, setSubmittedFilter] = useState<ResourceFilter | null>(
filterFromParams,
);

// Sync submitted filter when URL params change (e.g., browser back/forward)
useEffect(() => {
Expand All @@ -77,7 +81,14 @@ export default function ResourceHistoryPage() {
setNamespace(initialNamespace);
setName(initialName);
setUid(initialUid);
}, [filterFromParams, initialApiGroup, initialKind, initialNamespace, initialName, initialUid]);
}, [
filterFromParams,
initialApiGroup,
initialKind,
initialNamespace,
initialName,
initialUid,
]);

useEffect(() => {
// Check if in production environment
Expand All @@ -95,7 +106,7 @@ export default function ResourceHistoryPage() {
new ActivityApiClient({
baseUrl: apiUrl || "",
token,
})
}),
);
}
}, []);
Expand All @@ -119,76 +130,82 @@ export default function ResourceHistoryPage() {
} = useFacets(
client!,
{ start: "now-30d" },
currentFilters // Pass current selections to filter facet results
currentFilters, // Pass current selections to filter facet results
);

// Convert facets to combobox options
const apiGroupOptions: ComboboxOption[] = useMemo(() =>
apiGroups
.filter((f) => f.value)
.map((f) => ({
value: f.value,
label: f.value,
count: f.count,
})),
[apiGroups]
const apiGroupOptions: ComboboxOption[] = useMemo(
() =>
apiGroups
.filter((f) => f.value)
.map((f) => ({
value: f.value,
label: f.value,
count: f.count,
})),
[apiGroups],
);

const kindOptions: ComboboxOption[] = useMemo(() =>
resourceKinds
.filter((f) => f.value)
.map((f) => ({
value: f.value,
label: f.value,
count: f.count,
})),
[resourceKinds]
const kindOptions: ComboboxOption[] = useMemo(
() =>
resourceKinds
.filter((f) => f.value)
.map((f) => ({
value: f.value,
label: f.value,
count: f.count,
})),
[resourceKinds],
);

const namespaceOptions: ComboboxOption[] = useMemo(() =>
resourceNamespaces
.filter((f) => f.value)
.map((f) => ({
value: f.value,
label: f.value,
count: f.count,
})),
[resourceNamespaces]
const namespaceOptions: ComboboxOption[] = useMemo(
() =>
resourceNamespaces
.filter((f) => f.value)
.map((f) => ({
value: f.value,
label: f.value,
count: f.count,
})),
[resourceNamespaces],
);

const handleSubmit = useCallback((e: React.FormEvent) => {
e.preventDefault();
const filter: ResourceFilter = {};
const params = new URLSearchParams();
const handleSubmit = useCallback(
(e: React.FormEvent) => {
e.preventDefault();
const filter: ResourceFilter = {};
const params = new URLSearchParams();

if (uid.trim()) {
filter.uid = uid.trim();
params.set("uid", uid.trim());
} else {
if (apiGroup) {
filter.apiGroup = apiGroup;
params.set("apiGroup", apiGroup);
}
if (kind) {
filter.kind = kind;
params.set("kind", kind);
}
if (namespace) {
filter.namespace = namespace;
params.set("namespace", namespace);
if (uid.trim()) {
filter.uid = uid.trim();
params.set("uid", uid.trim());
} else {
if (apiGroup) {
filter.apiGroup = apiGroup;
params.set("apiGroup", apiGroup);
}
if (kind) {
filter.kind = kind;
params.set("kind", kind);
}
if (namespace) {
filter.namespace = namespace;
params.set("namespace", namespace);
}
if (name.trim()) {
filter.name = name.trim();
params.set("name", name.trim());
}
}
if (name.trim()) {
filter.name = name.trim();
params.set("name", name.trim());
}
}

// Only submit if we have at least one filter
if (Object.keys(filter).length > 0) {
setSubmittedFilter(filter);
setSearchParams(params, { replace: false });
}
}, [uid, apiGroup, kind, namespace, name, setSearchParams]);
// Only submit if we have at least one filter
if (Object.keys(filter).length > 0) {
setSubmittedFilter(filter);
setSearchParams(params, { replace: false });
}
},
[uid, apiGroup, kind, namespace, name, setSearchParams],
);

const handleActivityClick = useCallback((activity: Activity) => {
setSelectedActivity(activity);
Expand Down Expand Up @@ -320,7 +337,8 @@ export default function ResourceHistoryPage() {
disabled={isAttributeMode}
/>
<p className="text-xs text-muted-foreground">
UID provides exact match. When specified, other filters are ignored.
UID provides exact match. When specified, other filters are
ignored.
</p>
</div>
</div>
Expand All @@ -336,18 +354,22 @@ export default function ResourceHistoryPage() {
</h3>
<ul className="space-y-2 text-sm text-muted-foreground list-disc list-inside">
<li>
Dropdowns <strong>filter automatically</strong> based on other selections
Dropdowns <strong>filter automatically</strong> based on other
selections
</li>
<li>
<strong>Name</strong> supports partial matching (e.g., "api" matches "api-gateway")
<strong>Name</strong> supports partial matching (e.g., "api"
matches "api-gateway")
</li>
<li>
Combine filters to narrow down results (e.g., Kind + Namespace)
Combine filters to narrow down results (e.g., Kind +
Namespace)
</li>
<li>
Find a resource's UID with:{" "}
<code className="px-1 py-0.5 bg-muted rounded text-xs">
kubectl get &lt;kind&gt; &lt;name&gt; -o jsonpath='{"{.metadata.uid}"}'
kubectl get &lt;kind&gt; &lt;name&gt; -o jsonpath='
{"{.metadata.uid}"}'
</code>
</li>
</ul>
Expand All @@ -369,8 +391,10 @@ export default function ResourceHistoryPage() {
{[
submittedFilter.kind,
submittedFilter.name,
submittedFilter.namespace && `in ${submittedFilter.namespace}`,
submittedFilter.apiGroup && `(${submittedFilter.apiGroup})`,
submittedFilter.namespace &&
`in ${submittedFilter.namespace}`,
submittedFilter.apiGroup &&
`(${submittedFilter.apiGroup})`,
]
.filter(Boolean)
.join(" ")}
Expand Down
12 changes: 4 additions & 8 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"directory": "ui"
},
"peerDependencies": {
"@datum-cloud/datum-ui": "^0.8.0",
"@monaco-editor/react": "^4.6.0",
"@radix-ui/react-checkbox": "^1.0.0",
"@radix-ui/react-dialog": "^1.0.0",
Expand All @@ -56,17 +57,16 @@
"react-dom": "^18.0.0 || ^19.0.0"
},
"devDependencies": {
"@datum-cloud/datum-ui": "^0.8.0",
"@monaco-editor/react": "^4.6.0",
"@playwright/test": "^1.48.0",
"@rollup/plugin-commonjs": "^29.0.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-typescript": "^11.1.6",
"@tailwindcss/postcss": "^4.2.1",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^6.15.0",
"@typescript-eslint/parser": "^6.15.0",
"autoprefixer": "^10.4.27",
"eslint": "^8.56.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
Expand All @@ -75,18 +75,14 @@
"react-dom": "^19.0.0",
"rollup": "^4.9.1",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-postcss": "^4.0.2",
"tailwindcss": "^4.2.1",
"tslib": "^2.6.2",
"typescript": "^5.3.3"
},
"dependencies": {
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"date-fns": "^3.0.6",
"js-yaml": "^4.1.1",
"date-fns": "^4.1.0",
"lucide-react": "^0.577.0",
"tailwind-merge": "^3.4.0",
"tailwindcss-animate": "^1.0.7"
"tailwind-merge": "^3.4.0"
}
}
Loading
Loading