mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 12:25:22 +02:00
feature(kubernetes): stack name made optional & add toggle to disable stack in kubernetes [EE-6170] (#10436)
This commit is contained in:
parent
44d66cc633
commit
7840e0bfe1
29 changed files with 305 additions and 47 deletions
84
app/react/kubernetes/DeployView/StackName/StackName.tsx
Normal file
84
app/react/kubernetes/DeployView/StackName/StackName.tsx
Normal file
|
@ -0,0 +1,84 @@
|
|||
import { InsightsBox } from '@@/InsightsBox';
|
||||
import { Link } from '@@/Link';
|
||||
import { TextTip } from '@@/Tip/TextTip';
|
||||
import { Tooltip } from '@@/Tip/Tooltip';
|
||||
|
||||
type Props = {
|
||||
stackName: string;
|
||||
setStackName: (name: string) => void;
|
||||
isAdmin?: boolean;
|
||||
};
|
||||
|
||||
export function StackName({ stackName, setStackName, isAdmin = false }: Props) {
|
||||
const tooltip = (
|
||||
<>
|
||||
You may specify a stack name to label resources that you want to group.
|
||||
This includes Deployments, DaemonSets, StatefulSets and Pods.
|
||||
{isAdmin && (
|
||||
<>
|
||||
<br />
|
||||
You can leave the stack name empty, or even turn off Kubernetes Stacks
|
||||
functionality entirely via{' '}
|
||||
<Link to="portainer.settings" target="_blank">
|
||||
Kubernetes Settings
|
||||
</Link>
|
||||
.
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
const insightsBoxContent = (
|
||||
<>
|
||||
The stack field below was previously labelled 'Name' but, in
|
||||
fact, it's always been the stack name (hence the relabelling).
|
||||
{isAdmin && (
|
||||
<>
|
||||
<br />
|
||||
Kubernetes Stacks functionality can be turned off entirely via{' '}
|
||||
<Link to="portainer.settings" target="_blank">
|
||||
Kubernetes Settings
|
||||
</Link>
|
||||
.
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-fit mb-4">
|
||||
<InsightsBox
|
||||
type="slim"
|
||||
header="Stack"
|
||||
content={insightsBoxContent}
|
||||
insightCloseId="k8s-stacks-name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TextTip className="mb-4" color="blue">
|
||||
Enter or select a 'stack' name to group multiple deployments
|
||||
together, or else leave empty to ignore.
|
||||
</TextTip>
|
||||
<div className="form-group">
|
||||
<label
|
||||
htmlFor="stack_name"
|
||||
className="col-lg-2 col-sm-3 control-label text-left"
|
||||
>
|
||||
Stack
|
||||
<Tooltip message={tooltip} setHtmlMessage />
|
||||
</label>
|
||||
<div className="col-sm-8">
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
defaultValue={stackName}
|
||||
onChange={(e) => setStackName(e.target.value)}
|
||||
id="stack_name"
|
||||
placeholder="myStack"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -6,6 +6,8 @@ import { useCurrentStateAndParams } from '@uirouter/react';
|
|||
|
||||
import { Authorized } from '@/react/hooks/useUser';
|
||||
import { notifyError, notifySuccess } from '@/portainer/services/notifications';
|
||||
import { usePublicSettings } from '@/react/portainer/settings/queries';
|
||||
import { GlobalDeploymentOptions } from '@/react/portainer/settings/types';
|
||||
|
||||
import { DetailsTable } from '@@/DetailsTable';
|
||||
import { Badge } from '@@/Badge';
|
||||
|
@ -69,6 +71,11 @@ export function ApplicationSummaryWidget() {
|
|||
setApplicationNoteFormValues(applicationNote || '');
|
||||
}, [applicationNote]);
|
||||
|
||||
const globalDeploymentOptionsQuery =
|
||||
usePublicSettings<GlobalDeploymentOptions>({
|
||||
select: (settings) => settings.GlobalDeploymentOptions,
|
||||
});
|
||||
|
||||
const failedCreateCondition = application?.status?.conditions?.find(
|
||||
(condition) => condition.reason === 'FailedCreate'
|
||||
);
|
||||
|
@ -117,13 +124,17 @@ export function ApplicationSummaryWidget() {
|
|||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stack</td>
|
||||
<td data-cy="k8sAppDetail-stackName">
|
||||
{application?.metadata?.labels?.[appStackNameLabel] ||
|
||||
'-'}
|
||||
</td>
|
||||
</tr>
|
||||
{globalDeploymentOptionsQuery.data &&
|
||||
!globalDeploymentOptionsQuery.data
|
||||
.hideStacksFunctionality && (
|
||||
<tr>
|
||||
<td>Stack</td>
|
||||
<td data-cy="k8sAppDetail-stackName">
|
||||
{application?.metadata?.labels?.[appStackNameLabel] ||
|
||||
'-'}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
<tr>
|
||||
<td>Namespace</td>
|
||||
<td>
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
StatusType as EdgeStackStatusType,
|
||||
} from '@/react/edge/edge-stacks/types';
|
||||
|
||||
import { getPublicSettings } from '../../settings/settings.service';
|
||||
import type {
|
||||
Environment,
|
||||
EnvironmentId,
|
||||
|
@ -131,6 +132,20 @@ export async function snapshotEndpoints() {
|
|||
}
|
||||
}
|
||||
|
||||
export async function getDeploymentOptions(environmentId: EnvironmentId) {
|
||||
const publicSettings = await getPublicSettings();
|
||||
const endpoint = await getEndpoint(environmentId);
|
||||
|
||||
if (
|
||||
publicSettings.GlobalDeploymentOptions.perEnvOverride &&
|
||||
endpoint.DeploymentOptions?.overrideGlobalOptions
|
||||
) {
|
||||
return endpoint.DeploymentOptions;
|
||||
}
|
||||
|
||||
return publicSettings.GlobalDeploymentOptions;
|
||||
}
|
||||
|
||||
export async function snapshotEndpoint(id: EnvironmentId) {
|
||||
try {
|
||||
await axios.post<void>(buildUrl(id, 'snapshot'));
|
||||
|
|
|
@ -14,6 +14,7 @@ export function DeploymentOptionsSection() {
|
|||
values: { globalDeploymentOptions: values },
|
||||
setFieldValue,
|
||||
} = useFormikContext<FormValues>();
|
||||
|
||||
const limitedFeature = isLimitedToBE(FeatureId.ENFORCE_DEPLOYMENT_OPTIONS);
|
||||
return (
|
||||
<FormSection title="Deployment Options">
|
||||
|
@ -74,6 +75,24 @@ export function DeploymentOptionsSection() {
|
|||
)}
|
||||
|
||||
<KubeNoteMinimumCharacters />
|
||||
|
||||
<div className="form-group">
|
||||
<div className="col-sm-12">
|
||||
<SwitchField
|
||||
label="Allow stacks functionality with Kubernetes environments"
|
||||
checked={!values.hideStacksFunctionality}
|
||||
onChange={(value) =>
|
||||
setFieldValue(
|
||||
'globalDeploymentOptions.hideStacksFunctionality',
|
||||
!value
|
||||
)
|
||||
}
|
||||
name="toggle_stacksFunctionality"
|
||||
labelClass="col-sm-3 col-lg-2"
|
||||
tooltip="This allows you to group your applications/workloads into a single ‘stack’, and then view or delete an entire stack. If disabled, stacks functionality will not show in the UI."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</FormSection>
|
||||
);
|
||||
|
||||
|
|
|
@ -29,13 +29,17 @@ export function KubeSettingsPanel() {
|
|||
const initialValues: FormValues = {
|
||||
helmRepositoryUrl: settingsQuery.data.HelmRepositoryURL || '',
|
||||
kubeconfigExpiry: settingsQuery.data.KubeconfigExpiry || '0',
|
||||
globalDeploymentOptions: settingsQuery.data.GlobalDeploymentOptions || {
|
||||
requireNoteOnApplications: false,
|
||||
minApplicationNoteLength: 0,
|
||||
hideAddWithForm: false,
|
||||
hideFileUpload: false,
|
||||
hideWebEditor: false,
|
||||
perEnvOverride: false,
|
||||
globalDeploymentOptions: {
|
||||
...{
|
||||
requireNoteOnApplications: false,
|
||||
minApplicationNoteLength: 0,
|
||||
hideAddWithForm: false,
|
||||
hideFileUpload: false,
|
||||
hideWebEditor: false,
|
||||
perEnvOverride: false,
|
||||
hideStacksFunctionality: false,
|
||||
},
|
||||
...settingsQuery.data.GlobalDeploymentOptions,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -8,5 +8,6 @@ export interface FormValues {
|
|||
hideFileUpload: boolean;
|
||||
requireNoteOnApplications: boolean;
|
||||
minApplicationNoteLength: number;
|
||||
hideStacksFunctionality: boolean;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ export function validation(): SchemaOf<FormValues> {
|
|||
hideWebEditor: boolean().required(),
|
||||
hideFileUpload: boolean().required(),
|
||||
requireNoteOnApplications: boolean().required(),
|
||||
hideStacksFunctionality: boolean().required(),
|
||||
minApplicationNoteLength: number()
|
||||
.typeError('Must be a number')
|
||||
.default(0)
|
||||
|
|
|
@ -145,7 +145,7 @@ export interface Settings {
|
|||
};
|
||||
}
|
||||
|
||||
interface GlobalDeploymentOptions {
|
||||
export interface GlobalDeploymentOptions {
|
||||
/** Hide manual deploy forms in portainer */
|
||||
hideAddWithForm: boolean;
|
||||
/** Configure this per environment or globally */
|
||||
|
@ -157,6 +157,8 @@ interface GlobalDeploymentOptions {
|
|||
/** Make note on application add/edit screen required */
|
||||
requireNoteOnApplications: boolean;
|
||||
minApplicationNoteLength: number;
|
||||
|
||||
hideStacksFunctionality: boolean;
|
||||
}
|
||||
|
||||
export interface PublicSettingsResponse {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue