mirror of https://github.com/portainer/portainer
fix(image): Add hide default registry teaser for CE version [EE-4038] (#7533)
* fix(image): Add hide default registry teaser for CE version [EE-4038]. * fix(image): Hide advanced mode only if there is no docker hub registries [EE-3734] * sync with EEpull/7566/head
parent
234627f278
commit
c6ab5d5717
|
@ -77,10 +77,12 @@
|
|||
<input id="select_{{ $index }}" type="checkbox" disabled />
|
||||
<label for="select_{{ $index }}"></label>
|
||||
</span>
|
||||
<span>DockerHub (anonymous)</span>
|
||||
<span><default-registry-name></default-registry-name></span>
|
||||
</td>
|
||||
<td> <default-registry-domain></default-registry-domain> </td>
|
||||
<td>
|
||||
<default-registry-action ng-if="$ctrl.isAdmin && !$ctrl.endpointType"></default-registry-action>
|
||||
</td>
|
||||
<td> docker.io </td>
|
||||
<td> - </td>
|
||||
</tr>
|
||||
<tr
|
||||
dir-paginate="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit))"
|
||||
|
|
|
@ -30,4 +30,5 @@ export enum FeatureId {
|
|||
STACK_WEBHOOK = 'stack-webhook',
|
||||
CONTAINER_WEBHOOK = 'container-webhook',
|
||||
POD_SECURITY_POLICY_CONSTRAINT = 'pod-security-policy-constraint',
|
||||
HIDE_DOCKER_HUB_ANONYMOUS = 'hide-docker-hub-anonymous',
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ export async function init(edition: Edition) {
|
|||
[FeatureId.STACK_WEBHOOK]: Edition.BE,
|
||||
[FeatureId.CONTAINER_WEBHOOK]: Edition.BE,
|
||||
[FeatureId.POD_SECURITY_POLICY_CONSTRAINT]: Edition.BE,
|
||||
[FeatureId.HIDE_DOCKER_HUB_ANONYMOUS]: Edition.BE,
|
||||
};
|
||||
|
||||
state.currentEdition = currentEdition;
|
||||
|
|
|
@ -36,6 +36,7 @@ export function PublicSettingsViewModel(settings) {
|
|||
this.KubeconfigExpiry = settings.KubeconfigExpiry;
|
||||
this.Features = settings.Features;
|
||||
this.Edge = new EdgeSettingsViewModel(settings.Edge);
|
||||
this.DefaultRegistry = settings.DefaultRegistry;
|
||||
}
|
||||
|
||||
export function InternalAuthSettingsViewModel(data) {
|
||||
|
|
|
@ -2,11 +2,19 @@ import angular from 'angular';
|
|||
|
||||
import { r2a } from '@/react-tools/react2angular';
|
||||
import { CreateAccessToken } from '@/react/portainer/account/CreateAccessTokenView';
|
||||
import {
|
||||
DefaultRegistryAction,
|
||||
DefaultRegistryDomain,
|
||||
DefaultRegistryName,
|
||||
} from '@/react/portainer/registries/ListView/DefaultRegistry';
|
||||
|
||||
import { wizardModule } from './wizard';
|
||||
|
||||
export const viewsModule = angular
|
||||
.module('portainer.app.react.views', [wizardModule])
|
||||
.component('defaultRegistryName', r2a(DefaultRegistryName, []))
|
||||
.component('defaultRegistryAction', r2a(DefaultRegistryAction, []))
|
||||
.component('defaultRegistryDomain', r2a(DefaultRegistryDomain, []))
|
||||
.component(
|
||||
'createAccessToken',
|
||||
r2a(CreateAccessToken, ['onSubmit', 'onError'])
|
||||
|
|
|
@ -12,8 +12,9 @@ import {
|
|||
getSettings,
|
||||
updateSettings,
|
||||
getPublicSettings,
|
||||
updateDefaultRegistry,
|
||||
} from './settings.service';
|
||||
import { Settings } from './types';
|
||||
import { DefaultRegistry, Settings } from './types';
|
||||
|
||||
export function usePublicSettings<T = PublicSettingsViewModel>({
|
||||
enabled,
|
||||
|
@ -51,3 +52,15 @@ export function useUpdateSettingsMutation() {
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function useUpdateDefaultRegistrySettingsMutation() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation(
|
||||
(payload: Partial<DefaultRegistry>) => updateDefaultRegistry(payload),
|
||||
mutationOptions(
|
||||
withInvalidate(queryClient, [['settings']]),
|
||||
withError('Unable to update default registry settings')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { PublicSettingsViewModel } from '@/portainer/models/settings';
|
|||
|
||||
import axios, { parseAxiosError } from '../services/axios';
|
||||
|
||||
import { PublicSettingsResponse, Settings } from './types';
|
||||
import { DefaultRegistry, PublicSettingsResponse, Settings } from './types';
|
||||
|
||||
export async function getPublicSettings() {
|
||||
try {
|
||||
|
@ -38,6 +38,19 @@ export async function updateSettings(settings: Partial<Settings>) {
|
|||
}
|
||||
}
|
||||
|
||||
export async function updateDefaultRegistry(
|
||||
defaultRegistry: Partial<DefaultRegistry>
|
||||
) {
|
||||
try {
|
||||
await axios.put(buildUrl('default_registry'), defaultRegistry);
|
||||
} catch (e) {
|
||||
throw parseAxiosError(
|
||||
e as Error,
|
||||
'Unable to update default registry settings'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function buildUrl(subResource?: string, action?: string) {
|
||||
let url = 'settings';
|
||||
if (subResource) {
|
||||
|
|
|
@ -89,6 +89,10 @@ enum AuthenticationMethod {
|
|||
|
||||
type Feature = string;
|
||||
|
||||
export interface DefaultRegistry {
|
||||
Hide: boolean;
|
||||
}
|
||||
|
||||
export interface Settings {
|
||||
LogoURL: string;
|
||||
BlackListedLabels: Pair[];
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
import {
|
||||
usePublicSettings,
|
||||
useUpdateDefaultRegistrySettingsMutation,
|
||||
} from 'Portainer/settings/queries';
|
||||
import { notifySuccess } from 'Portainer/services/notifications';
|
||||
import { FeatureId } from 'Portainer/feature-flags/enums';
|
||||
|
||||
import { isLimitedToBE } from '@/portainer/feature-flags/feature-flags.service';
|
||||
|
||||
import { Tooltip } from '@@/Tip/Tooltip';
|
||||
import { Button } from '@@/buttons';
|
||||
import { Icon } from '@@/Icon';
|
||||
import { BEFeatureIndicator } from '@@/BEFeatureIndicator';
|
||||
|
||||
export function DefaultRegistryAction() {
|
||||
const settingsQuery = usePublicSettings({
|
||||
select: (settings) => settings.DefaultRegistry?.Hide,
|
||||
});
|
||||
const defaultRegistryMutation = useUpdateDefaultRegistrySettingsMutation();
|
||||
|
||||
if (!settingsQuery.isSuccess) {
|
||||
return null;
|
||||
}
|
||||
const hideDefaultRegistry = settingsQuery.data;
|
||||
|
||||
const isLimited = isLimitedToBE(FeatureId.HIDE_DOCKER_HUB_ANONYMOUS);
|
||||
|
||||
return (
|
||||
<>
|
||||
{!hideDefaultRegistry ? (
|
||||
<div className="vertical-center">
|
||||
<Button
|
||||
className="btn btn-xs btn-light vertical-center"
|
||||
onClick={() => handleShowOrHide(true)}
|
||||
disabled={isLimited}
|
||||
>
|
||||
<Icon icon="eye-off" feather />
|
||||
Hide for all users
|
||||
</Button>
|
||||
<BEFeatureIndicator featureId={FeatureId.HIDE_DOCKER_HUB_ANONYMOUS} />
|
||||
{isLimited ? null : (
|
||||
<Tooltip
|
||||
message="This hides the option in any registry dropdown prompts but does not prevent a user from deploying anonymously from Docker Hub directly via YAML.
|
||||
Note: Docker Hub (anonymous) will continue to show as the ONLY option if there are NO other registries available to the user."
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="vertical-center">
|
||||
<Button
|
||||
className="btn btn-xs btn-success vertical-center"
|
||||
onClick={() => handleShowOrHide(false)}
|
||||
>
|
||||
<Icon icon="eye" feather />
|
||||
Show for all users
|
||||
</Button>
|
||||
<Tooltip
|
||||
message="This reveals the option in any registry dropdown prompts.
|
||||
(but note that the Docker Hub (anonymous) option only shows if there is no credentialled Docker Hub option available to the user)."
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
function handleShowOrHide(hideDefaultRegistry: boolean) {
|
||||
defaultRegistryMutation.mutate(
|
||||
{
|
||||
Hide: hideDefaultRegistry,
|
||||
},
|
||||
{
|
||||
onSuccess() {
|
||||
notifySuccess(
|
||||
'Success',
|
||||
'Default registry Settings updated successfully'
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import clsx from 'clsx';
|
||||
import { usePublicSettings } from 'Portainer/settings/queries';
|
||||
|
||||
export function DefaultRegistryDomain() {
|
||||
const settingsQuery = usePublicSettings({
|
||||
select: (settings) => settings.DefaultRegistry?.Hide,
|
||||
});
|
||||
|
||||
return (
|
||||
<span
|
||||
className={clsx({
|
||||
'cm-strikethrough': settingsQuery.isSuccess && settingsQuery.data,
|
||||
})}
|
||||
>
|
||||
docker.io
|
||||
</span>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import { usePublicSettings } from 'Portainer/settings/queries';
|
||||
import clsx from 'clsx';
|
||||
|
||||
export function DefaultRegistryName() {
|
||||
const settingsQuery = usePublicSettings({
|
||||
select: (settings) => settings.DefaultRegistry?.Hide,
|
||||
});
|
||||
|
||||
return (
|
||||
<span
|
||||
className={clsx({
|
||||
'cm-strikethrough': settingsQuery.isSuccess && settingsQuery.data,
|
||||
})}
|
||||
>
|
||||
Docker Hub (anonymous)
|
||||
</span>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export { DefaultRegistryAction } from './DefaultRegistryAction';
|
||||
export { DefaultRegistryDomain } from './DefaultRegistryDomain';
|
||||
export { DefaultRegistryName } from './DefaultRegistryName';
|
Loading…
Reference in New Issue