= ({
id: 'workspace-kind-podconfig-resource',
}}
titleDescription={
-
- Optional: Configure k8s Pod Resource Requests & Limits
-
+
+ Optional: Configure k8s Pod Resource Requests & Limits.
+
}
/>
}
@@ -190,7 +194,7 @@ export const WorkspaceKindFormPodConfigResource: React.FC = ({
value={cpu.request}
onChange={(value) => handleChange('cpu', 'request', value)}
placeholder="e.g. 1"
- min={0}
+ min={1}
aria-label="CPU request"
isDisabled={!cpuRequestEnabled}
/>
@@ -201,7 +205,7 @@ export const WorkspaceKindFormPodConfigResource: React.FC = ({
value={memory.request}
onChange={(value) => handleChange('memory', 'request', value)}
placeholder="e.g. 512Mi"
- min={0}
+ min={1}
aria-label="Memory request"
isDisabled={!memoryRequestEnabled}
/>
@@ -232,7 +236,7 @@ export const WorkspaceKindFormPodConfigResource: React.FC = ({
value={cpu.limit}
onChange={(value) => handleChange('cpu', 'limit', value)}
placeholder="e.g. 2"
- min={0}
+ min={parseFloat(cpu.request)}
step={1}
aria-label="CPU limit"
isDisabled={!cpuRequestEnabled || !cpuLimitEnabled}
@@ -244,7 +248,7 @@ export const WorkspaceKindFormPodConfigResource: React.FC = ({
value={memory.limit}
onChange={(value) => handleChange('memory', 'limit', value)}
placeholder="e.g. 1Gi"
- min={0}
+ min={parseFloat(memory.request)}
aria-label="Memory limit"
isDisabled={!memoryRequestEnabled || !memoryLimitEnabled}
/>
@@ -278,7 +282,7 @@ export const WorkspaceKindFormPodConfigResource: React.FC = ({
value={res.request}
onChange={(value) => handleChange(res.type, 'request', value)}
placeholder="Request"
- min={0}
+ min={1}
aria-label="Custom resource request"
/>
@@ -287,7 +291,10 @@ export const WorkspaceKindFormPodConfigResource: React.FC = ({
id={`custom-limit-switch-${idx}`}
label="Set Limit"
isChecked={customLimitsEnabled[idx] || false}
- onChange={(_event, checked) => handleCustomLimitToggle(idx, checked)}
+ onChange={(_event, checked) => {
+ handleChange(res.type, 'limit', res.request);
+ handleCustomLimitToggle(idx, checked);
+ }}
aria-label={`Enable limit for ${res.type || 'custom resource'}`}
/>
@@ -297,7 +304,7 @@ export const WorkspaceKindFormPodConfigResource: React.FC = ({
value={res.limit}
onChange={(value) => handleChange(res.type, 'limit', value)}
placeholder="Limit"
- min={0}
+ min={parseFloat(res.request)}
isDisabled={!customLimitsEnabled[idx]}
aria-label={`${res.type || 'Custom resource'} limit`}
/>
diff --git a/workspaces/frontend/src/app/routes.ts b/workspaces/frontend/src/app/routes.ts
index ee0cf4d5..146b6686 100644
--- a/workspaces/frontend/src/app/routes.ts
+++ b/workspaces/frontend/src/app/routes.ts
@@ -6,6 +6,7 @@ export const AppRoutePaths = {
workspaceKinds: '/workspacekinds',
workspaceKindSummary: '/workspacekinds/:kind/summary',
workspaceKindCreate: '/workspacekinds/create',
+ workspaceKindEdit: '/workspacekinds/edit',
} satisfies Record;
export type AppRoute = (typeof AppRoutePaths)[keyof typeof AppRoutePaths];
@@ -31,6 +32,7 @@ export type RouteParamsMap = {
kind: string;
};
workspaceKindCreate: undefined;
+ workspaceKindEdit: undefined;
};
/**
@@ -62,6 +64,10 @@ export type RouteStateMap = {
workspaceKindCreate: {
namespace: string;
};
+ workspaceKindEdit: {
+ namespace: string;
+ workspaceKindName: string;
+ };
};
/**
@@ -82,4 +88,5 @@ export type RouteSearchParamsMap = {
workspaceKinds: undefined;
workspaceKindSummary: undefined;
workspaceKindCreate: undefined;
+ workspaceKindEdit: undefined;
};
diff --git a/workspaces/frontend/src/shared/utilities/WorkspaceUtils.ts b/workspaces/frontend/src/shared/utilities/WorkspaceUtils.ts
index a732b4af..bf90b549 100644
--- a/workspaces/frontend/src/shared/utilities/WorkspaceUtils.ts
+++ b/workspaces/frontend/src/shared/utilities/WorkspaceUtils.ts
@@ -13,6 +13,30 @@ export enum YesNoValue {
No = 'No',
}
+const RESOURCE_UNIT_CONFIG = {
+ cpu: CPU_UNITS,
+ memory: MEMORY_UNITS_FOR_PARSING,
+ gpu: OTHER,
+};
+
+export const parseResourceValue = (
+ value: string,
+ resourceType: ResourceType,
+): [number | undefined, { name: string; unit: string } | undefined] => {
+ const units = RESOURCE_UNIT_CONFIG[resourceType];
+ return splitValueUnit(value, units);
+};
+
+export const extractNumericValue = (value: string, resourceType: ResourceType): string => {
+ const [numericValue] = parseResourceValue(value, resourceType);
+ return String(numericValue || '');
+};
+
+export const extractUnit = (value: string, resourceType: ResourceType): string => {
+ const [, unit] = parseResourceValue(value, resourceType);
+ return unit?.unit || '';
+};
+
export const extractResourceValue = (
workspace: Workspace,
resourceType: ResourceType,
@@ -24,18 +48,13 @@ export const formatResourceValue = (v: string | undefined, resourceType?: Resour
if (v === undefined) {
return '-';
}
- switch (resourceType) {
- case 'cpu': {
- const [cpuValue, cpuUnit] = splitValueUnit(v, CPU_UNITS);
- return `${cpuValue ?? ''} ${cpuUnit.name}`;
- }
- case 'memory': {
- const [memoryValue, memoryUnit] = splitValueUnit(v, MEMORY_UNITS_FOR_PARSING);
- return `${memoryValue ?? ''} ${memoryUnit.name}`;
- }
- default:
- return v;
+
+ if (!resourceType) {
+ return v;
}
+
+ const [value, unit] = parseResourceValue(v, resourceType);
+ return `${value || ''} ${unit?.name || ''}`.trim();
};
export const formatResourceFromWorkspace = (