Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Modify UI stream & team form #97

Merged
merged 11 commits into from
May 28, 2024
9 changes: 7 additions & 2 deletions api/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ type UIConfig struct {

ClockworkUIHomepage string `json:"REACT_APP_CLOCKWORK_UI_HOMEPAGE"`
KubeflowUIHomepage string `json:"REACT_APP_KUBEFLOW_UI_HOMEPAGE"`

AllowCustomStream bool `json:"REACT_APP_ALLOW_CUSTOM_STREAM"`
AllowCustomTeam bool `json:"REACT_APP_ALLOW_CUSTOM_TEAM"`
}

// Transform env variables to the format consumed by koanf.
Expand Down Expand Up @@ -213,8 +216,10 @@ var defaultConfig = &Config{
TrackingURL: "",
},
UI: &UIConfig{
IndexPath: "index.html",
StaticPath: "ui/build",
IndexPath: "index.html",
StaticPath: "ui/build",
AllowCustomTeam: true,
AllowCustomStream: true,
},
DefaultSecretStorage: &SecretStorage{
Name: "internal",
Expand Down
14 changes: 10 additions & 4 deletions api/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,10 @@ func TestLoad(t *testing.T) {
"EmptyStream": {},
},
UI: &config.UIConfig{
StaticPath: "ui/build",
IndexPath: "index.html",
StaticPath: "ui/build",
IndexPath: "index.html",
AllowCustomTeam: true,
AllowCustomStream: true,
},
DefaultSecretStorage: &config.SecretStorage{
Name: "default-secret-storage",
Expand Down Expand Up @@ -142,8 +144,10 @@ func TestLoad(t *testing.T) {
"EmptyStream": {},
},
UI: &config.UIConfig{
StaticPath: "ui/build",
IndexPath: "index.html",
StaticPath: "ui/build",
IndexPath: "index.html",
AllowCustomTeam: true,
AllowCustomStream: true,
},
DefaultSecretStorage: &config.SecretStorage{
Name: "default-secret-storage",
Expand Down Expand Up @@ -240,6 +244,8 @@ func TestLoad(t *testing.T) {

ClockworkUIHomepage: "http://clockwork.dev",
KubeflowUIHomepage: "http://kubeflow.org",
AllowCustomTeam: true,
AllowCustomStream: true,
},
DefaultSecretStorage: &config.SecretStorage{
Name: "default-secret-storage",
Expand Down
4 changes: 3 additions & 1 deletion ui/packages/app/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ const config = {
),

CLOCKWORK_UI_HOMEPAGE: getEnv("REACT_APP_CLOCKWORK_UI_HOMEPAGE"),
KUBEFLOW_UI_HOMEPAGE: getEnv("REACT_APP_KUBEFLOW_UI_HOMEPAGE")
KUBEFLOW_UI_HOMEPAGE: getEnv("REACT_APP_KUBEFLOW_UI_HOMEPAGE"),
ALLOW_CUSTOM_STREAM: getEnv("REACT_APP_ALLOW_CUSTOM_STREAM") || true,
ALLOW_CUSTOM_TEAM: getEnv("REACT_APP_ALLOW_CUSTOM_TEAM") || true
};

export default config;
54 changes: 37 additions & 17 deletions ui/packages/app/src/project_setting/form/ProjectForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import { addToast, EuiComboBoxSelect, useMlpApi } from "@caraml-dev/ui-lib";
import { ProjectFormContext } from "./context";
import { EmailTextArea } from "./EmailTextArea";
import { Labels } from "./Labels";
import { isDNS1123Label } from "../../validation/validation";
import {
isDNS1123Label,
shydefoo marked this conversation as resolved.
Show resolved Hide resolved
isValidK8sLabelValue
} from "../../validation/validation";
import config from "../../config";
import { useNavigate } from "react-router-dom";

Expand Down Expand Up @@ -61,10 +64,10 @@ const ProjectForm = () => {
const [isValidStream, setIsValidStream] = useState(false);
const onStreamChange = selectedStream => {
if (selectedStream !== project.stream) {
let isValid = isDNS1123Label(selectedStream);
let isValid = isValidK8sLabelValue(selectedStream);
if (!isValid) {
setStreamError(
"Stream name is invalid. It should contain only lowercase alphanumeric and dash (-)"
"Stream name is invalid. It should contain only lowercase alphanumeric and dash (-), or underscore (_) or period (.)"
);
}
setIsValidStream(isValid);
Expand All @@ -76,10 +79,10 @@ const ProjectForm = () => {
const [isValidTeam, setIsValidTeam] = useState(false);
const onTeamChange = selectedTeam => {
if (selectedTeam !== project.team) {
let isValid = isDNS1123Label(selectedTeam);
let isValid = isValidK8sLabelValue(selectedTeam);
if (!isValid) {
setTeamError(
"Team name is invalid. It should contain only lowercase alphanumeric and dash (-)"
"Team name is invalid. It should contain only lowercase alphanumeric and dash (-), or underscore (_) or period (.)"
);
}
setIsValidTeam(isValid);
Expand Down Expand Up @@ -193,24 +196,41 @@ const ProjectForm = () => {
title={<h3>Stream</h3>}
description="Product stream the project belongs to">
<EuiFormRow isInvalid={!isValidStream} error={streamError}>
<EuiComboBoxSelect
value={project.stream}
options={streamOptions}
onChange={onStreamChange}
onCreateOption={onStreamChange}
/>
{config.ALLOW_CUSTOM_STREAM ? (
<EuiComboBoxSelect
value={project.stream}
options={streamOptions}
onChange={onStreamChange}
onCreateOption={onStreamChange}
/>
) : (
<EuiComboBoxSelect
value={project.stream}
options={streamOptions}
onChange={onStreamChange}
/>
)}
</EuiFormRow>
</EuiDescribedFormGroup>
<EuiDescribedFormGroup
title={<h3>Team</h3>}
description="Owner of the project">
<EuiFormRow isInvalid={!isValidTeam} error={teamError}>
<EuiComboBoxSelect
value={project.team}
options={teamOptions}
onChange={onTeamChange}
onCreateOption={onTeamChange}
/>
{config.ALLOW_CUSTOM_TEAM ? (
<EuiComboBoxSelect
value={project.team}
options={teamOptions}
onChange={onTeamChange}
onCreateOption={onTeamChange}
/>
) : (
<EuiComboBoxSelect
value={project.team}
options={teamOptions}
onChange={onTeamChange}
onCreateOption={onTeamChange}
/>
)}
</EuiFormRow>
</EuiDescribedFormGroup>
<EuiDescribedFormGroup
Expand Down
9 changes: 9 additions & 0 deletions ui/packages/app/src/validation/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,12 @@ export const validateEmail = email => {
const expression = /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/;
return expression.test(email);
};

// See https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set for full details
export const isValidK8sLabelValue = value => {
leonlnj marked this conversation as resolved.
Show resolved Hide resolved
const expression = /^[a-z0-9]([_.\-a-z0-9]*[a-z0-9])?$/;
if (value === undefined || value.length > DNS1123LabelMaxLength) {
return false;
}
return expression.test(value);
};
Loading