kubeflow / kubeflow/notebooks

bug: Dynamic filter rules on PodConfig cause flickering or incorrectly reveal hidden options

Open
#1,353 12 comments 0 reactions 1 assignee Assigned to @thisis-Shitanshu View on GitHub
kind/bug priority/needs-triage
Dominant language
No language data
Stars
84
Forks
149
Avg merge
5d 15h
Merged PRs (30d)
29

Description

### Checks

- [x] I have searched the [existing issues](https://github.com/kubeflow/notebooks/issues).
- [x] My issue is related to one of the components in the [`kubeflow/notebooks`](https://github.com/kubeflow/notebooks) repository.

### Kubeflow Notebooks Version

v2.0.0-beta.0

### Kubeflow Platform

Kubeflow Distributions

### Kubernetes Distribution

GKE

### Kubernetes Version

```shell
Client Version: v1.36.1
Kustomize Version: v5.8.1
Server Version: v1.35.6-gke.1258000
```

### Description

### **What happened?**

When defining a `filterRule` on `WorkspaceKind` to hide non-GPU `podConfigs` when a CUDA image is selected:

1. **Infinite Re-render Loop / UI Flickering with `api.hide: true`:**
When using both `ui.hide: true` and `api.hide: true` in the rule, selecting a CUDA image in the Spawner UI causes the form to flicker rapidly and get stuck in an infinite state update loop. The user is unable to select the remaining GPU pod config or proceed to create a workspace.

2. **Hidden PodConfigs Automatically Revealed with only `ui.hide: true`:**
When removing `api.hide: true` (relying only on `ui.hide: true`), user can proceed to create the GPU workspace, but the default CPU pod configs are not hidden in the UI even though the user has not selected "Show hidden". The "Show hidden" filter is automatically enabled.

---

### **What did you expect to happen?**

1. Selecting a CUDA image should cleanly filter the pod configs so that only compatible GPU pod configs are shown (and selectable) without causing UI flickering or infinite re-renders.
2. If `ui.hide: true` is set on CPU configs for a CUDA image, those CPU configs should remain hidden by default unless the user explicitly checks "Show hidden".

---

### **How to reproduce it?**

1. add the following `filterRules` in `kubeflow-notebooks/workspaces/controller/manifests/kustomize/samples/jupyterlab_v1beta1_workspacekind.yaml`:

```yaml
- scope: POD_CONFIG
effect:
ui:
hide: true
api:
hide: true
match:
- matchImageConfig:
selector:
matchExpressions:
- key: "cuda_version"
operator: Exists
- matchPodConfig:
selector:
matchExpressions:
- key: "gpu"
operator: DoesNotExist
```

2. Open the Workspace Spawner UI (`/workspaces/form/create`).
3. In Step 1, select the `jupyterlab` WorkspaceKind.
4. In Step 2, select the CUDA image (`jupyter-pytorch-cuda-full:v1.10.0`) and click **Next**.
5. **Observe Behavior 1**: The UI starts flickering indefinitely and pod config cards cannot be selected.

Image

6. Remove `api.hide: true` from the `filterRules` and reload the form.
7. Select the CUDA image and proceed to Step 3.
8. **Observe Behavior 2**: "Tiny CPU" is shown in the list by default even though the rule specifies `ui.hide: true` and the user did not check "Show hidden".
---

### **Root Cause Analysis (Generated by Gemini)**

#### 1. Infinite Loop in `WorkspaceForm.tsx` (Triggered when `api.hide: true`)
- In `WorkspaceForm.tsx`:
- **Effect 1 (Defaulting)** sets `podConfig` to `allValuesData.podConfig.default` (`tiny_cpu`) whenever `!data.podConfig`:
```tsx
useEffect(() => {
if (!allValuesData || !allValuesLoaded || !data.kind) return;
if (!data.podConfig && allValuesData.podConfig.default) {
setData('podConfig', allValuesData.podConfig.default);
}
}, [allValuesData, allValuesLoaded, data.kind, data.imageConfig, data.podConfig, setData]);
```
- **Effect 2 (Validation)** clears `data.podConfig` when `filteredValuesData` arrives and the selected pod config is no longer valid:
```tsx
useEffect(() => {
if (!filteredValuesLoaded || !filteredValuesData || !data.podConfig) return;
const podConfigOptions = filteredValuesData.podConfig.values ?? [];
const isStillValid = podConfigOptions.some((pc) => pc.id === data.podConfig);
if (!isStillValid) {
setData('podConfig', undefined);
}
}, [filteredValuesData, filteredValuesLoaded, data.podConfig, setData]);
```
- When `api.hide: true` removes `tiny_cpu` from `filteredValuesData`, Effect 2 sets `data.podConfig = undefined`. Because `data.podConfig` is in Effect 1's dependencies, Effect 1 immediately sets it back to `"tiny_cpu"`, which re-triggers Effect 2, creating an endless ping-pong re-render loop (`undefined` $\leftrightarrow$ `"tiny_cpu"`).

#### 2. Auto-enabling "Show hidden" in `filterDefaults.ts` (Triggered when only `ui.hide: true`)
- In `WorkspaceFormPodConfigSelection.tsx` and `filterDefaults.ts`:
```ts
export const computeDefaultFilterValues = (options, defaultId) => {
const defaultOption = options.find((opt) => opt.id === defaultId);
return {
showHidden: defaultOption?.hidden ?? false,
showRedirected: defaultOption?.redirect !== undefined,
};
};
```
- Because the backend returns the static default ID (`tiny_cpu`), and `tiny_cpu` has `hidden: true` due to `ui.hide`, `computeDefaultFilterValues` sets `showHidden: true` by default.
- Additionally, `selectedPodConfig` is initially set to `tiny_cpu` (which is `hidden: true`), forcing `showHidden = true`.

#### 3. Backend `/listvalues` returns static default
- In `workspaces/backend/internal/models/workspacekinds/podtemplate/options/funcs.go`, `/listvalues` statically returns `wsk.Spec.PodTemplate.Options.PodConfig.Spawner.Default` without validating if that default option was hidden or removed by filter rules in the requested context.

### Relevant Logs

```shell

```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.