Skip to content

Commit

Permalink
Initial state for handling multiple defaults. (#5881)
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Nelson <minelson@vmware.com>

<!--
Before you open the request please review the following guidelines and
tips to help it be more easily integrated:

 - Describe the scope of your change - i.e. what the change does.
 - Describe any known limitations with your change.
- Please run any tests or examples that can exercise your modified code.

 Thank you for contributing!
 -->

### Description of the change

<!-- Describe the scope of your change - i.e. what the change does. -->
Adds an example chart (which can later be used in CI) and the background
state work to support switching the selected default values for charts
that support it.

### Benefits

<!-- What benefits will be realized by the code change? -->
Next PR can focus on the UI work.

### Possible drawbacks

<!-- Describe any known limitations with your change -->

### Applicable issues

<!-- Enter any applicable Issues here (You can reference an issue using
#) -->

- Ref #5692 

### Additional information

<!-- If there's anything else that's important and relevant to your pull
request, mention that information here.-->

Signed-off-by: Michael Nelson <minelson@vmware.com>
  • Loading branch information
absoludity committed Jan 17, 2023
1 parent 3c61fee commit 4fef0c8
Show file tree
Hide file tree
Showing 14 changed files with 334 additions and 3 deletions.
1 change: 1 addition & 0 deletions .yamllint.yml
Expand Up @@ -8,6 +8,7 @@ ignore: |
**/chart/kubeapps/
**/integration/charts/simplechart/
**/integration/charts/simplechart-customvalues/
**/integration/charts/simplechart-multicustomvalues/
**/dashboard/node_modules/
**/devel/
# Ignore files
Expand Down
9 changes: 9 additions & 0 deletions dashboard/src/actions/availablepackages.ts
Expand Up @@ -59,6 +59,14 @@ export const receiveSelectedAvailablePackageDetail = createAction(
// Reset action
export const resetSelectedAvailablePackageDetail = createAction("RESET_PACKAGE_VERSION");

// Set custom defaults action
export const setAvailablePackageDetailCustomDefaults = createAction(
"SET_AVAILABLE_PACKAGE_DETAIL_CUSTOM_DEFAULTS",
resolve => {
return (customDefault: string) => resolve({ customDefault });
},
);

// Request action
export const requestSelectedAvailablePackageVersions = createAction(
"REQUEST_SELECTED_AVAILABLE_PACKAGE_VERSIONS",
Expand Down Expand Up @@ -91,6 +99,7 @@ const allActions = [
resetAvailablePackageSummaries,
requestSelectedAvailablePackageDetail,
receiveSelectedAvailablePackageDetail,
setAvailablePackageDetailCustomDefaults,
resetSelectedAvailablePackageDetail,
requestSelectedAvailablePackageVersions,
receiveSelectedAvailablePackageVersions,
Expand Down
@@ -1,6 +1,7 @@
// Copyright 2019-2022 the Kubeapps contributors.
// SPDX-License-Identifier: Apache-2.0

import actions from "actions";
import { CdsButton } from "@cds/react/button";
import { CdsControlMessage } from "@cds/react/forms";
import { CdsIcon } from "@cds/react/icon";
Expand All @@ -11,7 +12,7 @@ import LoadingWrapper from "components/LoadingWrapper";
import Tabs from "components/Tabs";
import { isEmpty } from "lodash";
import { FormEvent, RefObject, useCallback, useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { useDispatch, useSelector } from "react-redux";
import {
retrieveBasicFormParams,
schemaToObject,
Expand Down Expand Up @@ -63,6 +64,8 @@ function DeploymentFormBody({
config: { featureFlags },
} = useSelector((state: IStoreState) => state);

const dispatch = useDispatch();

// Component state
const [paramsFromComponentState, setParamsFromComponentState] = useState([] as IBasicFormParam[]);
const [valuesFromTheAvailablePackageNodes, setValuesFromTheAvailablePackageNodes] = useState(
Expand All @@ -86,6 +89,7 @@ function DeploymentFormBody({
const [isLoading, setIsLoading] = useState(true);
const [unsavedChangesMap] = useState(new Map<string, any>());
const [shouldSubmitForm, setShouldSubmitForm] = useState(false);
const [selectedDefaults] = useState("");

// whenever the parsed values change (for instance, when a new pkg version is selected),
// we need to force a new extraction of the params from the schema
Expand Down Expand Up @@ -170,6 +174,11 @@ function DeploymentFormBody({
}
}, [formRef, shouldSubmitForm]);

// When multiple defaults are available and one is selected.
useEffect(() => {
dispatch(actions.availablepackages.setAvailablePackageDetailCustomDefaults(selectedDefaults));
}, [dispatch, selectedDefaults]);

// for each unsaved change in the component state, we need to update the values,
// so that both the table and the yaml editor get the updated values
const saveAllChanges = () => {
Expand Down
92 changes: 91 additions & 1 deletion dashboard/src/reducers/availablepackages.test.ts
Expand Up @@ -10,7 +10,7 @@ import { Plugin } from "gen/kubeappsapis/core/plugins/v1alpha1/plugins";
import { getType } from "typesafe-actions";
import actions from "../actions";
import { IPackageState, IReceivePackagesActionPayload } from "../shared/types";
import packageReducer from "./availablepackages";
import packageReducer, { defaultValues } from "./availablepackages";
import { PackagesAction } from "../actions/availablepackages";

const nextPageToken = "nextPageToken";
Expand Down Expand Up @@ -554,4 +554,94 @@ describe("packageReducer", () => {
expect(state.selected.values).toEqual("default: values");
});
});

describe("setAvailablePackageDetailCustomDefaults", () => {
it("sets the custom default", () => {
const packageWithCustomDefaults = {
...initialState,
selected: {
...initialState.selected,
availablePackageDetail: {
...initialState.selected.availablePackageDetail!,
additionalDefaultValues: {
"values-custom": "custom: values",
"values-other": "more: customdefaultvalues",
},
},
values: "default: values",
},
};
const state = packageReducer(packageWithCustomDefaults, {
type: getType(actions.availablepackages.setAvailablePackageDetailCustomDefaults),
payload: { customDefault: "values-other" },
}) as any;

expect(state.selected.values).toEqual("more: customdefaultvalues");
});
});
});

describe("defaultValues", () => {
const packageDetail = {
name: "test-package",
defaultValues: "default: values",
valuesSchema: "",
additionalDefaultValues: {},
} as AvailablePackageDetail;

it("returns the only defaults when values.yaml is the only default file", () => {
const result = defaultValues(packageDetail);

expect(result).toEqual("default: values");
});

it("returns the only defaults when values.yaml is the only default file, regardless of input", () => {
const result = defaultValues(packageDetail, "other-default");

expect(result).toEqual("default: values");
});

it("returns a custom default file when there is exactly one custom default in the pkg", () => {
const result = defaultValues(
{
...packageDetail,
additionalDefaultValues: {
"values-custom": "custom: values",
},
},
"other-default",
);

expect(result).toEqual("custom: values");
});

it("returns the default file when there is more than one custom default in the pkg", () => {
const result = defaultValues(
{
...packageDetail,
additionalDefaultValues: {
"values-custom": "custom: values",
"other-custom": "other: values",
},
},
"other-default",
);

expect(result).toEqual("default: values");
});

it("returns the specific custom default file when specified", () => {
const result = defaultValues(
{
...packageDetail,
additionalDefaultValues: {
"values-custom": "custom: values",
"other-custom": "other: values",
},
},
"other-custom",
);

expect(result).toEqual("other: values");
});
});
19 changes: 18 additions & 1 deletion dashboard/src/reducers/availablepackages.ts
Expand Up @@ -24,11 +24,18 @@ export const initialState: IPackageState = {

// defaultValues determines whether the package defaults or custom default
// values should be used.
function defaultValues(pkg: AvailablePackageDetail) {
export function defaultValues(pkg: AvailablePackageDetail, customDefault?: string) {
const additionalValues = Object.values(pkg.additionalDefaultValues || []);
if (additionalValues.length === 1) {
return additionalValues[0];
}
if (
additionalValues.length > 1 &&
customDefault &&
customDefault in pkg.additionalDefaultValues
) {
return pkg.additionalDefaultValues[customDefault];
}
return pkg.defaultValues || "";
}

Expand All @@ -52,6 +59,11 @@ const selectedPackageReducer = (
? (JSON.parse(action.payload.selectedPackage.valuesSchema) as JSONSchemaType<any>)
: ({} as JSONSchemaType<any>),
};
case getType(actions.availablepackages.setAvailablePackageDetailCustomDefaults):
return {
...state,
values: defaultValues(state.availablePackageDetail!, action.payload.customDefault),
};
case getType(actions.availablepackages.receiveSelectedAvailablePackageVersions):
return {
...state,
Expand Down Expand Up @@ -114,6 +126,11 @@ const packageReducer = (
isFetching: true,
selected: selectedPackageReducer(state.selected, action),
};
case getType(actions.availablepackages.setAvailablePackageDetailCustomDefaults):
return {
...state,
selected: selectedPackageReducer(state.selected, action),
};
case getType(actions.availablepackages.resetAvailablePackageSummaries):
return {
...state,
Expand Down
26 changes: 26 additions & 0 deletions integration/charts/simplechart-multicustomvalues/.helmignore
@@ -0,0 +1,26 @@
# Copyright 2022 the Kubeapps contributors.
# SPDX-License-Identifier: Apache-2.0

# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
9 changes: 9 additions & 0 deletions integration/charts/simplechart-multicustomvalues/Chart.yaml
@@ -0,0 +1,9 @@
# Copyright 2022 the Kubeapps contributors.
# SPDX-License-Identifier: Apache-2.0

apiVersion: v2
name: simplechart-multicustomvalues
description: A simple chart for testing multiple custom values
type: application
version: 0.1.0
appVersion: "1.0.0"
@@ -0,0 +1,65 @@
{{/* Copyright 2022 the Kubeapps contributors. */}}
{{/* SPDX-License-Identifier: Apache-2.0 */}}

{{/*
Expand the name of the chart.
*/}}
{{- define "simplechart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "simplechart.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "simplechart.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "simplechart.labels" -}}
helm.sh/chart: {{ include "simplechart.chart" . }}
{{ include "simplechart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "simplechart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "simplechart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "simplechart.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "simplechart.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
@@ -0,0 +1,40 @@
# Copyright 2022 the Kubeapps contributors.
# SPDX-License-Identifier: Apache-2.0

apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "simplechart.fullname" . }}
labels:
{{- include "simplechart.labels" . | nindent 4 }}
spec:
replicas: 1
selector:
matchLabels:
{{- include "simplechart.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "simplechart.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "simplechart.serviceAccountName" . }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
@@ -0,0 +1,18 @@
# Copyright 2022 the Kubeapps contributors.
# SPDX-License-Identifier: Apache-2.0

apiVersion: v1
kind: Service
metadata:
name: {{ include "simplechart.fullname" . }}
labels:
{{- include "simplechart.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "simplechart.selectorLabels" . | nindent 4 }}

0 comments on commit 4fef0c8

Please sign in to comment.