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
pull/8527/head
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 +0,0 @@
<svg width="36" height="40" viewBox="0 0 36 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.3817 5.28003C22.1592 5.28003 28.4649 11.5865 28.4649 19.365C28.4649 27.1435 22.1592 33.45 14.3817 33.45C6.60065 33.4535 0.294922 27.1435 0.294922 19.365C0.294922 11.5865 6.60065 5.28003 14.3817 5.28003Z" fill="#E0F2FE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.5297 15.5683C14.8574 15.3761 14.1468 15.3553 13.4642 15.508C12.7816 15.6606 12.1493 15.9817 11.6262 16.4413C11.1031 16.9008 10.7063 17.4839 10.4728 18.136C10.3554 18.464 9.99118 18.6358 9.65933 18.5198C9.32747 18.4037 9.15365 18.0437 9.27108 17.7157C9.57638 16.8629 10.0953 16.1004 10.7793 15.4995C11.4634 14.8985 12.2903 14.4786 13.1829 14.279C14.0755 14.0794 15.0048 14.1065 15.8839 14.3579C16.7598 14.6083 17.5575 15.0731 18.2032 15.7092L19.5868 16.9943V15.3008C19.5868 14.9528 19.8722 14.6707 20.2242 14.6707C20.5762 14.6707 20.8616 14.9528 20.8616 15.3008V18.4509C20.8616 18.7988 20.5762 19.0809 20.2242 19.0809H17.0373C16.6852 19.0809 16.3999 18.7988 16.3999 18.4509C16.3999 18.1029 16.6852 17.8208 17.0373 17.8208H18.6151L17.3232 16.6209L17.3088 16.6072C16.8141 16.1179 16.202 15.7605 15.5297 15.5683ZM7.90137 20.5509C7.90137 20.203 8.18674 19.9209 8.53875 19.9209H11.7257C12.0777 19.9209 12.3631 20.203 12.3631 20.5509C12.3631 20.8989 12.0777 21.1809 11.7257 21.1809H10.1479L11.4398 22.3809L11.4541 22.3946C11.9489 22.8839 12.561 23.2413 13.2332 23.4335C13.9055 23.6257 14.6161 23.6465 15.2987 23.4938C15.9813 23.3411 16.6137 23.0201 17.1368 22.5605C17.6599 22.1009 18.0566 21.5179 18.2901 20.8658C18.4075 20.5377 18.7718 20.3659 19.1036 20.482C19.4355 20.5981 19.6093 20.9581 19.4919 21.2861C19.1866 22.1389 18.6677 22.9013 17.9836 23.5023C17.2996 24.1033 16.4727 24.5231 15.58 24.7228C14.6874 24.9224 13.7582 24.8953 12.879 24.6439C12.0032 24.3935 11.2055 23.9287 10.5598 23.2926L9.17614 22.0074V23.701C9.17614 24.049 8.89077 24.331 8.53875 24.331C8.18674 24.331 7.90137 24.049 7.90137 23.701V20.5509Z" fill="#0086C9"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,4 +0,0 @@
<svg width="36" height="40" viewBox="0 0 36 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.3817 5.28003C22.1592 5.28003 28.4649 11.5865 28.4649 19.365C28.4649 27.1435 22.1592 33.45 14.3817 33.45C6.60065 33.4535 0.294922 27.1435 0.294922 19.365C0.294922 11.5865 6.60065 5.28003 14.3817 5.28003Z" fill="#E0F2FE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4242 13.7577C14.5475 13.974 14.5308 14.2418 14.3815 14.4415C13.8988 15.087 13.6665 15.8823 13.7269 16.6828C13.7873 17.4832 14.1363 18.2357 14.7105 18.8033C15.2848 19.3709 16.046 19.7159 16.8559 19.7756C17.6657 19.8353 18.4703 19.6057 19.1234 19.1286C19.3254 18.981 19.5963 18.9644 19.8152 19.0863C20.0341 19.2083 20.1601 19.4459 20.1369 19.6932C20.0353 20.7805 19.6224 21.8167 18.9467 22.6806C18.271 23.5444 17.3604 24.2002 16.3213 24.5712C15.2823 24.9421 14.1579 25.0129 13.0797 24.7753C12.0014 24.5376 11.014 24.0014 10.2328 23.2293C9.45166 22.4571 8.90913 21.4811 8.66871 20.4153C8.42828 19.3495 8.49991 18.2381 8.87521 17.2111C9.25051 16.1841 9.91396 15.284 10.7879 14.6161C11.6619 13.9482 12.7102 13.5401 13.8103 13.4396C14.0604 13.4168 14.3008 13.5413 14.4242 13.7577ZM12.6775 14.989C12.2816 15.1435 11.9077 15.353 11.5677 15.6129C10.8852 16.1344 10.3672 16.8373 10.0742 17.6392C9.78113 18.4411 9.7252 19.3089 9.91293 20.1411C10.1007 20.9733 10.5243 21.7354 11.1342 22.3383C11.7442 22.9412 12.5152 23.3599 13.3571 23.5454C14.199 23.731 15.077 23.6757 15.8883 23.3861C16.6996 23.0964 17.4106 22.5844 17.9382 21.9098C18.2012 21.5737 18.4131 21.2041 18.5695 20.8128C17.9916 21.0012 17.3774 21.0776 16.7611 21.0321C15.6468 20.95 14.5993 20.4753 13.8091 19.6943C13.019 18.9133 12.5387 17.8779 12.4556 16.7765C12.4097 16.1672 12.4869 15.5602 12.6775 14.989Z" fill="#0086C9"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -1,4 +0,0 @@
<svg width="36" height="40" viewBox="0 0 36 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.3817 5.28003C22.1592 5.28003 28.4649 11.5865 28.4649 19.365C28.4649 27.1435 22.1592 33.45 14.3817 33.45C6.60065 33.4535 0.294922 27.1435 0.294922 19.365C0.294922 11.5865 6.60065 5.28003 14.3817 5.28003Z" fill="#E0F2FE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.72192 19.1859C8.78197 19.2875 8.85875 19.4126 8.95184 19.555C9.21567 19.9588 9.60629 20.4957 10.1132 21.0301C11.1385 22.1111 12.5641 23.106 14.3234 23.106C16.0828 23.106 17.5084 22.1111 18.5337 21.0301C19.0406 20.4957 19.4312 19.9588 19.695 19.555C19.7881 19.4126 19.8649 19.2875 19.925 19.1859C19.8649 19.0843 19.7881 18.9592 19.695 18.8167C19.4312 18.4129 19.0406 17.8761 18.5337 17.3417C17.5084 16.2606 16.0828 15.2658 14.3234 15.2658C12.5641 15.2658 11.1385 16.2606 10.1132 17.3417C9.60629 17.8761 9.21567 18.4129 8.95184 18.8167C8.85875 18.9592 8.78197 19.0843 8.72192 19.1859ZM20.6531 19.1859C21.2231 18.9041 21.223 18.9039 21.2229 18.9037L21.2219 18.9018L21.2199 18.8977L21.2132 18.8848C21.2076 18.874 21.1997 18.859 21.1896 18.8401C21.1693 18.8023 21.14 18.7487 21.1018 18.6815C21.0254 18.5473 20.9131 18.3584 20.7659 18.1331C20.4723 17.6838 20.0358 17.0831 19.4637 16.4799C18.3313 15.2859 16.5921 14.0057 14.3234 14.0057C12.0548 14.0057 10.3156 15.2859 9.18316 16.4799C8.61112 17.0831 8.17458 17.6838 7.88098 18.1331C7.73378 18.3584 7.62146 18.5473 7.54507 18.6815C7.50685 18.7487 7.47754 18.8023 7.45729 18.8401C7.44716 18.859 7.43929 18.874 7.4337 18.8848L7.42701 18.8977L7.42494 18.9018L7.42423 18.9032C7.42412 18.9034 7.42374 18.9041 7.99383 19.1859L7.42374 18.9041C7.33402 19.0815 7.33402 19.2903 7.42374 19.4676L7.99383 19.1859C7.42374 19.4676 7.42362 19.4674 7.42374 19.4676L7.42423 19.4686L7.42494 19.47L7.42701 19.4741L7.4337 19.487C7.43929 19.4978 7.44716 19.5127 7.45729 19.5317C7.47754 19.5695 7.50685 19.6231 7.54507 19.6903C7.62146 19.8245 7.73378 20.0134 7.88098 20.2386C8.17458 20.688 8.61112 21.2887 9.18316 21.8919C10.3156 23.0858 12.0548 24.366 14.3234 24.366C16.5921 24.366 18.3313 23.0858 19.4637 21.8919C20.0358 21.2887 20.4723 20.688 20.7659 20.2386C20.9131 20.0134 21.0254 19.8245 21.1018 19.6903C21.14 19.6231 21.1693 19.5695 21.1896 19.5317C21.1997 19.5127 21.2076 19.4978 21.2132 19.487L21.2199 19.4741L21.2219 19.47L21.2227 19.4686C21.2228 19.4684 21.2231 19.4676 20.6531 19.1859ZM20.6531 19.1859L21.2231 19.4676C21.3129 19.2903 21.3126 19.0811 21.2229 18.9037L20.6531 19.1859ZM14.3234 18.1096C13.7221 18.1096 13.2346 18.5915 13.2346 19.1859C13.2346 19.7803 13.7221 20.2622 14.3234 20.2622C14.9248 20.2622 15.4123 19.7803 15.4123 19.1859C15.4123 18.5915 14.9248 18.1096 14.3234 18.1096ZM11.9598 19.1859C11.9598 17.8956 13.018 16.8496 14.3234 16.8496C15.6288 16.8496 16.6871 17.8956 16.6871 19.1859C16.6871 20.4762 15.6288 21.5222 14.3234 21.5222C13.018 21.5222 11.9598 20.4762 11.9598 19.1859Z" fill="#0086C9"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,4 +0,0 @@
<svg width="36" height="40" viewBox="0 0 36 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.3817 5.28003C22.1592 5.28003 28.4649 11.5865 28.4649 19.365C28.4649 27.1435 22.1592 33.45 14.3817 33.45C6.60065 33.4535 0.294922 27.1435 0.294922 19.365C0.294922 11.5865 6.60065 5.28003 14.3817 5.28003Z" fill="#E0F2FE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.3225 11.6122C14.7096 11.6122 15.0235 11.9224 15.0235 12.3051V13.5561C15.0235 13.9388 14.7096 14.249 14.3225 14.249C13.9353 14.249 13.6215 13.9388 13.6215 13.5561V12.3051C13.6215 11.9224 13.9353 11.6122 14.3225 11.6122ZM8.90324 13.8293C9.17699 13.5587 9.62084 13.5587 9.8946 13.8293L10.7932 14.7176C11.067 14.9882 11.067 15.4269 10.7932 15.6975C10.5195 15.9681 10.0756 15.9681 9.80188 15.6975L8.90324 14.8092C8.62948 14.5386 8.62948 14.0999 8.90324 13.8293ZM19.7417 13.8293C20.0154 14.0999 20.0154 14.5386 19.7417 14.8092L18.843 15.6975C18.5693 15.9681 18.1254 15.9681 17.8517 15.6975C17.5779 15.4269 17.5779 14.9882 17.8517 14.7176L18.7503 13.8293C19.0241 13.5587 19.4679 13.5587 19.7417 13.8293ZM14.3225 16.7511C12.9621 16.7511 11.8592 17.8412 11.8592 19.1859C11.8592 20.5306 12.9621 21.6207 14.3225 21.6207C15.6829 21.6207 16.7857 20.5306 16.7857 19.1859C16.7857 17.8412 15.6829 16.7511 14.3225 16.7511ZM10.4572 19.1859C10.4572 17.0759 12.1878 15.3654 14.3225 15.3654C16.4572 15.3654 18.1877 17.0759 18.1877 19.1859C18.1877 21.2959 16.4572 23.0064 14.3225 23.0064C12.1878 23.0064 10.4572 21.2959 10.4572 19.1859ZM6.66016 19.1859C6.66016 18.8032 6.974 18.493 7.36115 18.493H8.62685C9.014 18.493 9.32784 18.8032 9.32784 19.1859C9.32784 19.5686 9.014 19.8788 8.62685 19.8788H7.36115C6.974 19.8788 6.66016 19.5686 6.66016 19.1859ZM19.3171 19.1859C19.3171 18.8032 19.6309 18.493 20.0181 18.493H21.2838C21.6709 18.493 21.9848 18.8032 21.9848 19.1859C21.9848 19.5686 21.6709 19.8788 21.2838 19.8788H20.0181C19.6309 19.8788 19.3171 19.5686 19.3171 19.1859ZM10.7932 22.6743C11.067 22.9449 11.067 23.3836 10.7932 23.6542L9.8946 24.5425C9.62084 24.8131 9.17699 24.8131 8.90324 24.5425C8.62948 24.2719 8.62948 23.8332 8.90324 23.5626L9.80188 22.6743C10.0756 22.4037 10.5195 22.4037 10.7932 22.6743ZM17.8517 22.6743C18.1254 22.4037 18.5693 22.4037 18.843 22.6743L19.7417 23.5626C20.0154 23.8332 20.0154 24.2719 19.7417 24.5425C19.4679 24.8131 19.0241 24.8131 18.7503 24.5425L17.8517 23.6542C17.5779 23.3836 17.5779 22.9449 17.8517 22.6743ZM14.3225 24.1228C14.7096 24.1228 15.0235 24.433 15.0235 24.8157V26.0667C15.0235 26.4494 14.7096 26.7596 14.3225 26.7596C13.9353 26.7596 13.6215 26.4494 13.6215 26.0667V24.8157C13.6215 24.433 13.9353 24.1228 14.3225 24.1228Z" fill="#0086C9"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1,4 +1,4 @@
import { getOptions } from './options';
import { getOptions } from '@/react/docker/networks/CreateView/macvlanOptions';
angular.module('portainer.docker').controller('NetworkMacvlanFormController', [
'$q',

View File

@ -1,12 +1,12 @@
import { confirmWebEditorDiscard } from '@@/modals/confirm';
import { options } from './options';
import { editor, upload, url } from '@@/BoxSelector/common-options/build-methods';
angular.module('portainer.docker').controller('BuildImageController', BuildImageController);
/* @ngInject */
function BuildImageController($scope, $async, $window, BuildService, Notifications, HttpRequestHelper, endpoint) {
$scope.endpoint = endpoint;
$scope.options = options;
$scope.options = [editor, upload, url];
$scope.state = {
BuildType: 'editor',

View File

@ -1,7 +0,0 @@
import {
editor,
upload,
url,
} from '@@/BoxSelector/common-options/build-methods';
export const options = [editor, upload, url] as const;

View File

@ -2,7 +2,7 @@ import _ from 'lodash-es';
import moment from 'moment';
import { editor, upload } from '@@/BoxSelector/common-options/build-methods';
import { cronMethodOptions } from './cron-method-options';
import { cronMethodOptions } from '@/react/edge/edge-jobs/CreateView/cron-method-options';
export class EdgeJobFormController {
/* @ngInject */

View File

@ -5,8 +5,8 @@ import { getEnvironments } from '@/react/portainer/environments/environment.serv
import { getTags } from '@/portainer/tags/tags.service';
import { notifyError } from '@/portainer/services/notifications';
import { buildConfirmButton } from '@@/modals/utils';
import { groupTypeOptions } from './group-type-options';
import { tagOptions } from './tag-options';
import { tagOptions } from '@/react/edge/edge-groups/CreateView/tag-options';
import { groupTypeOptions } from '@/react/edge/edge-groups/CreateView/group-type-options';
export class EdgeGroupFormController {
/* @ngInject */

View File

@ -37,7 +37,7 @@ import { confirmUpdateAppIngress } from '@/react/kubernetes/applications/CreateV
import { confirm, confirmUpdate, confirmWebEditorDiscard } from '@@/modals/confirm';
import { buildConfirmButton } from '@@/modals/utils';
import { ModalType } from '@@/modals';
import { placementOptions } from './placementTypes';
import { placementOptions } from '@/react/kubernetes/applications/CreateView/placementTypes';
class KubernetesCreateApplicationController {
/* #region CONSTRUCTOR */

View File

@ -5,10 +5,10 @@ import { KubernetesConfigurationKinds, KubernetesSecretTypeOptions } from 'Kuber
import KubernetesConfigurationHelper from 'Kubernetes/helpers/configurationHelper';
import KubernetesNamespaceHelper from 'Kubernetes/helpers/namespaceHelper';
import { getServiceAccounts } from 'Kubernetes/rest/serviceAccount';
import { typeOptions } from '@/react/kubernetes/configs/CreateView/options';
import { confirmWebEditorDiscard } from '@@/modals/confirm';
import { isConfigurationFormValid } from '../validation';
import { typeOptions } from './options';
class KubernetesCreateConfigurationController {
/* @ngInject */

View File

@ -7,9 +7,9 @@ import KubernetesNamespaceHelper from 'Kubernetes/helpers/namespaceHelper';
import { FeatureId } from '@/react/portainer/feature-flags/enums';
import { getIngressControllerClassMap, updateIngressControllerClassMap } from '@/react/kubernetes/cluster/ingressClass/utils';
import { getIsRBACEnabled } from '@/react/kubernetes/cluster/service';
import { buildConfirmButton } from '@@/modals/utils';
import { confirm } from '@@/modals/confirm';
import { getIsRBACEnabled } from '@/react/kubernetes/cluster/getIsRBACEnabled';
class KubernetesConfigureController {
/* #region CONSTRUCTOR */

View File

@ -3,7 +3,7 @@ import _ from 'lodash-es';
import { KubernetesPortainerConfigMapConfigName, KubernetesPortainerConfigMapNamespace, KubernetesPortainerConfigMapAccessKey } from 'Kubernetes/models/config-map/models';
import { UserAccessViewModel, TeamAccessViewModel } from 'Portainer/models/access';
import KubernetesConfigMapHelper from 'Kubernetes/helpers/configMapHelper';
import { getIsRBACEnabled } from '@/react/kubernetes/cluster/service';
import { getIsRBACEnabled } from '@/react/kubernetes/cluster/getIsRBACEnabled';
class KubernetesResourcePoolAccessController {
/* @ngInject */

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

@ -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,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,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,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,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,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,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

@ -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,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',

View File

@ -1,8 +1,3 @@
// theme icons
import automode from '@/assets/ico/theme/auto.svg?c';
import darkmode from '@/assets/ico/theme/darkmode.svg?c';
import lightmode from '@/assets/ico/theme/lightmode.svg?c';
import highcontrastmode from '@/assets/ico/theme/highcontrastmode.svg?c';
// general icons
import heartbeatup from '@/assets/ico/heartbeat-up.svg?c';
import heartbeatdown from '@/assets/ico/heartbeat-down.svg?c';
@ -47,10 +42,6 @@ const placeholder = Placeholder;
export const SvgIcons = {
heartbeatup,
heartbeatdown,
automode,
darkmode,
lightmode,
highcontrastmode,
dataflow,
dockericon,
git,

View File

@ -3,7 +3,7 @@ import { useMutation, useQueryClient } from 'react-query';
import { EnvironmentId } from '@/react/portainer/environments/types';
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { promiseSequence } from '@/portainer/helpers/promise-utils';
import { useIntegratedLicenseInfo } from '@/portainer/license-management/use-license.service';
import { useIntegratedLicenseInfo } from '@/react/portainer/licenses/use-license.service';
export function useAssociateDeviceMutation() {
const queryClient = useQueryClient();

View File

@ -4,7 +4,7 @@ import { EnvironmentId } from '@/react/portainer/environments/types';
export async function getIsRBACEnabled(environmentId: EnvironmentId) {
try {
const { data } = await axios.get(
const { data } = await axios.get<boolean>(
`kubernetes/${environmentId}/rbac_enabled`
);
return data;

View File

@ -1,6 +1,7 @@
import { server, rest } from '@/setup-tests/server';
import { renderWithQueryClient } from '@/react-tools/test-utils';
import { LicenseType } from '@/portainer/license-management/types';
import { LicenseType } from '../licenses/types';
import { LicenseNodePanel } from './LicenseNodePanel';

View File

@ -1,10 +1,9 @@
import { LicenseType } from '@/portainer/license-management/types';
import { useLicenseInfo } from '@/portainer/license-management/use-license.service';
import { TextTip } from '@@/Tip/TextTip';
import { InformationPanel } from '@@/InformationPanel';
import { useNodesCount } from '../system/useNodesCount';
import { useLicenseInfo } from '../licenses/use-license.service';
import { LicenseType } from '../licenses/types';
export function LicenseNodePanel() {
const nodesValid = useNodesValid();

View File

@ -1,33 +1,32 @@
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';
import { Eye, Moon, Sun, RefreshCw } from 'lucide-react';
import { BadgeIcon } from '@@/BadgeIcon';
export const options = [
{
id: 'light',
icon: Lightmode,
icon: <BadgeIcon icon={Sun} />,
label: 'Light Theme',
description: 'Default color mode',
value: 'light',
},
{
id: 'dark',
icon: Darkmode,
icon: <BadgeIcon icon={Moon} />,
label: 'Dark Theme',
description: 'Dark color mode',
value: 'dark',
},
{
id: 'highcontrast',
icon: Highcontrastmode,
icon: <BadgeIcon icon={Eye} />,
label: 'High Contrast',
description: 'High contrast color mode',
value: 'highcontrast',
},
{
id: 'auto',
icon: Automode,
icon: <BadgeIcon icon={RefreshCw} />,
label: 'Auto',
description: 'Sync with system theme',
value: 'auto',

View File

@ -1,7 +1,5 @@
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 {
@ -24,9 +22,3 @@ export function KVMControl({ deviceId, server, token }: KVMControlProps) {
/>
);
}
export const KVMControlAngular = react2angular(KVMControl, [
'deviceId',
'server',
'token',
]);

View File

@ -0,0 +1 @@
export { KVMControl } from './KVMControl';

View File

@ -3,7 +3,7 @@ import { boolean, number, object, SchemaOf, string } from 'yup';
import { GitAuthModel } from '@/react/portainer/gitops/types';
import { useDebounce } from '@/react/hooks/useDebounce';
import { GitCredential } from '@/portainer/views/account/git-credential/types';
import { GitCredential } from '@/react/portainer/account/git-credentials/types';
import { SwitchField } from '@@/form-components/SwitchField';
import { Input } from '@@/form-components/Input';

View File

@ -1,5 +1,5 @@
import { useGitCredentials } 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 { useGitCredentials } from '@/react/portainer/account/git-credentials/git-credentials.service';
import { useUser } from '@/react/hooks/useUser';
import { FormControl } from '@@/form-components/FormControl';

View File

@ -3,7 +3,7 @@ import { Form, Formik } from 'formik';
import { rest } from 'msw';
import { withUserProvider } from '@/react/test-utils/withUserProvider';
import { GitCredential } from '@/portainer/views/account/git-credential/types';
import { GitCredential } from '@/react/portainer/account/git-credentials/types';
import { GitForm, buildGitValidationSchema } from './GitForm';
import { GitFormModel } from './types';

View File

@ -5,12 +5,13 @@ import { ComposePathField } from '@/react/portainer/gitops/ComposePathField';
import { RefField } from '@/react/portainer/gitops/RefField';
import { GitFormUrlField } from '@/react/portainer/gitops/GitFormUrlField';
import { GitFormModel } from '@/react/portainer/gitops/types';
import { GitCredential } from '@/portainer/views/account/git-credential/types';
import { TimeWindowDisplay } from '@/react/portainer/gitops/TimeWindowDisplay';
import { FormSection } from '@@/form-components/FormSection';
import { TimeWindowDisplay } from '@@/TimeWindowDisplay';
import { validateForm } from '@@/form-components/validate-form';
import { GitCredential } from '../account/git-credentials/types';
import { AdditionalFileField } from './AdditionalFilesField';
import { gitAuthValidation, AuthFieldset } from './AuthFieldset';
import { AutoUpdateFieldset } from './AutoUpdateFieldset';

View File

@ -5,7 +5,7 @@ import { useCurrentEnvironment } from '@/react/hooks/useCurrentEnvironment';
import { TextTip } from '@@/Tip/TextTip';
import { withEdition } from '../portainer/feature-flags/withEdition';
import { withEdition } from '../feature-flags/withEdition';
const TimeWindowDisplayWrapper = withEdition(TimeWindowDisplay, 'BE');

View File

@ -0,0 +1,128 @@
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;
if (axiosError.response?.status === 401) {
throw new Error(
'Your session has expired, please refresh the browser and log in again.'
);
}
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 function resetState() {
store.invalidated = true;
store.data = undefined;
}
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);
}
function buildUrl(action = '') {
let url = 'licenses';
if (action) {
url += `/${action}`;
}
return url;
}

View File

@ -4,7 +4,7 @@ import {
Edition,
LicenseInfo,
LicenseType,
} from '@/portainer/license-management/types';
} from '@/react/portainer/licenses/types';
import { EnvironmentGroup } from '@/react/portainer/environments/environment-groups/types';
import { Tag } from '@/portainer/tags/types';
import { StatusResponse } from '@/react/portainer/system/useSystemStatus';