1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-22 23:09:41 +02:00

fix(container): hide capabilities tab EE-6258 (#10540)

This commit is contained in:
cmeng 2023-10-26 15:44:31 +13:00 committed by GitHub
parent 403fdf7ce3
commit 3964852fda
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 34 deletions

View file

@ -7,6 +7,7 @@ export interface Option<T extends string | number = string> {
label: ReactNode; label: ReactNode;
children?: ReactNode; children?: ReactNode;
id: T; id: T;
hidden?: boolean;
} }
interface Props<T extends string | number> { interface Props<T extends string | number> {
@ -33,31 +34,34 @@ export function NavTabs<T extends string | number = string>({
<ul <ul
className={clsx('nav', `nav-${type}`, { 'nav-justified': justified })} className={clsx('nav', `nav-${type}`, { 'nav-justified': justified })}
> >
{options.map((option) => ( {options.map(
<li (option) =>
className={clsx({ !option.hidden && (
active: option.id === selectedId, <li
[styles.parent]: !option.children, className={clsx({
disabled, active: option.id === selectedId,
})} [styles.parent]: !option.children,
key={option.id} disabled,
> })}
{/* rule disabled because `nav-tabs` requires an anchor */} key={option.id}
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} >
<a {/* rule disabled because `nav-tabs` requires an anchor */}
onClick={() => handleSelect(option)} {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
onKeyDown={(e) => { <a
if (e.key === 'Enter' || e.key === ' ') { onClick={() => handleSelect(option)}
handleSelect(option); onKeyDown={(e) => {
} if (e.key === 'Enter' || e.key === ' ') {
}} handleSelect(option);
role="button" }
tabIndex={0} }}
> role="button"
{option.label} tabIndex={0}
</a> >
</li> {option.label}
))} </a>
</li>
)
)}
</ul> </ul>
{selected && selected.children && ( {selected && selected.children && (
<div className="tab-content mt-3">{selected.children}</div> <div className="tab-content mt-3">{selected.children}</div>

View file

@ -5,16 +5,19 @@ import { Values } from './CapabilitiesTab';
export function toRequest( export function toRequest(
oldConfig: CreateContainerRequest, oldConfig: CreateContainerRequest,
values: Values values: Values,
hideCapabilities: boolean
): CreateContainerRequest { ): CreateContainerRequest {
return { return {
...oldConfig, ...oldConfig,
HostConfig: { HostConfig: {
...oldConfig.HostConfig, ...oldConfig.HostConfig,
CapAdd: values, CapAdd: hideCapabilities ? [] : values,
CapDrop: capabilities CapDrop: hideCapabilities
.filter((cap) => !values.includes(cap.key)) ? []
.map((cap) => cap.key), : capabilities
.filter((cap) => !values.includes(cap.key))
.map((cap) => cap.key),
}, },
}; };
} }

View file

@ -2,7 +2,7 @@ import { Formik } from 'formik';
import { useRouter } from '@uirouter/react'; import { useRouter } from '@uirouter/react';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useCurrentUser } from '@/react/hooks/useUser'; import { useCurrentUser, useIsEnvironmentAdmin } from '@/react/hooks/useUser';
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId'; import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
import { useCurrentEnvironment } from '@/react/hooks/useCurrentEnvironment'; import { useCurrentEnvironment } from '@/react/hooks/useCurrentEnvironment';
import { useEnvironmentRegistries } from '@/react/portainer/environments/queries/useEnvironmentRegistries'; import { useEnvironmentRegistries } from '@/react/portainer/environments/queries/useEnvironmentRegistries';
@ -48,6 +48,7 @@ function CreateForm() {
const router = useRouter(); const router = useRouter();
const { trackEvent } = useAnalytics(); const { trackEvent } = useAnalytics();
const { isAdmin } = useCurrentUser(); const { isAdmin } = useCurrentUser();
const isEnvironmentAdmin = useIsEnvironmentAdmin();
const [isDockerhubRateLimited, setIsDockerhubRateLimited] = useState(false); const [isDockerhubRateLimited, setIsDockerhubRateLimited] = useState(false);
const mutation = useCreateOrReplaceMutation(); const mutation = useCreateOrReplaceMutation();
@ -79,6 +80,10 @@ function CreateForm() {
const environment = envQuery.data; const environment = envQuery.data;
const hideCapabilities =
!environment.SecuritySettings.allowContainerCapabilitiesForRegularUsers &&
!isEnvironmentAdmin;
const { const {
isDuplicating = false, isDuplicating = false,
initialValues, initialValues,
@ -112,6 +117,7 @@ function CreateForm() {
validationSchema={validationSchema} validationSchema={validationSchema}
> >
<InnerForm <InnerForm
hideCapabilities={hideCapabilities}
onChangeName={syncName} onChangeName={syncName}
isDuplicate={isDuplicating} isDuplicate={isDuplicating}
isLoading={mutation.isLoading} isLoading={mutation.isLoading}
@ -136,7 +142,7 @@ function CreateForm() {
} }
const registry = getRegistry(values.image, registriesQuery.data || []); const registry = getRegistry(values.image, registriesQuery.data || []);
const config = toRequest(values, registry); const config = toRequest(values, registry, hideCapabilities);
mutation.mutate( mutation.mutate(
{ config, environment, values, registry, oldContainer, extraNetworks }, { config, environment, values, registry, oldContainer, extraNetworks },

View file

@ -24,11 +24,13 @@ import { EnvVarsTab } from './EnvVarsTab';
import { EditResourcesForm } from './ResourcesTab/EditResourceForm'; import { EditResourcesForm } from './ResourcesTab/EditResourceForm';
export function InnerForm({ export function InnerForm({
hideCapabilities = false,
isLoading, isLoading,
isDuplicate, isDuplicate,
onChangeName, onChangeName,
onRateLimit, onRateLimit,
}: { }: {
hideCapabilities: boolean;
isDuplicate: boolean; isDuplicate: boolean;
isLoading: boolean; isLoading: boolean;
onChangeName: (value: string) => void; onChangeName: (value: string) => void;
@ -202,6 +204,7 @@ export function InnerForm({
{ {
id: 'capabilities', id: 'capabilities',
label: 'Capabilities', label: 'Capabilities',
hidden: hideCapabilities,
children: ( children: (
<CapabilitiesTab <CapabilitiesTab
values={values.capabilities} values={values.capabilities}

View file

@ -13,7 +13,11 @@ import { restartPolicyTabUtils } from './RestartPolicyTab';
import { envVarsTabUtils } from './EnvVarsTab'; import { envVarsTabUtils } from './EnvVarsTab';
import { Values } from './useInitialValues'; import { Values } from './useInitialValues';
export function toRequest(values: Values, registry?: Registry) { export function toRequest(
values: Values,
registry?: Registry,
ignoreCapabilities?: boolean
) {
let config: CreateContainerRequest = { let config: CreateContainerRequest = {
HostConfig: {}, HostConfig: {},
NetworkingConfig: {}, NetworkingConfig: {},
@ -25,7 +29,11 @@ export function toRequest(values: Values, registry?: Registry) {
config = labelsTabUtils.toRequest(config, values.labels); config = labelsTabUtils.toRequest(config, values.labels);
config = restartPolicyTabUtils.toRequest(config, values.restartPolicy); config = restartPolicyTabUtils.toRequest(config, values.restartPolicy);
config = resourcesTabUtils.toRequest(config, values.resources); config = resourcesTabUtils.toRequest(config, values.resources);
config = capabilitiesTabUtils.toRequest(config, values.capabilities); config = capabilitiesTabUtils.toRequest(
config,
values.capabilities,
!!ignoreCapabilities
);
config = baseFormUtils.toRequest(config, values); config = baseFormUtils.toRequest(config, values);
config = envVarsTabUtils.toRequest(config, values.env); config = envVarsTabUtils.toRequest(config, values.env);
config.Image = buildImageFullURI(values.image.image, registry); config.Image = buildImageFullURI(values.image.image, registry);