1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-08 15:25:22 +02:00

refactor(ui): move react components to react codebase [EE-3354] (#8258)

* refactor(ui): move react components to react codebase [EE-3354]

* refactor(app): move bocx selector options

* refactor(react): spearate portainer components

* fix(app): fix imports
This commit is contained in:
Chaim Lev-Ari 2023-02-28 17:32:29 +02:00 committed by GitHub
parent f9a09301a8
commit b98c71f1ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 312 additions and 294 deletions

View file

@ -1,4 +1,4 @@
import { tlsOptions } from './tls-options';
import { tlsOptions } from '@/react/portainer/environments/ItemView/tls-options';
angular.module('portainer.app').controller('porEndpointSecurityController', [
'$scope',

View file

@ -1,38 +0,0 @@
import { Shield } from 'lucide-react';
import { BoxSelectorOption } from '@@/BoxSelector';
export const tlsOptions: ReadonlyArray<BoxSelectorOption<string>> = [
{
id: 'tls_client_ca',
value: 'tls_client_ca',
icon: Shield,
iconType: 'badge',
label: 'TLS with server and client verification',
description: 'Use client certificates and server verification',
},
{
id: 'tls_client_noca',
value: 'tls_client_noca',
icon: Shield,
iconType: 'badge',
label: 'TLS with client verification only',
description: 'Use client certificates without server verification',
},
{
id: 'tls_ca',
value: 'tls_ca',
icon: Shield,
iconType: 'badge',
label: 'TLS with server verification only',
description: 'Only verify the server certificate',
},
{
id: 'tls_only',
value: 'tls_only',
icon: Shield,
iconType: 'badge',
label: 'TLS only',
description: 'No server/client verification',
},
] as const;

View file

@ -5,8 +5,8 @@ import { notifyError } from '@/portainer/services/notifications';
import { IAuthenticationService } from '@/portainer/services/types';
import { GitAuthModel } from '@/react/portainer/gitops/types';
import { gitAuthValidation } from '@/react/portainer/gitops/AuthFieldset';
import { getGitCredentials } from '@/portainer/views/account/git-credential/gitCredential.service';
import { GitCredential } from '@/portainer/views/account/git-credential/types';
import { GitCredential } from '@/react/portainer/account/git-credentials/types';
import { getGitCredentials } from '@/react/portainer/account/git-credentials/git-credentials.service';
import { validateForm } from '@@/form-components/validate-form';

View file

@ -5,8 +5,8 @@ import { GitFormModel } from '@/react/portainer/gitops/types';
import { validateGitForm } from '@/react/portainer/gitops/GitForm';
import { notifyError } from '@/portainer/services/notifications';
import { IAuthenticationService } from '@/portainer/services/types';
import { getGitCredentials } from '@/portainer/views/account/git-credential/gitCredential.service';
import { GitCredential } from '@/portainer/views/account/git-credential/types';
import { getGitCredentials } from '@/react/portainer/account/git-credentials/git-credentials.service';
import { GitCredential } from '@/react/portainer/account/git-credentials/types';
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
export default class GitFormController {

View file

@ -1,35 +0,0 @@
import Lightmode from '@/assets/ico/theme/lightmode.svg?c';
import Darkmode from '@/assets/ico/theme/darkmode.svg?c';
import Highcontrastmode from '@/assets/ico/theme/highcontrastmode.svg?c';
import Automode from '@/assets/ico/theme/auto.svg?c';
export const options = [
{
id: 'light',
icon: Lightmode,
label: 'Light Theme',
description: 'Default color mode',
value: 'light',
},
{
id: 'dark',
icon: Darkmode,
label: 'Dark Theme',
description: 'Dark color mode',
value: 'dark',
},
{
id: 'highcontrast',
icon: Highcontrastmode,
label: 'High Contrast',
description: 'High contrast color mode',
value: 'highcontrast',
},
{
id: 'auto',
icon: Automode,
label: 'Auto',
description: 'Sync with system theme',
value: 'auto',
},
];

View file

@ -1,7 +1,7 @@
import { notifyError, notifySuccess } from '@/portainer/services/notifications';
import { queryKeys } from '@/portainer/users/queries/queryKeys';
import { queryClient } from '@/react-tools/react-query';
import { options } from './options';
import { options } from '@/react/portainer/account/AccountView/theme-options';
export default class ThemeSettingsController {
/* @ngInject */

View file

@ -1,43 +0,0 @@
import { server, rest } from '@/setup-tests/server';
import { getLicenses } from './license.service';
import type { License } from './types';
describe('getLicenses', () => {
it('on success should return the server body', async () => {
const catchFn = jest.fn();
const thenFn = jest.fn();
const data: License[] = [];
server.use(
rest.get('/api/licenses', (req, res, ctx) => res(ctx.json(data)))
);
const promise = getLicenses();
await promise.then(thenFn).catch(catchFn);
expect(catchFn).not.toHaveBeenCalled();
expect(thenFn).toHaveBeenCalledWith(data);
});
it('on failure should return the server message', async () => {
const catchFn = jest.fn();
const thenFn = jest.fn();
const message = 'message';
const details = 'details';
server.use(
rest.get('/api/licenses', (req, res, ctx) =>
res(ctx.status(400), ctx.json({ message, details }))
)
);
const promise = getLicenses();
await promise.then(thenFn, catchFn);
expect(catchFn).toHaveBeenCalledWith(new Error(message));
expect(thenFn).not.toHaveBeenCalled();
});
});

View file

@ -1,112 +1,11 @@
import _ from 'lodash';
import { AxiosError } from 'axios';
import axios from '@/portainer/services/axios';
import { License, LicenseInfo } from './types';
type Listener = (info: LicenseInfo) => void;
interface Store {
data?: LicenseInfo;
lastLoaded?: number;
invalidated: boolean;
listeners: Listener[];
}
const store: Store = {
listeners: [],
invalidated: true,
};
export async function getLicenses() {
try {
const { data } = await axios.get<License[]>(buildUrl());
return data;
} catch (e) {
const axiosError = e as AxiosError;
throw new Error(axiosError.response?.data.message);
}
}
interface AttachResponse {
licenses: License[];
failedKeys: Record<string, string>;
}
export async function attachLicense(licenseKeys: string[]) {
try {
const { data } = await axios.post<AttachResponse>(buildUrl(), {
licenseKeys,
});
if (Object.keys(data.failedKeys).length === licenseKeys.length) {
return data;
}
store.invalidated = true;
getLicenseInfo();
return data;
} catch (e) {
const axiosError = e as AxiosError;
throw new Error(axiosError.response?.data.message);
}
}
interface RemoveResponse {
failedKeys: Record<string, string>;
}
export async function removeLicense(licenseKeys: string[]) {
try {
const { data } = await axios.post<RemoveResponse>(buildUrl('remove'), {
licenseKeys,
});
if (Object.keys(data.failedKeys).length === licenseKeys.length) {
return data;
}
store.invalidated = true;
getLicenseInfo();
return data;
} catch (e) {
const axiosError = e as AxiosError;
throw new Error(axiosError.response?.data.message);
}
}
export async function getLicenseInfo() {
try {
if (
store.data &&
!store.invalidated &&
store.lastLoaded &&
Math.abs(store.lastLoaded - Date.now()) < 1000 * 30
) {
return store.data;
}
const { data: info } = await axios.get<LicenseInfo>(buildUrl('info'));
store.data = info;
store.lastLoaded = Date.now();
store.invalidated = false;
store.listeners.forEach((listener) => listener(info));
return info;
} catch (e) {
const axiosError = e as AxiosError;
throw new Error(axiosError.response?.data.message);
}
}
export function subscribe(listener: Listener) {
store.listeners.push(listener);
}
export function unsubscribe(listener: Listener) {
_.remove<Listener>(store.listeners, listener);
}
import {
getLicenses,
attachLicense,
removeLicense,
getLicenseInfo,
unsubscribe,
subscribe,
} from '@/react/portainer/licenses/license.service';
/* @ngInject */
export function LicenseService() {
@ -119,12 +18,3 @@ export function LicenseService() {
unsubscribe,
};
}
function buildUrl(action = '') {
let url = 'licenses';
if (action) {
url += `/${action}`;
}
return url;
}

View file

@ -1,45 +0,0 @@
// matches https://github.com/portainer/liblicense/blob/master/liblicense.go#L66-L74
export enum Edition {
CE = 1,
BE,
EE,
}
// matches https://github.com/portainer/liblicense/blob/master/liblicense.go#L60-L64
export enum LicenseType {
Trial = 1,
Subscription,
}
// matches https://github.com/portainer/liblicense/blob/master/liblicense.go#L35-L50
export interface License {
id: string;
company: string;
created: number;
email: string;
expiresAfter: number;
licenseKey: string;
nodes: number;
productEdition: Edition;
revoked: boolean;
revokedAt: number;
type: LicenseType;
version: number;
reference: string;
expiresAt: number;
}
// matches https://github.com/portainer/portainer-ee/blob/c4575bf528583fe1682267db4ee40a11a905f611/api/portainer.go#L588-L597
export interface LicenseInfo {
productEdition: Edition;
company: string;
email: string;
createdAt: number;
expiresAt: number;
nodes: number;
type: LicenseType;
valid: boolean;
enforcedAt: number;
enforced: boolean;
}

View file

@ -1,37 +0,0 @@
import { useQuery } from 'react-query';
import { error as notifyError } from '@/portainer/services/notifications';
import { useNodesCount } from '@/react/portainer/system/useNodesCount';
import { getLicenseInfo } from './license.service';
import { LicenseInfo, LicenseType } from './types';
export function useLicenseInfo() {
const { isLoading, data: info } = useQuery<LicenseInfo, Error>(
'licenseInfo',
() => getLicenseInfo(),
{
onError(error) {
notifyError('Failure', error as Error, 'Failed to get license info');
},
}
);
return { isLoading, info };
}
export function useIntegratedLicenseInfo() {
const { isLoading: isLoadingNodes, data: nodesCount = 0 } = useNodesCount();
const { isLoading: isLoadingLicense, info } = useLicenseInfo();
if (
isLoadingLicense ||
isLoadingNodes ||
!info ||
info.type === LicenseType.Trial
) {
return null;
}
return { licenseInfo: info as LicenseInfo, usedNodes: nodesCount };
}

View file

@ -1,42 +0,0 @@
import { Edit } from 'lucide-react';
import { FeatureId } from '@/react/portainer/feature-flags/enums';
import Microsoft from '@/assets/ico/vendor/microsoft.svg?c';
import Google from '@/assets/ico/vendor/google.svg?c';
import Github from '@/assets/ico/vendor/github.svg?c';
import { BadgeIcon } from '@@/BadgeIcon';
export const options = [
{
id: 'microsoft',
icon: Microsoft,
label: 'Microsoft',
description: 'Microsoft OAuth provider',
value: 'microsoft',
feature: FeatureId.HIDE_INTERNAL_AUTH,
},
{
id: 'google',
icon: Google,
label: 'Google',
description: 'Google OAuth provider',
value: 'google',
feature: FeatureId.HIDE_INTERNAL_AUTH,
},
{
id: 'github',
icon: Github,
label: 'Github',
description: 'Github OAuth provider',
value: 'github',
feature: FeatureId.HIDE_INTERNAL_AUTH,
},
{
id: 'custom',
icon: <BadgeIcon icon={Edit} />,
label: 'Custom',
description: 'Custom OAuth provider',
value: 'custom',
},
];

View file

@ -1,4 +1,4 @@
import { options } from './oauth-options';
import { options } from '@/react/portainer/settings/AuthenticationView/oauth-options';
export default class OAuthProviderSelectorController {
constructor() {

View file

@ -0,0 +1,58 @@
import angular from 'angular';
import { r2a } from '@/react-tools/react2angular';
import { withCurrentUser } from '@/react-tools/withCurrentUser';
import { withReactQuery } from '@/react-tools/withReactQuery';
import { withUIRouter } from '@/react-tools/withUIRouter';
import { PorAccessControlFormTeamSelector } from '@/react/portainer/access-control/PorAccessControlForm/TeamsSelector';
import { PorAccessControlFormUserSelector } from '@/react/portainer/access-control/PorAccessControlForm/UsersSelector';
import { PorAccessManagementUsersSelector } from '@/react/portainer/access-control/AccessManagement/PorAccessManagementUsersSelector';
import { AccessTypeSelector } from '@/react/portainer/access-control/EditDetails/AccessTypeSelector';
import { AccessControlPanel } from '@/react/portainer/access-control';
export const accessControlModule = angular
.module('portainer.app.react.components.access-control', [])
.component(
'accessControlPanel',
r2a(withUIRouter(withReactQuery(withCurrentUser(AccessControlPanel))), [
'disableOwnershipChange',
'onUpdateSuccess',
'resourceControl',
'resourceId',
'resourceType',
'environmentId',
])
)
.component(
'accessTypeSelector',
r2a(AccessTypeSelector, [
'isAdmin',
'isPublicVisible',
'name',
'onChange',
'value',
'teams',
])
)
.component(
'porAccessControlFormTeamSelector',
r2a(PorAccessControlFormTeamSelector, [
'inputId',
'onChange',
'options',
'value',
])
)
.component(
'porAccessControlFormUserSelector',
r2a(PorAccessControlFormUserSelector, [
'inputId',
'onChange',
'options',
'value',
])
)
.component(
'porAccessManagementUsersSelector',
r2a(PorAccessManagementUsersSelector, ['onChange', 'options', 'value'])
).name;

View file

@ -0,0 +1,16 @@
import angular from 'angular';
import { r2a } from '@/react-tools/react2angular';
import { withControlledInput } from '@/react-tools/withControlledInput';
import { EdgeKeyDisplay } from '@/react/portainer/environments/ItemView/EdgeKeyDisplay';
import { KVMControl } from '@/react/portainer/environments/KvmView/KVMControl';
import { GpusList } from '@/react/portainer/environments/wizard/EnvironmentsCreationView/shared/Hardware/GpusList';
export const environmentsModule = angular
.module('portainer.app.react.components.environments', [])
.component('edgeKeyDisplay', r2a(EdgeKeyDisplay, ['edgeKey']))
.component('kvmControl', r2a(KVMControl, ['deviceId', 'server', 'token']))
.component(
'gpusList',
r2a(withControlledInput(GpusList), ['value', 'onChange'])
).name;

View file

@ -9,6 +9,7 @@ import { GitForm } from '@/react/portainer/gitops/GitForm';
import { AuthFieldset } from '@/react/portainer/gitops/AuthFieldset';
import { InfoPanel } from '@/react/portainer/gitops/InfoPanel';
import { RefField } from '@/react/portainer/gitops/RefField';
import { TimeWindowDisplay } from '@/react/portainer/gitops/TimeWindowDisplay';
export const gitFormModule = angular
.module('portainer.app.components.forms.git', [])
@ -66,4 +67,8 @@ export const gitFormModule = angular
'value',
'isUrlValid',
])
)
.component(
'timeWindowDisplay',
r2a(withReactQuery(withUIRouter(TimeWindowDisplay)), [])
).name;

View file

@ -1,26 +1,12 @@
import angular from 'angular';
import { r2a } from '@/react-tools/react2angular';
import {
DefaultRegistryAction,
DefaultRegistryDomain,
DefaultRegistryName,
} from '@/react/portainer/registries/ListView/DefaultRegistry';
import { Icon } from '@/react/components/Icon';
import { ReactQueryDevtoolsWrapper } from '@/react/components/ReactQueryDevtoolsWrapper';
import { AccessControlPanel } from '@/react/portainer/access-control';
import { withCurrentUser } from '@/react-tools/withCurrentUser';
import { withReactQuery } from '@/react-tools/withReactQuery';
import { withUIRouter } from '@/react-tools/withUIRouter';
import { SettingsFDO } from '@/react/portainer/settings/EdgeComputeView/SettingsFDO';
import { SettingsOpenAMT } from '@/react/portainer/settings/EdgeComputeView/SettingsOpenAMT';
import { InternalAuth } from '@/react/portainer/settings/AuthenticationView/InternalAuth';
import { PorAccessControlFormTeamSelector } from '@/react/portainer/access-control/PorAccessControlForm/TeamsSelector';
import { PorAccessControlFormUserSelector } from '@/react/portainer/access-control/PorAccessControlForm/UsersSelector';
import { PorAccessManagementUsersSelector } from '@/react/portainer/access-control/AccessManagement/PorAccessManagementUsersSelector';
import { AccessTypeSelector } from '@/react/portainer/access-control/EditDetails/AccessTypeSelector';
import { EdgeKeyDisplay } from '@/react/portainer/environments/ItemView/EdgeKeyDisplay';
import { Icon } from '@@/Icon';
import { ReactQueryDevtoolsWrapper } from '@@/ReactQueryDevtoolsWrapper';
import { PageHeader } from '@@/PageHeader';
import { TagSelector } from '@@/TagSelector';
import { Loading } from '@@/Widget/Loading';
@ -38,18 +24,21 @@ import { PortainerSelect } from '@@/form-components/PortainerSelect';
import { Slider } from '@@/form-components/Slider';
import { TagButton } from '@@/TagButton';
import { BETeaserButton } from '@@/BETeaserButton';
import { TimeWindowDisplay } from '@@/TimeWindowDisplay';
import { CodeEditor } from '@@/CodeEditor';
import { fileUploadField } from './file-upload-field';
import { switchField } from './switch-field';
import { customTemplatesModule } from './custom-templates';
import { gitFormModule } from './git-form';
import { settingsModule } from './settings';
import { accessControlModule } from './access-control';
export const componentsModule = angular
.module('portainer.app.react.components', [
customTemplatesModule,
gitFormModule,
settingsModule,
accessControlModule,
])
.component(
'tagSelector',
@ -74,17 +63,7 @@ export const componentsModule = angular
'tagButton',
r2a(TagButton, ['value', 'label', 'title', 'onRemove'])
)
.component(
'accessTypeSelector',
r2a(AccessTypeSelector, [
'isAdmin',
'isPublicVisible',
'name',
'onChange',
'value',
'teams',
])
)
.component(
'portainerTooltip',
r2a(Tooltip, ['message', 'position', 'className', 'setHtmlMessage'])
@ -143,38 +122,6 @@ export const componentsModule = angular
])
)
.component('badgeIcon', r2a(BadgeIcon, ['icon', 'size']))
.component(
'accessControlPanel',
r2a(withUIRouter(withReactQuery(withCurrentUser(AccessControlPanel))), [
'disableOwnershipChange',
'onUpdateSuccess',
'resourceControl',
'resourceId',
'resourceType',
'environmentId',
])
)
.component(
'defaultRegistryName',
r2a(withReactQuery(DefaultRegistryName), [])
)
.component(
'defaultRegistryAction',
r2a(withReactQuery(DefaultRegistryAction), [])
)
.component(
'defaultRegistryDomain',
r2a(withReactQuery(DefaultRegistryDomain), [])
)
.component(
'settingsFdo',
r2a(withUIRouter(withReactQuery(SettingsFDO)), ['onSubmit', 'settings'])
)
.component('settingsOpenAmt', r2a(SettingsOpenAMT, ['onSubmit', 'settings']))
.component(
'internalAuth',
r2a(InternalAuth, ['onSaveSettings', 'isLoading', 'value', 'onChange'])
)
.component(
'teamsSelector',
r2a(TeamsSelector, [
@ -188,24 +135,6 @@ export const componentsModule = angular
'disabled',
])
)
.component(
'porAccessControlFormTeamSelector',
r2a(PorAccessControlFormTeamSelector, [
'inputId',
'onChange',
'options',
'value',
])
)
.component(
'porAccessControlFormUserSelector',
r2a(PorAccessControlFormUserSelector, [
'inputId',
'onChange',
'options',
'value',
])
)
.component(
'porSelect',
r2a(PortainerSelect, [
@ -234,15 +163,7 @@ export const componentsModule = angular
'dataCy',
])
)
.component(
'porAccessManagementUsersSelector',
r2a(PorAccessManagementUsersSelector, ['onChange', 'options', 'value'])
)
.component('edgeKeyDisplay', r2a(EdgeKeyDisplay, ['edgeKey']))
.component(
'timeWindowDisplay',
r2a(withReactQuery(withUIRouter(TimeWindowDisplay)), [])
)
.component(
'reactCodeEditor',
r2a(CodeEditor, [

View file

@ -0,0 +1,24 @@
import angular from 'angular';
import { r2a } from '@/react-tools/react2angular';
import { withReactQuery } from '@/react-tools/withReactQuery';
import {
DefaultRegistryAction,
DefaultRegistryDomain,
DefaultRegistryName,
} from '@/react/portainer/registries/ListView/DefaultRegistry';
export const registriesModule = angular
.module('portainer.app.react.components.registries', [])
.component(
'defaultRegistryName',
r2a(withReactQuery(DefaultRegistryName), [])
)
.component(
'defaultRegistryAction',
r2a(withReactQuery(DefaultRegistryAction), [])
)
.component(
'defaultRegistryDomain',
r2a(withReactQuery(DefaultRegistryDomain), [])
).name;

View file

@ -0,0 +1,20 @@
import angular from 'angular';
import { SettingsFDO } from '@/react/portainer/settings/EdgeComputeView/SettingsFDO';
import { SettingsOpenAMT } from '@/react/portainer/settings/EdgeComputeView/SettingsOpenAMT';
import { InternalAuth } from '@/react/portainer/settings/AuthenticationView/InternalAuth';
import { r2a } from '@/react-tools/react2angular';
import { withReactQuery } from '@/react-tools/withReactQuery';
import { withUIRouter } from '@/react-tools/withUIRouter';
export const settingsModule = angular
.module('portainer.app.react.components.settings', [])
.component(
'settingsFdo',
r2a(withUIRouter(withReactQuery(SettingsFDO)), ['onSubmit', 'settings'])
)
.component('settingsOpenAmt', r2a(SettingsOpenAMT, ['onSubmit', 'settings']))
.component(
'internalAuth',
r2a(InternalAuth, ['onSaveSettings', 'isLoading', 'value', 'onChange'])
).name;

View file

@ -1,28 +0,0 @@
import { Edit } from 'lucide-react';
import { FeatureId } from '@/react/portainer/feature-flags/enums';
import Openldap from '@/assets/ico/vendor/openldap.svg?c';
import { BadgeIcon } from '@@/BadgeIcon';
const SERVER_TYPES = {
CUSTOM: 0,
OPEN_LDAP: 1,
AD: 2,
};
export const options = [
{
id: 'ldap_custom',
icon: <BadgeIcon icon={Edit} />,
label: 'Custom',
value: SERVER_TYPES.CUSTOM,
},
{
id: 'ldap_openldap',
icon: Openldap,
label: 'OpenLDAP',
value: SERVER_TYPES.OPEN_LDAP,
feature: FeatureId.EXTERNAL_AUTH_LDAP,
},
];

View file

@ -1,5 +1,5 @@
import { buildLdapSettingsModel, buildOpenLDAPSettingsModel } from '@/portainer/settings/authentication/ldap/ldap-settings.model';
import { options } from './ldap-options';
import { options } from '@/react/portainer/settings/AuthenticationView/ldap-options';
const SERVER_TYPES = {
CUSTOM: 0,

View file

@ -1,155 +0,0 @@
import { useMutation, useQuery, useQueryClient } from 'react-query';
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { success as notifySuccess } from '@/portainer/services/notifications';
import {
CreateGitCredentialPayload,
GitCredential,
UpdateGitCredentialPayload,
} from './types';
export async function createGitCredential(
gitCredential: CreateGitCredentialPayload
) {
try {
await axios.post(buildGitUrl(gitCredential.userId), gitCredential);
} catch (e) {
throw parseAxiosError(e as Error, 'Unable to create git credential');
}
}
export async function getGitCredentials(userId: number) {
try {
const { data } = await axios.get<GitCredential[]>(buildGitUrl(userId));
return data;
} catch (e) {
throw parseAxiosError(e as Error, 'Unable to get git credentials');
}
}
export async function getGitCredential(userId: number, id: number) {
try {
const { data } = await axios.get<GitCredential>(buildGitUrl(userId, id));
return data;
} catch (e) {
throw parseAxiosError(e as Error, 'Unable to get git credential');
}
}
export async function deleteGitCredential(credential: GitCredential) {
try {
await axios.delete<GitCredential[]>(
buildGitUrl(credential.userId, credential.id)
);
} catch (e) {
throw parseAxiosError(e as Error, 'Unable to delete git credential');
}
}
export async function updateGitCredential(
credential: Partial<UpdateGitCredentialPayload>,
userId: number,
id: number
) {
try {
const { data } = await axios.put(buildGitUrl(userId, id), credential);
return data;
} catch (e) {
throw parseAxiosError(e as Error, 'Unable to update credential');
}
}
export function useUpdateGitCredentialMutation() {
const queryClient = useQueryClient();
return useMutation(
({
credential,
userId,
id,
}: {
credential: UpdateGitCredentialPayload;
userId: number;
id: number;
}) => updateGitCredential(credential, userId, id),
{
onSuccess: (_, data) => {
notifySuccess(
'Git credential updated successfully',
data.credential.name
);
return queryClient.invalidateQueries(['gitcredentials']);
},
meta: {
error: {
title: 'Failure',
message: 'Unable to update credential',
},
},
}
);
}
export function useDeleteGitCredentialMutation() {
const queryClient = useQueryClient();
return useMutation(deleteGitCredential, {
onSuccess: (_, credential) => {
notifySuccess('Git Credential deleted successfully', credential.name);
return queryClient.invalidateQueries(['gitcredentials']);
},
meta: {
error: {
title: 'Failure',
message: 'Unable to delete git credential',
},
},
});
}
export function useGitCredentials(userId: number) {
return useQuery('gitcredentials', () => getGitCredentials(userId), {
staleTime: 20,
meta: {
error: {
title: 'Failure',
message: 'Unable to retrieve git credentials',
},
},
});
}
export function useGitCredential(userId: number, id: number) {
return useQuery(['gitcredentials', id], () => getGitCredential(userId, id), {
meta: {
error: {
title: 'Failure',
message: 'Unable to retrieve git credential',
},
},
});
}
export function useCreateGitCredentialMutation() {
const queryClient = useQueryClient();
return useMutation(createGitCredential, {
onSuccess: (_, payload) => {
notifySuccess('Credentials created successfully', payload.name);
return queryClient.invalidateQueries(['gitcredentials']);
},
meta: {
error: {
title: 'Failure',
message: 'Unable to create credential',
},
},
});
}
function buildGitUrl(userId: number, credentialId?: number) {
return credentialId
? `/users/${userId}/gitcredentials/${credentialId}`
: `/users/${userId}/gitcredentials`;
}

View file

@ -1,35 +0,0 @@
import {
PaginationTableSettings,
SortableTableSettings,
} from '@@/datatables/types';
export interface GitCredentialTableSettings
extends SortableTableSettings,
PaginationTableSettings {}
export interface GitCredentialFormValues {
name: string;
username?: string;
password: string;
}
export interface CreateGitCredentialPayload {
userId: number;
name: string;
username?: string;
password: string;
}
export interface UpdateGitCredentialPayload {
name: string;
username?: string;
password: string;
}
export type GitCredential = {
id: number;
userId: number;
name: string;
username: string;
creationDate: number;
};

View file

@ -1,15 +0,0 @@
.canvas-container {
display: contents;
}
.kvm-maximized {
position: fixed;
background: white;
bottom: 0;
top: 0;
left: 0;
width: 100vw;
z-index: 1000;
max-height: 100% !important;
overflow-y: scroll;
}

View file

@ -1,32 +0,0 @@
import { KVM } from '@open-amt-cloud-toolkit/ui-toolkit-react/reactjs/src/kvm.bundle';
import { react2angular } from '@/react-tools/react2angular';
import './KVMControl.css';
export interface KVMControlProps {
deviceId: string;
server: string;
token: string;
}
export function KVMControl({ deviceId, server, token }: KVMControlProps) {
if (!deviceId || !server || !token) return <div>Loading...</div>;
return (
<KVM
deviceId={deviceId}
mpsServer={`https://${server}/mps/ws/relay`}
authToken={token}
mouseDebounceTime="200"
canvasHeight="100%"
canvasWidth="100%"
/>
);
}
export const KVMControlAngular = react2angular(KVMControl, [
'deviceId',
'server',
'token',
]);

View file

@ -1,5 +0,0 @@
import angular from 'angular';
import { KVMControlAngular } from '@/portainer/views/endpoints/kvm/KVMControl';
angular.module('portainer.app').component('kvmControl', KVMControlAngular).name;

View file

@ -1,5 +1,5 @@
import { getEnvironments } from '@/react/portainer/environments/environment.service';
import { restoreOptions } from './restore-options';
import { restoreOptions } from '@/react/portainer/init/InitAdminView/restore-options';
angular.module('portainer.app').controller('InitAdminController', [
'$scope',

View file

@ -1,23 +0,0 @@
import { Download, Upload } from 'lucide-react';
import { FeatureId } from '@/react/portainer/feature-flags/enums';
import { BoxSelectorOption } from '@@/BoxSelector';
export const restoreOptions: ReadonlyArray<BoxSelectorOption<string>> = [
{
id: 'restore_file',
value: 'file',
icon: Upload,
iconType: 'badge',
label: 'Upload backup file',
},
{
id: 'restore_s3',
value: 's3',
icon: Download,
iconType: 'badge',
label: 'Retrieve from S3',
feature: FeatureId.S3_RESTORE,
},
] as const;

View file

@ -1,7 +1,7 @@
import _ from 'lodash';
import { RegistryTypes } from 'Portainer/models/registryTypes';
import { RegistryCreateFormValues } from 'Portainer/models/registry';
import { options } from './options';
import { options } from '@/react/portainer/registries/CreateView/options';
class CreateRegistryController {
/* @ngInject */

View file

@ -1,62 +0,0 @@
import { Edit } from 'lucide-react';
import Docker from '@/assets/ico/vendor/docker.svg?c';
import Ecr from '@/assets/ico/vendor/ecr.svg?c';
import Quay from '@/assets/ico/vendor/quay.svg?c';
import Proget from '@/assets/ico/vendor/proget.svg?c';
import Azure from '@/assets/ico/vendor/azure.svg?c';
import Gitlab from '@/assets/ico/vendor/gitlab.svg?c';
import { BadgeIcon } from '@@/BadgeIcon';
export const options = [
{
id: 'registry_dockerhub',
icon: Docker,
label: 'DockerHub',
description: 'DockerHub authenticated account',
value: '6',
},
{
id: 'registry_aws_ecr',
icon: Ecr,
label: 'AWS ECR',
description: 'Amazon elastic container registry',
value: '7',
},
{
id: 'registry_quay',
icon: Quay,
label: 'Quay.io',
description: 'Quay container registry',
value: '1',
},
{
id: 'registry_proget',
icon: Proget,
label: 'ProGet',
description: 'ProGet container registry',
value: '5',
},
{
id: 'registry_azure',
icon: Azure,
label: 'Azure',
description: 'Azure container registry',
value: '2',
},
{
id: 'registry_gitlab',
icon: Gitlab,
label: 'GitLab',
description: 'GitLab container registry',
value: '4',
},
{
id: 'registry_custom',
icon: <BadgeIcon icon={Edit} />,
label: 'Custom registry',
description: 'Define your own registry',
value: '3',
},
];

View file

@ -1,40 +0,0 @@
import { ArrowDownCircle } from 'lucide-react';
import { FeatureId } from '@/react/portainer/feature-flags/enums';
import Microsoft from '@/assets/ico/vendor/microsoft.svg?c';
import Ldap from '@/assets/ico/ldap.svg?c';
import OAuth from '@/assets/ico/oauth.svg?c';
import { BadgeIcon } from '@@/BadgeIcon';
export const options = [
{
id: 'auth_internal',
icon: <BadgeIcon icon={ArrowDownCircle} />,
label: 'Internal',
description: 'Internal authentication mechanism',
value: 1,
},
{
id: 'auth_ldap',
icon: Ldap,
label: 'LDAP',
description: 'LDAP authentication',
value: 2,
},
{
id: 'auth_ad',
icon: Microsoft,
label: 'Microsoft Active Directory',
description: 'AD authentication',
value: 4,
feature: FeatureId.HIDE_INTERNAL_AUTH,
},
{
id: 'auth_oauth',
icon: OAuth,
label: 'OAuth',
description: 'OAuth authentication',
value: 3,
},
];

View file

@ -2,7 +2,7 @@ import angular from 'angular';
import _ from 'lodash-es';
import { buildLdapSettingsModel, buildAdSettingsModel } from '@/portainer/settings/authentication/ldap/ldap-settings.model';
import { options } from './options';
import { options } from '@/react/portainer/settings/AuthenticationView/InternalAuth/options';
angular.module('portainer.app').controller('SettingsAuthenticationController', SettingsAuthenticationController);

View file

@ -1,22 +0,0 @@
import { DownloadCloud, UploadCloud } from 'lucide-react';
import { FeatureId } from '@/react/portainer/feature-flags/enums';
import { BadgeIcon } from '@@/BadgeIcon';
export const options = [
{
id: 'backup_file',
icon: <BadgeIcon icon={DownloadCloud} />,
label: 'Download backup file',
value: 'file',
},
{
id: 'backup_s3',
icon: <BadgeIcon icon={UploadCloud} />,
label: 'Store in S3',
description: 'Define a cron schedule',
value: 's3',
feature: FeatureId.S3_BACKUP_SETTING,
},
];

View file

@ -1,7 +1,7 @@
import angular from 'angular';
import { FeatureId } from '@/react/portainer/feature-flags/enums';
import { options } from './options';
import { options } from '@/react/portainer/settings/SettingsView/backup-options';
angular.module('portainer.app').controller('SettingsController', [
'$scope',