mirror of
https://github.com/portainer/portainer.git
synced 2026-08-07 10:04:49 +00:00
chore(react2angular): remove orphaned bridges [BE-13186] (#3142)
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,11 +6,7 @@ import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
|||||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||||
import { DockerfileDetails } from '@/react/docker/images/ItemView/DockerfileDetails';
|
import { DockerfileDetails } from '@/react/docker/images/ItemView/DockerfileDetails';
|
||||||
import { HealthStatus } from '@/react/docker/containers/ItemView/HealthStatus';
|
|
||||||
import { GpusList } from '@/react/docker/host/SetupView/GpusList';
|
import { GpusList } from '@/react/docker/host/SetupView/GpusList';
|
||||||
import { InsightsBox } from '@/react/components/InsightsBox';
|
|
||||||
import { BetaAlert } from '@/react/portainer/environments/update-schedules/common/BetaAlert';
|
|
||||||
import { EventsDatatable } from '@/react/docker/events/EventsDatatables';
|
|
||||||
import { AgentHostBrowser } from '@/react/docker/host/BrowseView/AgentHostBrowser';
|
import { AgentHostBrowser } from '@/react/docker/host/BrowseView/AgentHostBrowser';
|
||||||
import { AgentVolumeBrowser } from '@/react/docker/volumes/BrowseView/AgentVolumeBrowser';
|
import { AgentVolumeBrowser } from '@/react/docker/volumes/BrowseView/AgentVolumeBrowser';
|
||||||
import { ProcessesDatatable } from '@/react/docker/containers/StatsView/ProcessesDatatable';
|
import { ProcessesDatatable } from '@/react/docker/containers/StatsView/ProcessesDatatable';
|
||||||
@@ -35,22 +31,10 @@ const ngModule = angular
|
|||||||
templatesModule,
|
templatesModule,
|
||||||
])
|
])
|
||||||
.component('dockerfileDetails', r2a(DockerfileDetails, ['image']))
|
.component('dockerfileDetails', r2a(DockerfileDetails, ['image']))
|
||||||
.component('dockerHealthStatus', r2a(HealthStatus, ['health']))
|
|
||||||
.component(
|
.component(
|
||||||
'gpusList',
|
'gpusList',
|
||||||
r2a(withControlledInput(GpusList), ['value', 'onChange'])
|
r2a(withControlledInput(GpusList), ['value', 'onChange'])
|
||||||
)
|
)
|
||||||
.component(
|
|
||||||
'insightsBox',
|
|
||||||
r2a(InsightsBox, [
|
|
||||||
'header',
|
|
||||||
'content',
|
|
||||||
'insightCloseId',
|
|
||||||
'type',
|
|
||||||
'className',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component('betaAlert', r2a(BetaAlert, ['className', 'message', 'isHtml']))
|
|
||||||
.component(
|
.component(
|
||||||
'agentHostBrowserReact',
|
'agentHostBrowserReact',
|
||||||
r2a(withUIRouter(withCurrentUser(AgentHostBrowser)), [
|
r2a(withUIRouter(withCurrentUser(AgentHostBrowser)), [
|
||||||
@@ -84,7 +68,6 @@ const ngModule = angular
|
|||||||
'dockerContainerProcessesDatatable',
|
'dockerContainerProcessesDatatable',
|
||||||
r2a(withUIRouter(withReactQuery(withCurrentUser(ProcessesDatatable))), [])
|
r2a(withUIRouter(withReactQuery(withCurrentUser(ProcessesDatatable))), [])
|
||||||
)
|
)
|
||||||
.component('dockerEventsDatatable', r2a(EventsDatatable, ['dataset']))
|
|
||||||
.component(
|
.component(
|
||||||
'dockerSecretsDatatable',
|
'dockerSecretsDatatable',
|
||||||
r2a(withUIRouter(withCurrentUser(SecretsDatatable)), [
|
r2a(withUIRouter(withCurrentUser(SecretsDatatable)), [
|
||||||
|
|||||||
@@ -3,12 +3,8 @@ import angular from 'angular';
|
|||||||
import { r2a } from '@/react-tools/react2angular';
|
import { r2a } from '@/react-tools/react2angular';
|
||||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||||
import { AssociatedEdgeEnvironmentsSelector } from '@/react/edge/components/AssociatedEdgeEnvironmentsSelector';
|
|
||||||
import { EdgeAsyncIntervalsForm } from '@/react/edge/components/EdgeAsyncIntervalsForm';
|
|
||||||
import { EdgeCheckinIntervalField } from '@/react/edge/components/EdgeCheckInIntervalField';
|
|
||||||
import { EdgeScriptForm } from '@/react/edge/components/EdgeScriptForm';
|
import { EdgeScriptForm } from '@/react/edge/components/EdgeScriptForm';
|
||||||
import { EdgeGroupsSelector } from '@/react/edge/edge-stacks/components/EdgeGroupsSelector';
|
import { EdgeGroupsSelector } from '@/react/edge/edge-stacks/components/EdgeGroupsSelector';
|
||||||
import { AssociatedEdgeGroupEnvironmentsSelector } from '@/react/edge/components/AssociatedEdgeGroupEnvironmentsSelector';
|
|
||||||
|
|
||||||
const ngModule = angular
|
const ngModule = angular
|
||||||
.module('portainer.edge.react.components', [])
|
.module('portainer.edge.react.components', [])
|
||||||
@@ -32,45 +28,6 @@ const ngModule = angular
|
|||||||
'asyncMode',
|
'asyncMode',
|
||||||
'showMetaFields',
|
'showMetaFields',
|
||||||
])
|
])
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'edgeCheckinIntervalField',
|
|
||||||
r2a(withReactQuery(EdgeCheckinIntervalField), [
|
|
||||||
'value',
|
|
||||||
'onChange',
|
|
||||||
'isDefaultHidden',
|
|
||||||
'tooltip',
|
|
||||||
'label',
|
|
||||||
'readonly',
|
|
||||||
'size',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'edgeAsyncIntervalsForm',
|
|
||||||
r2a(withReactQuery(EdgeAsyncIntervalsForm), [
|
|
||||||
'values',
|
|
||||||
'onChange',
|
|
||||||
'isDefaultHidden',
|
|
||||||
'readonly',
|
|
||||||
'fieldSettings',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'associatedEdgeEnvironmentsSelector',
|
|
||||||
r2a(withReactQuery(AssociatedEdgeEnvironmentsSelector), [
|
|
||||||
'onChange',
|
|
||||||
'value',
|
|
||||||
'error',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'associatedEdgeGroupEnvironmentsSelector',
|
|
||||||
r2a(withReactQuery(AssociatedEdgeGroupEnvironmentsSelector), [
|
|
||||||
'onChange',
|
|
||||||
'value',
|
|
||||||
'error',
|
|
||||||
'edgeGroupId',
|
|
||||||
])
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export const componentsModule = ngModule.name;
|
export const componentsModule = ngModule.name;
|
||||||
|
|||||||
@@ -3,16 +3,11 @@ import angular from 'angular';
|
|||||||
import { r2a } from '@/react-tools/react2angular';
|
import { r2a } from '@/react-tools/react2angular';
|
||||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||||
import { NodeApplicationsDatatable } from '@/react/kubernetes/cluster/NodeView/NodeApplicationsDatatable/NodeApplicationsDatatable';
|
|
||||||
import { ResourceEventsDatatable } from '@/react/kubernetes/components/EventsDatatable/ResourceEventsDatatable';
|
import { ResourceEventsDatatable } from '@/react/kubernetes/components/EventsDatatable/ResourceEventsDatatable';
|
||||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||||
|
|
||||||
export const clusterManagementModule = angular
|
export const clusterManagementModule = angular
|
||||||
.module('portainer.kubernetes.react.components.clusterManagement', [])
|
.module('portainer.kubernetes.react.components.clusterManagement', [])
|
||||||
.component(
|
|
||||||
'kubernetesNodeApplicationsDatatable',
|
|
||||||
r2a(withUIRouter(withCurrentUser(NodeApplicationsDatatable)), [])
|
|
||||||
)
|
|
||||||
.component(
|
.component(
|
||||||
'resourceEventsDatatable',
|
'resourceEventsDatatable',
|
||||||
r2a(
|
r2a(
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
import angular from 'angular';
|
import angular from 'angular';
|
||||||
|
|
||||||
import { r2a } from '@/react-tools/react2angular';
|
import { r2a } from '@/react-tools/react2angular';
|
||||||
import { IngressClassDatatableAngular } from '@/react/kubernetes/cluster/ingressClass/IngressClassDatatable/IngressClassDatatableAngular';
|
|
||||||
import { NamespacesSelector } from '@/react/kubernetes/cluster/RegistryAccessView/NamespacesSelector';
|
import { NamespacesSelector } from '@/react/kubernetes/cluster/RegistryAccessView/NamespacesSelector';
|
||||||
import { NamespaceAccessUsersSelector } from '@/react/kubernetes/namespaces/AccessView/NamespaceAccessUsersSelector';
|
|
||||||
import { KubeServicesForm } from '@/react/kubernetes/applications/CreateView/application-services/KubeServicesForm';
|
import { KubeServicesForm } from '@/react/kubernetes/applications/CreateView/application-services/KubeServicesForm';
|
||||||
import { kubeServicesValidation } from '@/react/kubernetes/applications/CreateView/application-services/kubeServicesValidation';
|
import { kubeServicesValidation } from '@/react/kubernetes/applications/CreateView/application-services/kubeServicesValidation';
|
||||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||||
import {
|
|
||||||
ApplicationSummaryWidget,
|
|
||||||
ApplicationDetailsWidget,
|
|
||||||
ApplicationEventsDatatable,
|
|
||||||
} from '@/react/kubernetes/applications/DetailsView';
|
|
||||||
import { ApplicationContainersDatatable } from '@/react/kubernetes/applications/DetailsView/ApplicationContainersDatatable';
|
|
||||||
import {
|
import {
|
||||||
PlacementFormSection,
|
PlacementFormSection,
|
||||||
placementValidation,
|
placementValidation,
|
||||||
@@ -22,7 +14,6 @@ import { ApplicationSummarySection } from '@/react/kubernetes/applications/compo
|
|||||||
import { withFormValidation } from '@/react-tools/withFormValidation';
|
import { withFormValidation } from '@/react-tools/withFormValidation';
|
||||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||||
import { YAMLInspector } from '@/react/kubernetes/components/YAMLInspector';
|
import { YAMLInspector } from '@/react/kubernetes/components/YAMLInspector';
|
||||||
import { NodesDatatable } from '@/react/kubernetes/cluster/HomeView/NodesDatatable';
|
|
||||||
import { StackName } from '@/react/kubernetes/DeployView/StackName/StackName';
|
import { StackName } from '@/react/kubernetes/DeployView/StackName/StackName';
|
||||||
import { StackNameLabelInsight } from '@/react/kubernetes/DeployView/StackName/StackNameLabelInsight';
|
import { StackNameLabelInsight } from '@/react/kubernetes/DeployView/StackName/StackNameLabelInsight';
|
||||||
import { SecretsFormSection } from '@/react/kubernetes/applications/components/ConfigurationsFormSection/SecretsFormSection';
|
import { SecretsFormSection } from '@/react/kubernetes/applications/components/ConfigurationsFormSection/SecretsFormSection';
|
||||||
@@ -59,33 +50,17 @@ import { EnvironmentVariablesFormSection } from '@/react/kubernetes/applications
|
|||||||
import { kubeEnvVarValidationSchema } from '@/react/kubernetes/applications/components/EnvironmentVariablesFormSection/kubeEnvVarValidationSchema';
|
import { kubeEnvVarValidationSchema } from '@/react/kubernetes/applications/components/EnvironmentVariablesFormSection/kubeEnvVarValidationSchema';
|
||||||
import { IntegratedAppsDatatable } from '@/react/kubernetes/components/IntegratedAppsDatatable/IntegratedAppsDatatable';
|
import { IntegratedAppsDatatable } from '@/react/kubernetes/components/IntegratedAppsDatatable/IntegratedAppsDatatable';
|
||||||
import { K8sRegistryAccessNotice } from '@/react/kubernetes/components/K8sRegistryAccessNotice';
|
import { K8sRegistryAccessNotice } from '@/react/kubernetes/components/K8sRegistryAccessNotice';
|
||||||
import { HelmTemplates } from '@/react/kubernetes/helm/HelmTemplates/HelmTemplates';
|
|
||||||
import { SecretDetailsTable } from '@/react/kubernetes/configs/secrets/ItemView/SecretDetailsTable';
|
|
||||||
import { KubernetesSummaryView } from '@/react/kubernetes/summary/KubernetesSummaryView';
|
import { KubernetesSummaryView } from '@/react/kubernetes/summary/KubernetesSummaryView';
|
||||||
import { SecretItemTabsWidget } from '@/react/kubernetes/configs/secrets/ItemView/SecretItemTabsWidget';
|
import { SecretItemTabsWidget } from '@/react/kubernetes/configs/secrets/ItemView/SecretItemTabsWidget';
|
||||||
|
|
||||||
import { namespacesModule } from './namespaces';
|
|
||||||
import { clusterManagementModule } from './clusterManagement';
|
import { clusterManagementModule } from './clusterManagement';
|
||||||
import { registriesModule } from './registries';
|
import { registriesModule } from './registries';
|
||||||
|
|
||||||
export const ngModule = angular
|
export const ngModule = angular
|
||||||
.module('portainer.kubernetes.react.components', [
|
.module('portainer.kubernetes.react.components', [
|
||||||
namespacesModule,
|
|
||||||
clusterManagementModule,
|
clusterManagementModule,
|
||||||
registriesModule,
|
registriesModule,
|
||||||
])
|
])
|
||||||
.component(
|
|
||||||
'ingressClassDatatable',
|
|
||||||
r2a(IngressClassDatatableAngular, [
|
|
||||||
'onChangeControllers',
|
|
||||||
'description',
|
|
||||||
'ingressControllers',
|
|
||||||
'initialIngressControllers',
|
|
||||||
'allowNoneIngressClass',
|
|
||||||
'isLoading',
|
|
||||||
'view',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
.component(
|
||||||
'namespacesSelector',
|
'namespacesSelector',
|
||||||
r2a(NamespacesSelector, [
|
r2a(NamespacesSelector, [
|
||||||
@@ -99,22 +74,6 @@ export const ngModule = angular
|
|||||||
'allowSelectAll',
|
'allowSelectAll',
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
.component(
|
|
||||||
'namespaceAccessUsersSelector',
|
|
||||||
r2a(NamespaceAccessUsersSelector, [
|
|
||||||
'inputId',
|
|
||||||
'onChange',
|
|
||||||
'options',
|
|
||||||
'value',
|
|
||||||
'dataCy',
|
|
||||||
'placeholder',
|
|
||||||
'name',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'kubeNodesDatatable',
|
|
||||||
r2a(withUIRouter(withReactQuery(withCurrentUser(NodesDatatable))), [])
|
|
||||||
)
|
|
||||||
.component(
|
.component(
|
||||||
'accessPolicyFormSection',
|
'accessPolicyFormSection',
|
||||||
r2a(DataAccessPolicyFormSection, [
|
r2a(DataAccessPolicyFormSection, [
|
||||||
@@ -166,36 +125,6 @@ export const ngModule = angular
|
|||||||
'isComposeFormat',
|
'isComposeFormat',
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
.component(
|
|
||||||
'applicationSummaryWidget',
|
|
||||||
r2a(
|
|
||||||
withUIRouter(withReactQuery(withCurrentUser(ApplicationSummaryWidget))),
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'applicationContainersDatatable',
|
|
||||||
r2a(
|
|
||||||
withUIRouter(
|
|
||||||
withReactQuery(withCurrentUser(ApplicationContainersDatatable))
|
|
||||||
),
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'applicationDetailsWidget',
|
|
||||||
r2a(
|
|
||||||
withUIRouter(withReactQuery(withCurrentUser(ApplicationDetailsWidget))),
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'applicationEventsDatatable',
|
|
||||||
r2a(
|
|
||||||
withUIRouter(withReactQuery(withCurrentUser(ApplicationEventsDatatable))),
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.component(
|
.component(
|
||||||
'applicationSummarySection',
|
'applicationSummarySection',
|
||||||
r2a(
|
r2a(
|
||||||
@@ -214,24 +143,6 @@ export const ngModule = angular
|
|||||||
'dataCy',
|
'dataCy',
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
.component(
|
|
||||||
'helmTemplatesView',
|
|
||||||
r2a(withUIRouter(withCurrentUser(HelmTemplates)), [
|
|
||||||
'onSelectHelmChart',
|
|
||||||
'namespace',
|
|
||||||
'name',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'secretDetailsTable',
|
|
||||||
r2a(withUIRouter(withCurrentUser(withReactQuery(SecretDetailsTable))), [
|
|
||||||
'name',
|
|
||||||
'namespace',
|
|
||||||
'secretTypeLabel',
|
|
||||||
'isSystem',
|
|
||||||
'registryId',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
.component(
|
||||||
'secretItemTabsWidget',
|
'secretItemTabsWidget',
|
||||||
r2a(withUIRouter(withReactQuery(withCurrentUser(SecretItemTabsWidget))), [
|
r2a(withUIRouter(withReactQuery(withCurrentUser(SecretItemTabsWidget))), [
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import angular from 'angular';
|
|
||||||
|
|
||||||
import { r2a } from '@/react-tools/react2angular';
|
|
||||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
|
||||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
|
||||||
import { NamespacesDatatable } from '@/react/kubernetes/namespaces/ListView/NamespacesDatatable';
|
|
||||||
|
|
||||||
export const namespacesModule = angular
|
|
||||||
.module('portainer.kubernetes.react.components.namespaces', [])
|
|
||||||
.component(
|
|
||||||
'kubernetesNamespacesDatatable',
|
|
||||||
r2a(withUIRouter(withCurrentUser(NamespacesDatatable)), [])
|
|
||||||
).name;
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
<form class="form-horizontal" name="endpointGroupForm" ng-if="$ctrl.model">
|
|
||||||
<!-- name-input -->
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="group_name" class="col-sm-3 col-lg-2 control-label required text-left">Name</label>
|
|
||||||
<div class="col-sm-9 col-lg-10">
|
|
||||||
<input type="text" class="form-control" name="group_name" ng-model="$ctrl.model.Name" placeholder="e.g. my-group" required auto-focus data-cy="group-name-input" />
|
|
||||||
<div class="help-block" ng-show="endpointGroupForm.group_name.$invalid">
|
|
||||||
<div class="small text-warning">
|
|
||||||
<div ng-messages="endpointGroupForm.group_name.$error">
|
|
||||||
<p ng-message="required" class="vertical-center">
|
|
||||||
<pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon>
|
|
||||||
This field is required.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- !name-input -->
|
|
||||||
<!-- description-input -->
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="group_description" class="col-sm-3 col-lg-2 control-label text-left">Description</label>
|
|
||||||
<div class="col-sm-9 col-lg-10">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="form-control"
|
|
||||||
id="group_description"
|
|
||||||
ng-model="$ctrl.model.Description"
|
|
||||||
placeholder="e.g. production environments..."
|
|
||||||
data-cy="group-description-input"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- !description-input -->
|
|
||||||
<div class="col-sm-12 form-section-title"> Metadata </div>
|
|
||||||
|
|
||||||
<tag-selector ng-if="$ctrl.model.TagIds" value="$ctrl.model.TagIds" on-change="($ctrl.onChangeTags)" allow-create="$ctrl.state.allowCreateTag"> </tag-selector>
|
|
||||||
|
|
||||||
<div class="form-group" ng-if="$ctrl.model.Id !== 1">
|
|
||||||
<associated-endpoints-selector value="$ctrl.associatedEndpoints" on-change="($ctrl.onChangeEnvironments)"></associated-endpoints-selector>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="-mx-[15px]">
|
|
||||||
<group-association-table
|
|
||||||
ng-if="$ctrl.model.Id === 1"
|
|
||||||
title="'Unassociated environments'"
|
|
||||||
empty-content-message="'No environment available'"
|
|
||||||
query="$ctrl.unassociatedQuery"
|
|
||||||
></group-association-table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- actions -->
|
|
||||||
<div class="col-sm-12 form-section-title"> Actions </div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-primary btn-sm"
|
|
||||||
ng-click="$ctrl.formAction()"
|
|
||||||
ng-disabled="$ctrl.actionInProgress || !endpointGroupForm.$valid"
|
|
||||||
button-spinner="$ctrl.actionInProgress"
|
|
||||||
>
|
|
||||||
<span ng-hide="$ctrl.actionInProgress">{{ $ctrl.formActionLabel }}</span>
|
|
||||||
<span ng-show="$ctrl.actionInProgress">In progress...</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- !actions -->
|
|
||||||
</form>
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import angular from 'angular';
|
|
||||||
|
|
||||||
class GroupFormController {
|
|
||||||
/* @ngInject */
|
|
||||||
constructor($async, $scope, GroupService, Notifications, Authentication) {
|
|
||||||
this.$async = $async;
|
|
||||||
this.$scope = $scope;
|
|
||||||
this.GroupService = GroupService;
|
|
||||||
this.Notifications = Notifications;
|
|
||||||
this.Authentication = Authentication;
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
allowCreateTag: this.Authentication.isAdmin(),
|
|
||||||
};
|
|
||||||
|
|
||||||
this.unassociatedQuery = {
|
|
||||||
groupIds: [1],
|
|
||||||
};
|
|
||||||
|
|
||||||
this.onChangeTags = this.onChangeTags.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
onChangeTags(value) {
|
|
||||||
return this.$scope.$evalAsync(() => {
|
|
||||||
this.model.TagIds = value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
angular.module('portainer.app').controller('GroupFormController', GroupFormController);
|
|
||||||
export default GroupFormController;
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import angular from 'angular';
|
import angular from 'angular';
|
||||||
|
|
||||||
import { r2a } from '@/react-tools/react2angular';
|
import { r2a } from '@/react-tools/react2angular';
|
||||||
import { CustomTemplatesVariablesDefinitionField } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesDefinitionField';
|
|
||||||
import { CustomTemplatesVariablesField } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesField';
|
import { CustomTemplatesVariablesField } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesField';
|
||||||
import { withControlledInput } from '@/react-tools/withControlledInput';
|
import { withControlledInput } from '@/react-tools/withControlledInput';
|
||||||
|
|
||||||
@@ -18,15 +17,6 @@ export const ngModule = angular
|
|||||||
'errors',
|
'errors',
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
.component('customTemplatesVariablesField', VariablesFieldAngular)
|
.component('customTemplatesVariablesField', VariablesFieldAngular);
|
||||||
.component(
|
|
||||||
'customTemplatesVariablesDefinitionField',
|
|
||||||
r2a(withControlledInput(CustomTemplatesVariablesDefinitionField), [
|
|
||||||
'onChange',
|
|
||||||
'value',
|
|
||||||
'errors',
|
|
||||||
'isVariablesNamesFromParent',
|
|
||||||
])
|
|
||||||
);
|
|
||||||
|
|
||||||
export const customTemplatesModule = ngModule.name;
|
export const customTemplatesModule = ngModule.name;
|
||||||
|
|||||||
@@ -11,32 +11,21 @@ import { withControlledInput } from '@/react-tools/withControlledInput';
|
|||||||
import {
|
import {
|
||||||
EnvironmentVariablesFieldset,
|
EnvironmentVariablesFieldset,
|
||||||
EnvironmentVariablesPanel,
|
EnvironmentVariablesPanel,
|
||||||
StackEnvironmentVariablesPanel,
|
|
||||||
envVarValidation,
|
envVarValidation,
|
||||||
} from '@@/form-components/EnvironmentVariablesFieldset';
|
} from '@@/form-components/EnvironmentVariablesFieldset';
|
||||||
import { Icon } from '@@/Icon';
|
import { Icon } from '@@/Icon';
|
||||||
import { ReactQueryDevtoolsWrapper } from '@@/ReactQueryDevtoolsWrapper';
|
import { ReactQueryDevtoolsWrapper } from '@@/ReactQueryDevtoolsWrapper';
|
||||||
import { PageHeader } from '@@/PageHeader';
|
import { PageHeader } from '@@/PageHeader';
|
||||||
import { TagSelector } from '@@/TagSelector';
|
|
||||||
import { Loading } from '@@/Widget/Loading';
|
import { Loading } from '@@/Widget/Loading';
|
||||||
import { PasswordCheckHint } from '@@/PasswordCheckHint';
|
import { PasswordCheckHint } from '@@/PasswordCheckHint';
|
||||||
import { Tooltip } from '@@/Tip/Tooltip';
|
import { Tooltip } from '@@/Tip/Tooltip';
|
||||||
import { TableColumnHeaderAngular } from '@@/datatables/TableHeaderCell';
|
import { TableColumnHeaderAngular } from '@@/datatables/TableHeaderCell';
|
||||||
import { DashboardItem } from '@@/DashboardItem';
|
|
||||||
import { SearchBar } from '@@/datatables/SearchBar';
|
|
||||||
import { FallbackImage } from '@@/FallbackImage';
|
|
||||||
import { BadgeIcon } from '@@/BadgeIcon';
|
|
||||||
import { TeamsSelector } from '@@/TeamsSelector';
|
|
||||||
import { TerminalTooltip } from '@@/TerminalTooltip';
|
import { TerminalTooltip } from '@@/TerminalTooltip';
|
||||||
import { Terminal } from '@@/Terminal/Terminal';
|
import { Terminal } from '@@/Terminal/Terminal';
|
||||||
import { PortainerSelect } from '@@/form-components/PortainerSelect';
|
import { PortainerSelect } from '@@/form-components/PortainerSelect';
|
||||||
import { Slider } from '@@/form-components/Slider';
|
|
||||||
import { TagButton } from '@@/TagButton';
|
|
||||||
import { BETeaserButton } from '@@/BETeaserButton';
|
import { BETeaserButton } from '@@/BETeaserButton';
|
||||||
import { CodeEditor } from '@@/CodeEditor';
|
import { CodeEditor } from '@@/CodeEditor';
|
||||||
import { HelpLink } from '@@/HelpLink';
|
|
||||||
import { TextTip } from '@@/Tip/TextTip';
|
import { TextTip } from '@@/Tip/TextTip';
|
||||||
import { InlineLoader } from '@@/InlineLoader/InlineLoader';
|
|
||||||
|
|
||||||
import { fileUploadField } from './file-upload-field';
|
import { fileUploadField } from './file-upload-field';
|
||||||
import { switchField } from './switch-field';
|
import { switchField } from './switch-field';
|
||||||
@@ -68,15 +57,6 @@ export const ngModule = angular
|
|||||||
rbacModule,
|
rbacModule,
|
||||||
stacksModule,
|
stacksModule,
|
||||||
])
|
])
|
||||||
.component(
|
|
||||||
'tagSelector',
|
|
||||||
r2a(withUIRouter(withReactQuery(TagSelector)), [
|
|
||||||
'allowCreate',
|
|
||||||
'onChange',
|
|
||||||
'value',
|
|
||||||
'errors',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
.component(
|
||||||
'beTeaserButton',
|
'beTeaserButton',
|
||||||
r2a(BETeaserButton, [
|
r2a(BETeaserButton, [
|
||||||
@@ -89,11 +69,6 @@ export const ngModule = angular
|
|||||||
'data-cy',
|
'data-cy',
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
.component(
|
|
||||||
'tagButton',
|
|
||||||
r2a(TagButton, ['value', 'label', 'title', 'onRemove'])
|
|
||||||
)
|
|
||||||
|
|
||||||
.component(
|
.component(
|
||||||
'portainerTooltip',
|
'portainerTooltip',
|
||||||
r2a(Tooltip, ['message', 'position', 'className', 'setHtmlMessage', 'size'])
|
r2a(Tooltip, ['message', 'position', 'className', 'setHtmlMessage', 'size'])
|
||||||
@@ -130,64 +105,11 @@ export const ngModule = angular
|
|||||||
'showTitle',
|
'showTitle',
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
.component(
|
|
||||||
'fallbackImage',
|
|
||||||
r2a(FallbackImage, ['src', 'fallbackIcon', 'alt', 'className'])
|
|
||||||
)
|
|
||||||
.component('prIcon', r2a(Icon, ['className', 'icon', 'mode', 'size', 'spin']))
|
.component('prIcon', r2a(Icon, ['className', 'icon', 'mode', 'size', 'spin']))
|
||||||
.component(
|
.component(
|
||||||
'reactQueryDevTools',
|
'reactQueryDevTools',
|
||||||
r2a(withReactQuery(ReactQueryDevtoolsWrapper), [])
|
r2a(withReactQuery(ReactQueryDevtoolsWrapper), [])
|
||||||
)
|
)
|
||||||
.component(
|
|
||||||
'helpLink',
|
|
||||||
r2a(withUIRouter(withReactQuery(HelpLink)), [
|
|
||||||
'docLink',
|
|
||||||
'target',
|
|
||||||
'children',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'dashboardItem',
|
|
||||||
r2a(DashboardItem, [
|
|
||||||
'icon',
|
|
||||||
'type',
|
|
||||||
'value',
|
|
||||||
'to',
|
|
||||||
'params',
|
|
||||||
'children',
|
|
||||||
'pluralType',
|
|
||||||
'isLoading',
|
|
||||||
'isRefetching',
|
|
||||||
'data-cy',
|
|
||||||
'iconClass',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'datatableSearchbar',
|
|
||||||
r2a(SearchBar, [
|
|
||||||
'data-cy',
|
|
||||||
'onChange',
|
|
||||||
'value',
|
|
||||||
'placeholder',
|
|
||||||
'children',
|
|
||||||
'className',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component('badgeIcon', r2a(BadgeIcon, ['icon', 'size', 'iconClass']))
|
|
||||||
.component(
|
|
||||||
'teamsSelector',
|
|
||||||
r2a(TeamsSelector, [
|
|
||||||
'onChange',
|
|
||||||
'value',
|
|
||||||
'dataCy',
|
|
||||||
'inputId',
|
|
||||||
'name',
|
|
||||||
'placeholder',
|
|
||||||
'teams',
|
|
||||||
'disabled',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
.component(
|
||||||
'porSelect',
|
'porSelect',
|
||||||
r2a(PortainerSelect, [
|
r2a(PortainerSelect, [
|
||||||
@@ -213,19 +135,6 @@ export const ngModule = angular
|
|||||||
'onBlur',
|
'onBlur',
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
.component(
|
|
||||||
'porSlider',
|
|
||||||
r2a(Slider, [
|
|
||||||
'min',
|
|
||||||
'max',
|
|
||||||
'step',
|
|
||||||
'value',
|
|
||||||
'onChange',
|
|
||||||
'visibleTooltip',
|
|
||||||
'dataCy',
|
|
||||||
'disabled',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
.component(
|
||||||
'reactCodeEditor',
|
'reactCodeEditor',
|
||||||
r2a(CodeEditor, [
|
r2a(CodeEditor, [
|
||||||
@@ -257,10 +166,6 @@ export const ngModule = angular
|
|||||||
'childrenWrapperClassName',
|
'childrenWrapperClassName',
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
.component(
|
|
||||||
'inlineLoader',
|
|
||||||
r2a(InlineLoader, ['children', 'className', 'size'])
|
|
||||||
)
|
|
||||||
.component('annotationsBeTeaser', r2a(AnnotationsBeTeaser, []))
|
.component('annotationsBeTeaser', r2a(AnnotationsBeTeaser, []))
|
||||||
.component(
|
.component(
|
||||||
'shellTerminal',
|
'shellTerminal',
|
||||||
@@ -290,17 +195,3 @@ withFormValidation(
|
|||||||
['explanation', 'showHelpMessage', 'isFoldable'],
|
['explanation', 'showHelpMessage', 'isFoldable'],
|
||||||
envVarValidation
|
envVarValidation
|
||||||
);
|
);
|
||||||
|
|
||||||
withFormValidation(
|
|
||||||
ngModule,
|
|
||||||
withUIRouter(
|
|
||||||
withReactQuery(
|
|
||||||
withControlledInput(StackEnvironmentVariablesPanel, {
|
|
||||||
values: 'onChange',
|
|
||||||
})
|
|
||||||
)
|
|
||||||
),
|
|
||||||
'stackEnvironmentVariablesPanel',
|
|
||||||
['showHelpMessage', 'isFoldable'],
|
|
||||||
envVarValidation
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -2,27 +2,11 @@ import angular from 'angular';
|
|||||||
|
|
||||||
import { r2a } from '@/react-tools/react2angular';
|
import { r2a } from '@/react-tools/react2angular';
|
||||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
|
||||||
import { RepositoriesDatatable } from '@/react/portainer/registries/repositories/ListView/RepositoriesDatatable';
|
|
||||||
import { TagsDatatable } from '@/react/portainer/registries/repositories/ItemView/TagsDatatable/TagsDatatable';
|
|
||||||
import { GitlabProjectTable } from '@/react/portainer/registries/CreateView/GitlabProjectsTable/GitlabProjectsTable';
|
import { GitlabProjectTable } from '@/react/portainer/registries/CreateView/GitlabProjectsTable/GitlabProjectsTable';
|
||||||
import { RegistryFormDockerhub } from '@/react/portainer/registries/CreateView/RegistryFormDockerhub/RegistryFormDockerhub';
|
import { RegistryFormDockerhub } from '@/react/portainer/registries/CreateView/RegistryFormDockerhub/RegistryFormDockerhub';
|
||||||
|
|
||||||
export const registriesModule = angular
|
export const registriesModule = angular
|
||||||
.module('portainer.app.react.components.registries', [])
|
.module('portainer.app.react.components.registries', [])
|
||||||
.component(
|
|
||||||
'registryRepositoriesDatatable',
|
|
||||||
r2a(withUIRouter(withReactQuery(RepositoriesDatatable)), ['dataset'])
|
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'registriesRepositoryTagsDatatable',
|
|
||||||
r2a(withUIRouter(withReactQuery(TagsDatatable)), [
|
|
||||||
'dataset',
|
|
||||||
'advancedFeaturesAvailable',
|
|
||||||
'onRemove',
|
|
||||||
'onRetag',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
.component(
|
||||||
'gitlabProjectSelector',
|
'gitlabProjectSelector',
|
||||||
r2a(GitlabProjectTable, ['dataset', 'onChange', 'value'])
|
r2a(GitlabProjectTable, ['dataset', 'onChange', 'value'])
|
||||||
|
|||||||
@@ -4,14 +4,8 @@ import { InternalAuth } from '@/react/portainer/settings/AuthenticationView/Inte
|
|||||||
import { AuthenticationMethodSelector } from '@/react/portainer/settings/AuthenticationView/AuthenticationMethodSelector';
|
import { AuthenticationMethodSelector } from '@/react/portainer/settings/AuthenticationView/AuthenticationMethodSelector';
|
||||||
import { r2a } from '@/react-tools/react2angular';
|
import { r2a } from '@/react-tools/react2angular';
|
||||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
|
||||||
import { LDAPUsersTable } from '@/react/portainer/settings/AuthenticationView/LDAPAuth/LDAPUsersTable';
|
import { LDAPUsersTable } from '@/react/portainer/settings/AuthenticationView/LDAPAuth/LDAPUsersTable';
|
||||||
import { LDAPGroupsTable } from '@/react/portainer/settings/AuthenticationView/LDAPAuth/LDAPGroupsTable';
|
import { LDAPGroupsTable } from '@/react/portainer/settings/AuthenticationView/LDAPAuth/LDAPGroupsTable';
|
||||||
import { ApplicationSettingsPanel } from '@/react/portainer/settings/SettingsView/ApplicationSettingsPanel';
|
|
||||||
import { KubeSettingsPanel } from '@/react/portainer/settings/SettingsView/KubeSettingsPanel';
|
|
||||||
import { HelmCertPanel } from '@/react/portainer/settings/SettingsView/HelmCertPanel';
|
|
||||||
import { HiddenContainersPanel } from '@/react/portainer/settings/SettingsView/HiddenContainersPanel/HiddenContainersPanel';
|
|
||||||
import { SSLSettingsPanelWrapper } from '@/react/portainer/settings/SettingsView/SSLSettingsPanel/SSLSettingsPanel';
|
|
||||||
import { AuthStyleField } from '@/react/portainer/settings/AuthenticationView/OAuth';
|
import { AuthStyleField } from '@/react/portainer/settings/AuthenticationView/OAuth';
|
||||||
import { AutoUserProvisionToggle } from '@/react/portainer/settings/AuthenticationView/AutoUserProvisionToggle/AutoUserProvisionToggle';
|
import { AutoUserProvisionToggle } from '@/react/portainer/settings/AuthenticationView/AutoUserProvisionToggle/AutoUserProvisionToggle';
|
||||||
import { LdapSettingsTestLogin } from '@/react/portainer/settings/AuthenticationView/LDAPAuth/LdapSettingsTestLogin/LdapSettingsTestLogin';
|
import { LdapSettingsTestLogin } from '@/react/portainer/settings/AuthenticationView/LDAPAuth/LdapSettingsTestLogin/LdapSettingsTestLogin';
|
||||||
@@ -53,23 +47,6 @@ export const settingsModule = angular
|
|||||||
'limitedFeatureId',
|
'limitedFeatureId',
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
.component(
|
|
||||||
'applicationSettingsPanel',
|
|
||||||
r2a(withReactQuery(ApplicationSettingsPanel), ['onSuccess', 'settings'])
|
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'sslSettingsPanel',
|
|
||||||
r2a(withReactQuery(SSLSettingsPanelWrapper), [])
|
|
||||||
)
|
|
||||||
.component('helmCertPanel', r2a(withReactQuery(HelmCertPanel), []))
|
|
||||||
.component(
|
|
||||||
'hiddenContainersPanel',
|
|
||||||
r2a(withUIRouter(withReactQuery(HiddenContainersPanel)), [])
|
|
||||||
)
|
|
||||||
.component(
|
|
||||||
'kubeSettingsPanel',
|
|
||||||
r2a(withUIRouter(withReactQuery(KubeSettingsPanel)), ['settings'])
|
|
||||||
)
|
|
||||||
.component(
|
.component(
|
||||||
'oauthAuthStyle',
|
'oauthAuthStyle',
|
||||||
r2a(AuthStyleField, [
|
r2a(AuthStyleField, [
|
||||||
|
|||||||
@@ -4,18 +4,11 @@ import { r2a } from '@/react-tools/react2angular';
|
|||||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||||
import { EffectiveAccessViewerDatatable } from '@/react/portainer/users/RolesView/AccessViewer/EffectiveAccessViewerDatatable';
|
|
||||||
import { EffectiveAccessViewer } from '@/react/portainer/users/RolesView/AccessViewer/EffectiveAccessViewer';
|
import { EffectiveAccessViewer } from '@/react/portainer/users/RolesView/AccessViewer/EffectiveAccessViewer';
|
||||||
import { RbacRolesDatatable } from '@/react/portainer/users/RolesView/RbacRolesDatatable';
|
import { RbacRolesDatatable } from '@/react/portainer/users/RolesView/RbacRolesDatatable';
|
||||||
|
|
||||||
export const usersModule = angular
|
export const usersModule = angular
|
||||||
.module('portainer.app.react.components.users', [])
|
.module('portainer.app.react.components.users', [])
|
||||||
.component(
|
|
||||||
'effectiveAccessViewerDatatable',
|
|
||||||
r2a(withUIRouter(withCurrentUser(EffectiveAccessViewerDatatable)), [
|
|
||||||
'dataset',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
.component(
|
||||||
'effectiveAccessViewer',
|
'effectiveAccessViewer',
|
||||||
r2a(withUIRouter(withReactQuery(withCurrentUser(EffectiveAccessViewer))), [
|
r2a(withUIRouter(withReactQuery(withCurrentUser(EffectiveAccessViewer))), [
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { withReactQuery } from '@/react-tools/withReactQuery';
|
|||||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||||
import { CreateUserAccessToken } from '@/react/portainer/account/CreateAccessTokenView';
|
import { CreateUserAccessToken } from '@/react/portainer/account/CreateAccessTokenView';
|
||||||
import { EdgeComputeSettingsView } from '@/react/portainer/settings/EdgeComputeView/EdgeComputeSettingsView';
|
import { EdgeComputeSettingsView } from '@/react/portainer/settings/EdgeComputeView/EdgeComputeSettingsView';
|
||||||
import { BackupSettingsPanel } from '@/react/portainer/settings/SettingsView/BackupSettingsView/BackupSettingsPanel';
|
|
||||||
import { SettingsView } from '@/react/portainer/settings/SettingsView/SettingsView';
|
import { SettingsView } from '@/react/portainer/settings/SettingsView/SettingsView';
|
||||||
import { CreateHelmRepositoriesView } from '@/react/portainer/account/helm-repositories/CreateHelmRepositoryView';
|
import { CreateHelmRepositoriesView } from '@/react/portainer/account/helm-repositories/CreateHelmRepositoryView';
|
||||||
|
|
||||||
@@ -53,11 +52,6 @@ export const viewsModule = angular
|
|||||||
['onSubmit', 'settings']
|
['onSubmit', 'settings']
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
.component(
|
|
||||||
'backupSettingsPanel',
|
|
||||||
r2a(withUIRouter(withReactQuery(withCurrentUser(BackupSettingsPanel))), [])
|
|
||||||
)
|
|
||||||
.component(
|
.component(
|
||||||
'settingsView',
|
'settingsView',
|
||||||
r2a(withUIRouter(withReactQuery(withCurrentUser(SettingsView))), [])
|
r2a(withUIRouter(withReactQuery(withCurrentUser(SettingsView))), [])
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { array, object, string } from 'yup';
|
import { array, object, string } from 'yup';
|
||||||
|
|
||||||
import { r2a } from '@/react-tools/react2angular';
|
|
||||||
import { withControlledInput } from '@/react-tools/withControlledInput';
|
|
||||||
|
|
||||||
import { InputList } from '@@/form-components/InputList';
|
import { InputList } from '@@/form-components/InputList';
|
||||||
import { ItemProps } from '@@/form-components/InputList/InputList';
|
import { ItemProps } from '@@/form-components/InputList/InputList';
|
||||||
import { InputGroup } from '@@/form-components/InputGroup';
|
import { InputGroup } from '@@/form-components/InputGroup';
|
||||||
@@ -69,8 +66,3 @@ export function gpusListValidation() {
|
|||||||
});
|
});
|
||||||
return array().of(gpuShape).default([]);
|
return array().of(gpuShape).default([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GpusListAngular = r2a(withControlledInput(GpusList), [
|
|
||||||
'value',
|
|
||||||
'onChange',
|
|
||||||
]);
|
|
||||||
|
|||||||
@@ -1,106 +0,0 @@
|
|||||||
import { useCurrentStateAndParams } from '@uirouter/react';
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { compact } from 'lodash';
|
|
||||||
|
|
||||||
import { createStore } from '@/react/kubernetes/datatables/default-kube-datatable-store';
|
|
||||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
|
||||||
|
|
||||||
import { useTableState } from '@@/datatables/useTableState';
|
|
||||||
|
|
||||||
import { EventsDatatable } from '../../components/EventsDatatable';
|
|
||||||
import { useEvents } from '../../queries/useEvents';
|
|
||||||
import { AppKind } from '../types';
|
|
||||||
import { useApplication } from '../queries/useApplication';
|
|
||||||
import { useApplicationServices } from '../queries/useApplicationServices';
|
|
||||||
import { useApplicationPods } from '../queries/useApplicationPods';
|
|
||||||
|
|
||||||
const storageKey = 'k8sAppEventsDatatable';
|
|
||||||
const settingsStore = createStore(storageKey, { id: 'Date', desc: true });
|
|
||||||
|
|
||||||
export function ApplicationEventsDatatable() {
|
|
||||||
const tableState = useTableState(settingsStore, storageKey);
|
|
||||||
const {
|
|
||||||
params: {
|
|
||||||
namespace,
|
|
||||||
name,
|
|
||||||
'resource-type': appKind,
|
|
||||||
endpointId: environmentId,
|
|
||||||
},
|
|
||||||
} = useCurrentStateAndParams();
|
|
||||||
|
|
||||||
const { relatedEvents, isInitialLoading } = useApplicationEvents(
|
|
||||||
environmentId,
|
|
||||||
namespace,
|
|
||||||
name,
|
|
||||||
appKind,
|
|
||||||
{
|
|
||||||
autoRefreshRate: tableState.autoRefreshRate,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EventsDatatable
|
|
||||||
dataset={relatedEvents}
|
|
||||||
tableState={tableState}
|
|
||||||
isLoading={isInitialLoading}
|
|
||||||
data-cy="k8sAppDetail-eventsTable"
|
|
||||||
noWidget
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useApplicationEvents(
|
|
||||||
environmentId: EnvironmentId,
|
|
||||||
namespace: string,
|
|
||||||
name: string,
|
|
||||||
appKind?: AppKind,
|
|
||||||
options?: { autoRefreshRate?: number; yaml?: boolean }
|
|
||||||
) {
|
|
||||||
const { data: application, ...applicationQuery } = useApplication(
|
|
||||||
environmentId,
|
|
||||||
namespace,
|
|
||||||
name,
|
|
||||||
appKind
|
|
||||||
);
|
|
||||||
const servicesQuery = useApplicationServices(
|
|
||||||
environmentId,
|
|
||||||
namespace,
|
|
||||||
name,
|
|
||||||
application
|
|
||||||
);
|
|
||||||
const podsQuery = useApplicationPods(
|
|
||||||
environmentId,
|
|
||||||
namespace,
|
|
||||||
name,
|
|
||||||
application
|
|
||||||
);
|
|
||||||
|
|
||||||
// related events are events that have the application id, or the id of a service or pod from the application
|
|
||||||
const relatedUids = useMemo(() => {
|
|
||||||
const serviceIds = compact(
|
|
||||||
servicesQuery.data?.map((service) => service?.metadata?.uid)
|
|
||||||
);
|
|
||||||
const podIds = compact(podsQuery.data?.map((pod) => pod?.metadata?.uid));
|
|
||||||
return [application?.metadata?.uid, ...serviceIds, ...podIds];
|
|
||||||
}, [application?.metadata?.uid, podsQuery.data, servicesQuery.data]);
|
|
||||||
|
|
||||||
const relatedUidsSet = useMemo(() => new Set(relatedUids), [relatedUids]);
|
|
||||||
const { data: events, ...eventsQuery } = useEvents(environmentId, {
|
|
||||||
namespace,
|
|
||||||
queryOptions: {
|
|
||||||
autoRefreshRate: options?.autoRefreshRate
|
|
||||||
? options.autoRefreshRate * 1000
|
|
||||||
: undefined,
|
|
||||||
select: (data) =>
|
|
||||||
data.filter((event) => relatedUidsSet.has(event.involvedObject.uid)),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const isInitialLoading =
|
|
||||||
applicationQuery.isInitialLoading ||
|
|
||||||
servicesQuery.isInitialLoading ||
|
|
||||||
podsQuery.isInitialLoading ||
|
|
||||||
eventsQuery.isInitialLoading;
|
|
||||||
|
|
||||||
return { relatedEvents: events || [], isInitialLoading };
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,2 @@
|
|||||||
export { ApplicationSummaryWidget } from './ApplicationSummaryWidget';
|
export { ApplicationSummaryWidget } from './ApplicationSummaryWidget';
|
||||||
export { ApplicationDetailsWidget } from './ApplicationDetailsWidget/ApplicationDetailsWidget';
|
export { ApplicationDetailsWidget } from './ApplicationDetailsWidget/ApplicationDetailsWidget';
|
||||||
export { ApplicationEventsDatatable } from './ApplicationEventsDatatable';
|
|
||||||
|
|||||||
-269
@@ -1,269 +0,0 @@
|
|||||||
import { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
import Route from '@/assets/ico/route.svg?c';
|
|
||||||
|
|
||||||
import { confirm } from '@@/modals/confirm';
|
|
||||||
import { ModalType } from '@@/modals';
|
|
||||||
import { Datatable } from '@@/datatables';
|
|
||||||
import { Button, ButtonGroup } from '@@/buttons';
|
|
||||||
import { createPersistedStore } from '@@/datatables/types';
|
|
||||||
import { buildConfirmButton } from '@@/modals/utils';
|
|
||||||
import { useTableState } from '@@/datatables/useTableState';
|
|
||||||
import { TextTip } from '@@/Tip/TextTip';
|
|
||||||
|
|
||||||
import { IngressControllerClassMap } from '../types';
|
|
||||||
|
|
||||||
import { columns } from './columns';
|
|
||||||
|
|
||||||
const storageKey = 'ingressClasses';
|
|
||||||
const settingsStore = createPersistedStore(storageKey, 'name');
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
onChangeControllers: (
|
|
||||||
controllerClassMap: IngressControllerClassMap[]
|
|
||||||
) => void; // angular function to save the ingress class list
|
|
||||||
description: string;
|
|
||||||
ingressControllers: IngressControllerClassMap[] | undefined;
|
|
||||||
initialIngressControllers: IngressControllerClassMap[] | undefined;
|
|
||||||
allowNoneIngressClass: boolean;
|
|
||||||
isLoading: boolean;
|
|
||||||
view: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a legacy component that has more state logic than the new one, for angular views
|
|
||||||
// Delete this component when the namespace edit view is migrated to react
|
|
||||||
export function IngressClassDatatableAngular({
|
|
||||||
onChangeControllers,
|
|
||||||
description,
|
|
||||||
initialIngressControllers,
|
|
||||||
ingressControllers,
|
|
||||||
allowNoneIngressClass,
|
|
||||||
isLoading,
|
|
||||||
view,
|
|
||||||
}: Props) {
|
|
||||||
const tableState = useTableState(settingsStore, storageKey);
|
|
||||||
|
|
||||||
const [ingControllerFormValues, setIngControllerFormValues] = useState(
|
|
||||||
ingressControllers || []
|
|
||||||
);
|
|
||||||
|
|
||||||
// set the ingress controller form values when the ingress controller list changes
|
|
||||||
// and the ingress controller form values are not set
|
|
||||||
useEffect(() => {
|
|
||||||
if (
|
|
||||||
ingressControllers &&
|
|
||||||
ingControllerFormValues.length !== ingressControllers.length
|
|
||||||
) {
|
|
||||||
setIngControllerFormValues(ingressControllers);
|
|
||||||
}
|
|
||||||
}, [ingressControllers, ingControllerFormValues]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (allowNoneIngressClass === undefined || isLoading) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let newIngFormValues: IngressControllerClassMap[];
|
|
||||||
const isCustomTypeExist = ingControllerFormValues.some(
|
|
||||||
(ic) => ic.Type === 'custom'
|
|
||||||
);
|
|
||||||
if (allowNoneIngressClass) {
|
|
||||||
newIngFormValues = [...ingControllerFormValues];
|
|
||||||
// add the ingress controller type 'custom' with a 'none' ingress class name
|
|
||||||
if (!isCustomTypeExist) {
|
|
||||||
newIngFormValues.push({
|
|
||||||
Name: 'none',
|
|
||||||
ClassName: 'none',
|
|
||||||
Type: 'custom',
|
|
||||||
Availability: true,
|
|
||||||
New: false,
|
|
||||||
Used: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newIngFormValues = ingControllerFormValues.filter(
|
|
||||||
(ingController) => ingController.ClassName !== 'none'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
setIngControllerFormValues(newIngFormValues);
|
|
||||||
onChangeControllers(newIngFormValues);
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [allowNoneIngressClass, onChangeControllers]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="-mx-[15px]">
|
|
||||||
<Datatable
|
|
||||||
settingsManager={tableState}
|
|
||||||
dataset={ingControllerFormValues || []}
|
|
||||||
columns={columns}
|
|
||||||
isLoading={isLoading}
|
|
||||||
title="Ingress Controllers"
|
|
||||||
titleIcon={Route}
|
|
||||||
getRowId={(row) => `${row.Name}-${row.ClassName}-${row.Type}`}
|
|
||||||
renderTableActions={(selectedRows) => renderTableActions(selectedRows)}
|
|
||||||
description={renderIngressClassDescription()}
|
|
||||||
data-cy="k8s-ingress-classes-datatable"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
function renderTableActions(selectedRows: IngressControllerClassMap[]) {
|
|
||||||
return (
|
|
||||||
<div className="flex items-start">
|
|
||||||
<ButtonGroup>
|
|
||||||
<Button
|
|
||||||
disabled={
|
|
||||||
selectedRows.filter((row) => row.Availability === true).length ===
|
|
||||||
0
|
|
||||||
}
|
|
||||||
color="dangerlight"
|
|
||||||
size="small"
|
|
||||||
onClick={() =>
|
|
||||||
updateIngressControllers(
|
|
||||||
selectedRows,
|
|
||||||
ingControllerFormValues || [],
|
|
||||||
false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
data-cy="k8s-disallow-selected-ingress-controllers-button"
|
|
||||||
>
|
|
||||||
Disallow selected
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
disabled={
|
|
||||||
selectedRows.filter((row) => row.Availability === false)
|
|
||||||
.length === 0
|
|
||||||
}
|
|
||||||
color="default"
|
|
||||||
size="small"
|
|
||||||
onClick={() =>
|
|
||||||
updateIngressControllers(
|
|
||||||
selectedRows,
|
|
||||||
ingControllerFormValues || [],
|
|
||||||
true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
data-cy="k8s-allow-selected-ingress-controllers-button"
|
|
||||||
>
|
|
||||||
Allow selected
|
|
||||||
</Button>
|
|
||||||
</ButtonGroup>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderIngressClassDescription() {
|
|
||||||
return (
|
|
||||||
<div className="text-muted flex w-full flex-col !text-xs">
|
|
||||||
<div className="mt-1">{description}</div>
|
|
||||||
{initialIngressControllers &&
|
|
||||||
ingControllerFormValues &&
|
|
||||||
isUnsavedChanges(
|
|
||||||
initialIngressControllers,
|
|
||||||
ingControllerFormValues
|
|
||||||
) && <TextTip>Unsaved changes.</TextTip>}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateIngressControllers(
|
|
||||||
selectedRows: IngressControllerClassMap[],
|
|
||||||
ingControllerFormValues: IngressControllerClassMap[],
|
|
||||||
availability: boolean
|
|
||||||
) {
|
|
||||||
const updatedIngressControllers = getUpdatedIngressControllers(
|
|
||||||
selectedRows,
|
|
||||||
ingControllerFormValues || [],
|
|
||||||
availability
|
|
||||||
);
|
|
||||||
|
|
||||||
if (ingressControllers && ingressControllers.length) {
|
|
||||||
const newAllowed = updatedIngressControllers.map(
|
|
||||||
(ingController) => ingController.Availability
|
|
||||||
);
|
|
||||||
if (view === 'namespace') {
|
|
||||||
setIngControllerFormValues(updatedIngressControllers);
|
|
||||||
onChangeControllers(updatedIngressControllers);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const usedControllersToDisallow = ingressControllers.filter(
|
|
||||||
(ingController, index) => {
|
|
||||||
// if any of the current controllers are allowed, and are used, then become disallowed, then add the controller to a new list
|
|
||||||
if (
|
|
||||||
ingController.Availability &&
|
|
||||||
ingController.Used &&
|
|
||||||
!newAllowed[index]
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (usedControllersToDisallow.length > 0) {
|
|
||||||
const confirmed = await confirm({
|
|
||||||
title: 'Disallow in-use ingress controllers?',
|
|
||||||
modalType: ModalType.Warn,
|
|
||||||
message: (
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
There are ingress controllers you want to disallow that are in
|
|
||||||
use:
|
|
||||||
</p>
|
|
||||||
<ul className="ml-6">
|
|
||||||
{usedControllersToDisallow.map((controller) => (
|
|
||||||
<li key={controller.ClassName}>{controller.ClassName}</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
No new ingress rules can be created for the disallowed
|
|
||||||
controllers.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
confirmButton: buildConfirmButton('Disallow', 'warning'),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!confirmed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setIngControllerFormValues(updatedIngressControllers);
|
|
||||||
onChangeControllers(updatedIngressControllers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isUnsavedChanges(
|
|
||||||
oldIngressControllers: IngressControllerClassMap[],
|
|
||||||
newIngressControllers: IngressControllerClassMap[]
|
|
||||||
) {
|
|
||||||
if (oldIngressControllers.length !== newIngressControllers.length) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (let i = 0; i < newIngressControllers.length; i += 1) {
|
|
||||||
if (
|
|
||||||
oldIngressControllers[i]?.Availability !==
|
|
||||||
newIngressControllers[i]?.Availability
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUpdatedIngressControllers(
|
|
||||||
selectedRows: IngressControllerClassMap[],
|
|
||||||
allRows: IngressControllerClassMap[],
|
|
||||||
allow: boolean
|
|
||||||
) {
|
|
||||||
const selectedRowClassNames = selectedRows.map((row) => row.ClassName);
|
|
||||||
const updatedIngressControllers = allRows?.map((row) => {
|
|
||||||
if (selectedRowClassNames.includes(row.ClassName)) {
|
|
||||||
return { ...row, Availability: allow };
|
|
||||||
}
|
|
||||||
return row;
|
|
||||||
});
|
|
||||||
return updatedIngressControllers;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user