Skip to content

Commit

Permalink
Merge pull request #58 from kamilmadejek/nephio-resources-editors
Browse files Browse the repository at this point in the history
Editors for Nephio-specific resources (1st batch).
  • Loading branch information
radoslawc authored Sep 4, 2024
2 parents 7b97e0f + 846962f commit 3ed685b
Show file tree
Hide file tree
Showing 25 changed files with 748 additions and 31 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"engines": {
"node": "16 || 18"
"node": ">=18.20.0"
},
"scripts": {
"dev": "NODE_ENV=development concurrently \"yarn start\" \"yarn start-backend\"",
Expand Down
16 changes: 6 additions & 10 deletions plugins/cad-backend/src/service/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ export enum GitOpsDeliveryTool {
export enum ClusterLocatorMethodType {
CURRENT_CONTEXT = 'current-context',
IN_CLUSTER = 'in-cluster',
LOCAL_PROXY = 'local-proxy',
}

export enum ClusterLocatorAuthProvider {
CURRENT_CONTEXT = 'current-context',
GOOGLE = 'google',
OIDC = 'oidc',
SERVICE_ACCOUNT = 'service-account',
NONE = 'none',
}

export enum OIDCTokenProvider {
Expand All @@ -39,17 +41,11 @@ export enum OIDCTokenProvider {
OKTA = 'okta',
}

export const getMaxRequestSize = (config: Config): string => {
const maxRequestSize = config.getOptionalString('maxRequestSize') ?? '1mb';

return maxRequestSize;
};
export const getMaxRequestSize = (config: Config): string =>
config.getOptionalString('maxRequestSize') ?? '1mb';

export const getResourcesNamespace = (config: Config): string => {
const namespace = config.getString('resourcesNamespace');

return namespace;
};
export const getResourcesNamespace = (config: Config): string =>
config.getString('resourcesNamespace');

export const getGitOpsDeliveryTool = (config: Config): GitOpsDeliveryTool => {
const gitOpsTool = config.getString('gitOpsDeliveryTool');
Expand Down
6 changes: 6 additions & 0 deletions plugins/cad-backend/src/service/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ export const getKubernetesConfig = (
case ClusterLocatorMethodType.CURRENT_CONTEXT:
kubeConfig.loadFromDefault();
break;
case ClusterLocatorMethodType.LOCAL_PROXY:
kubeConfig.loadFromClusterAndUser(
{ name: 'local-proxy', server: 'http://localhost:8001' },
{ name: 'local-user' },
);
break;
default:
throw new Error(
`Unknown cluster locator method type, ${clusterLocatorMethodType}`,
Expand Down
1 change: 1 addition & 0 deletions plugins/cad-backend/src/service/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const getClientAuthentication = (

case ClusterLocatorAuthProvider.SERVICE_ACCOUNT:
case ClusterLocatorAuthProvider.CURRENT_CONTEXT:
case ClusterLocatorAuthProvider.NONE:
return 'none';

default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
DeploymentEditor,
StatefulSetEditor,
} from './FirstClassEditors/DeploymentEditor';
import { CapacityEditor } from './FirstClassEditors/CapacityEditor';
import { IngressEditor } from './FirstClassEditors/IngressEditor';
import { KptfileEditor } from './FirstClassEditors/KptfileEditor';
import { NamespaceEditor } from './FirstClassEditors/NamespaceEditor';
Expand All @@ -33,6 +34,8 @@ import { ServiceAccountEditor } from './FirstClassEditors/ServiceAccountEditor';
import { ServiceEditor } from './FirstClassEditors/ServiceEditor';
import { SetLabelsEditor } from './FirstClassEditors/SetLabelsEditor';
import { PackageVariantSetEditor } from './FirstClassEditors/PackageVariantSetEditor';
import { NephioTokenEditor } from './FirstClassEditors/NephioTokenEditor';
import { WorkloadClusterEditor } from './FirstClassEditors/WorkloadClusterEditor';

type OnUpdatedYamlFn = (yaml: string) => void;
type OnNoNamedEditorFn = () => void;
Expand Down Expand Up @@ -110,6 +113,14 @@ export const FirstClassEditorSelector = ({
case 'fn.kpt.dev/v1alpha1/SetLabels':
return <SetLabelsEditor yaml={yaml} onUpdatedYaml={onUpdatedYaml} />;

case 'infra.nephio.org/v1alpha1/Token':
return <NephioTokenEditor yaml={yaml} onUpdatedYaml={onUpdatedYaml} />;

case 'infra.nephio.org/v1alpha1/WorkloadCluster':
return (
<WorkloadClusterEditor yaml={yaml} onUpdatedYaml={onUpdatedYaml} />
);

case 'kpt.dev/v1/Kptfile':
return (
<KptfileEditor
Expand Down Expand Up @@ -140,6 +151,9 @@ export const FirstClassEditorSelector = ({
/>
);

case 'req.nephio.org/v1alpha1/Capacity':
return <CapacityEditor yaml={yaml} onUpdatedYaml={onUpdatedYaml} />;

case 'v1/ConfigMap':
return <ConfigMapEditor yaml={yaml} onUpdatedYaml={onUpdatedYaml} />;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/**
* Copyright 2024 The Nephio Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { TextField } from '@material-ui/core';
import React, { useState } from 'react';
import { useSetStateAndCall } from '../../../../../hooks/useSetStateAndCall';
import { getNumber } from '../../../../../utils/string';
import {
Capacity,
CapacityMetadata,
CapacitySpec,
} from '../../../../../types/Capacity';
import { dumpYaml, loadYaml } from '../../../../../utils/yaml';
import { EditorAccordion, ResourceMetadataAccordion } from '../Controls';
import { useEditorStyles } from '../styles';

type OnUpdatedYamlFn = (yaml: string) => void;

type ResourceEditorProps = {
yaml: string;
onUpdatedYaml: OnUpdatedYamlFn;
};

type State = {
metadata: CapacityMetadata;
spec: CapacitySpec;
};

export const CapacityEditor = ({
yaml,
onUpdatedYaml,
}: ResourceEditorProps) => {
const classes = useEditorStyles();
const resourceYaml = loadYaml(yaml) as Capacity;

const createResourceState = (): State => ({
metadata: resourceYaml.metadata,
spec: resourceYaml.spec,
});

const [state, setState] = useState<State>(createResourceState());
const [expanded, setExpanded] = useState<string>();

const setStateAndCall = useSetStateAndCall([state, setState], newState => {
onUpdatedYaml(dumpYaml({ ...resourceYaml, ...newState }));
});

return (
<div className={classes.root}>
<ResourceMetadataAccordion
id="metadata"
state={[expanded, setExpanded]}
value={state.metadata}
onUpdate={metadata => setStateAndCall(s => ({ ...s, metadata }))}
/>

<EditorAccordion
id="spec"
title="Capacity"
state={[expanded, setExpanded]}
>
{/* TODO Consider adding regex-based validation of both throughput values. */}
<TextField
label="Max Uplink Throughput"
variant="outlined"
value={state.spec.maxUplinkThroughput ?? ''}
onChange={e => {
setStateAndCall(s => ({
...s,
spec: { ...s.spec, maxUplinkThroughput: e.target.value },
}));
}}
fullWidth
/>

<TextField
label="Max Downlink Throughput"
variant="outlined"
value={state.spec.maxDownlinkThroughput ?? ''}
onChange={e => {
setStateAndCall(s => ({
...s,
spec: { ...s.spec, maxDownlinkThroughput: e.target.value },
}));
}}
fullWidth
/>

<TextField
label="Max NF Connections"
variant="outlined"
value={state.spec.maxNFConnections ?? ''}
onChange={e => {
setStateAndCall(s => ({
...s,
spec: { ...s.spec, maxNFConnections: getNumber(e.target.value) },
}));
}}
fullWidth
/>

<TextField
label="Max Sessions"
variant="outlined"
value={state.spec.maxSessions ?? ''}
onChange={e => {
setStateAndCall(s => ({
...s,
spec: { ...s.spec, maxSessions: getNumber(e.target.value) },
}));
}}
fullWidth
/>

<TextField
label="Max Subscribers"
variant="outlined"
value={state.spec.maxSubscribers ?? ''}
onChange={e => {
setStateAndCall(s => ({
...s,
spec: { ...s.spec, maxSubscribers: getNumber(e.target.value) },
}));
}}
fullWidth
/>
</EditorAccordion>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Copyright 2024 The Nephio Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export { CapacityEditor } from './CapacityEditor';
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* Copyright 2024 The Nephio Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Button, TextField } from '@material-ui/core';
import AddIcon from '@material-ui/icons/Add';
import DeleteIcon from '@material-ui/icons/Delete';
import React, { Fragment, useRef } from 'react';
import { KubernetesValueList } from '../../../../../types/KubernetesResource';
import { toLowerCase } from '../../../../../utils/string';
import { IconButton } from '../../../../Controls';
import { useEditorStyles } from '../styles';
import { AccordionState, EditorAccordion } from './EditorAccordion';

type ValueListEditorProps = {
id: string;
title: string;
state: AccordionState;
valueList: KubernetesValueList;
onUpdatedValueList: (valueList: KubernetesValueList) => void;
};

export const ValueListEditorAccordion = ({
id,
title,
state,
valueList,
onUpdatedValueList,
}: ValueListEditorProps) => {
const refViewModel = useRef<{ value: string }[]>(
valueList.map(value => ({ value })),
);

const classes = useEditorStyles();

const valueUpdated = (): void => {
onUpdatedValueList(
refViewModel.current.map(valueHolder => valueHolder.value),
);
};

const addRow = () => {
refViewModel.current.push({ value: '' });
valueUpdated();
};

const description = `${refViewModel.current.length} ${toLowerCase(title)}`;

return (
<EditorAccordion
id={id}
state={state}
title={title}
description={description}
>
<Fragment>
{refViewModel.current.map((valueHolder, index) => (
<div className={classes.multiControlRow} key={index}>
<TextField
label="Value"
variant="outlined"
value={valueHolder.value}
onChange={e => {
valueHolder.value = e.target.value;
valueUpdated();
}}
fullWidth
/>
<IconButton
title="Delete"
className={classes.iconButton}
onClick={() => {
refViewModel.current = refViewModel.current.filter(
thisValueHolder => thisValueHolder !== valueHolder,
);
valueUpdated();
}}
>
<DeleteIcon />
</IconButton>
</div>
))}

<Button variant="outlined" startIcon={<AddIcon />} onClick={addRow}>
Add {title}
</Button>
</Fragment>
</EditorAccordion>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export { EditorAccordion } from './EditorAccordion';
export { KeyValueEditorAccordion } from './KeyValueEditorAccordion';
export { ResourceMetadataAccordion } from './ResourceMetadataAccordion';
export { SingleTextFieldAccordion } from './SingleTextFieldAccordion';
export { ValueListEditorAccordion } from './ValueListEditorAccordion';
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ import {
Deployment,
DeploymentMetadata,
DeploymentStrategy,
LabelSelector,
} from '../../../../../types/Deployment';
import {
Container,
PodSecurityContext,
Volume,
} from '../../../../../types/Pod';
import { LabelSelector } from '../../../../../types/Selectors';
import { PackageResource } from '../../../../../utils/packageRevisionResources';
import { dumpYaml, loadYaml } from '../../../../../utils/yaml';
import { ResourceMetadataAccordion } from '../Controls/ResourceMetadataAccordion';
import { ResourceMetadataAccordion } from '../Controls';
import { useEditorStyles } from '../styles';
import {
Deletable,
Expand Down
Loading

0 comments on commit 3ed685b

Please sign in to comment.