mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
refactor(ui/box-selector): replace all selectors [EE-3856] (#7902)
This commit is contained in:
parent
c9253319d9
commit
2dddc1c6b9
80 changed files with 1267 additions and 1011 deletions
|
@ -734,90 +734,12 @@
|
|||
<div class="col-sm-12 small text-muted"> Specify how the data will be used across instances. </div>
|
||||
</div>
|
||||
|
||||
<!-- access policy options -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div
|
||||
ng-if="
|
||||
(!ctrl.state.isEdit && !ctrl.state.persistedFoldersUseExistingVolumes) ||
|
||||
(ctrl.state.isEdit && ctrl.formValues.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.ISOLATED)
|
||||
"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
id="data_access_isolated"
|
||||
ng-value="ctrl.ApplicationDataAccessPolicies.ISOLATED"
|
||||
ng-model="ctrl.formValues.DataAccessPolicy"
|
||||
ng-change="ctrl.resetDeploymentType()"
|
||||
/>
|
||||
<label for="data_access_isolated">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'boxes'"></pr-icon>
|
||||
Isolated
|
||||
</div>
|
||||
<p>Application will be deployed as a StatefulSet with each instantiating their own data</p>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
style="color: #767676"
|
||||
ng-if="
|
||||
(ctrl.state.isEdit && ctrl.formValues.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.SHARED) || ctrl.state.persistedFoldersUseExistingVolumes
|
||||
"
|
||||
>
|
||||
<input type="radio" id="data_access_isolated" disabled />
|
||||
<label
|
||||
for="data_access_isolated"
|
||||
tooltip-append-to-body="true"
|
||||
tooltip-placement="bottom"
|
||||
tooltip-class="portainer-tooltip"
|
||||
uib-tooltip="Changing the data access policy is not allowed"
|
||||
style="cursor: pointer; border-color: #767676"
|
||||
>
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'boxes'"></pr-icon>
|
||||
Isolated
|
||||
</div>
|
||||
<p>Application will be deployed as a StatefulSet with each instantiating their own data</p>
|
||||
</label>
|
||||
</div>
|
||||
<div ng-if="!ctrl.state.isEdit || (ctrl.state.isEdit && ctrl.formValues.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.SHARED)">
|
||||
<input
|
||||
type="radio"
|
||||
id="data_access_shared"
|
||||
ng-value="ctrl.ApplicationDataAccessPolicies.SHARED"
|
||||
ng-model="ctrl.formValues.DataAccessPolicy"
|
||||
ng-change="ctrl.resetDeploymentType()"
|
||||
/>
|
||||
<label for="data_access_shared">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'box'"></pr-icon>
|
||||
Shared
|
||||
</div>
|
||||
<p>Application will be deployed as a Deployment with a shared storage access</p>
|
||||
</label>
|
||||
</div>
|
||||
<div style="color: #767676" ng-if="ctrl.state.isEdit && ctrl.formValues.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.ISOLATED">
|
||||
<input type="radio" id="data_access_shared" disabled />
|
||||
<label
|
||||
for="data_access_shared"
|
||||
tooltip-append-to-body="true"
|
||||
tooltip-placement="bottom"
|
||||
tooltip-class="portainer-tooltip"
|
||||
uib-tooltip="Changing the data access policy is not allowed"
|
||||
style="cursor: pointer; border-color: #767676"
|
||||
>
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'sliders'"></pr-icon>
|
||||
Shared
|
||||
</div>
|
||||
<p>Application will be deployed as a Deployment with a shared storage access</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !access policy options -->
|
||||
<kube-application-access-policy-selector
|
||||
value="ctrl.formValues.DataAccessPolicy"
|
||||
on-change="(ctrl.onDataAccessPolicyChange)"
|
||||
is-edit="ctrl.state.isEdit"
|
||||
persisted-folders-use-existing-volumes="ctrl.state.persistedFoldersUseExistingVolumes"
|
||||
></kube-application-access-policy-selector>
|
||||
</div>
|
||||
<!-- #endregion -->
|
||||
|
||||
|
@ -925,62 +847,12 @@
|
|||
</div>
|
||||
|
||||
<!-- deployment options -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input
|
||||
type="radio"
|
||||
id="deployment_replicated"
|
||||
ng-value="ctrl.ApplicationDeploymentTypes.REPLICATED"
|
||||
ng-model="ctrl.formValues.DeploymentType"
|
||||
data-cy="k8sAppCreate-replicatedDeploymentButton"
|
||||
/>
|
||||
<label for="deployment_replicated">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'sliders'"></pr-icon>
|
||||
Replicated
|
||||
</div>
|
||||
<p>Run one or multiple instances of this container</p>
|
||||
</label>
|
||||
</div>
|
||||
<div ng-if="!ctrl.supportGlobalDeployment()">
|
||||
<input type="radio" id="deployment_global" disabled />
|
||||
<label
|
||||
for="deployment_global"
|
||||
tooltip-append-to-body="true"
|
||||
tooltip-placement="bottom"
|
||||
tooltip-class="portainer-tooltip"
|
||||
uib-tooltip="The storage or access policy used for persisted folders cannot be used with this option"
|
||||
>
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'boxes'"></pr-icon>
|
||||
Global
|
||||
</div>
|
||||
<p>Application will be deployed as a DaemonSet with an instance on each node of the cluster</p>
|
||||
</label>
|
||||
</div>
|
||||
<div ng-if="ctrl.supportGlobalDeployment()">
|
||||
<input
|
||||
type="radio"
|
||||
id="deployment_global"
|
||||
ng-value="ctrl.ApplicationDeploymentTypes.GLOBAL"
|
||||
ng-model="ctrl.formValues.DeploymentType"
|
||||
ng-click="ctrl.unselectAutoScaler()"
|
||||
data-cy="k8sAppCreate-globalDeployButton"
|
||||
/>
|
||||
<label for="deployment_global">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'boxes'"></pr-icon>
|
||||
Global
|
||||
</div>
|
||||
<p>Application will be deployed as a DaemonSet with an instance on each node of the cluster</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !deployment options -->
|
||||
<kube-application-deployment-type-selector
|
||||
value="ctrl.formValues.DeploymentType"
|
||||
on-change="(ctrl.onChangeDeploymentType)"
|
||||
support-global-deployment="ctrl.supportGlobalDeployment()"
|
||||
radio-name="'deploymentType'"
|
||||
></kube-application-deployment-type-selector>
|
||||
|
||||
<!-- replica count -->
|
||||
<div class="form-group" ng-if="ctrl.formValues.DeploymentType === ctrl.ApplicationDeploymentTypes.REPLICATED">
|
||||
|
@ -1260,46 +1132,14 @@
|
|||
<div class="col-sm-12 small text-muted"> Specify the policy associated to the placement rules. </div>
|
||||
</div>
|
||||
|
||||
<!-- placement policy options -->
|
||||
<div class="form-group" ng-if="ctrl.formValues.Placements.length">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input
|
||||
type="radio"
|
||||
id="placement_hard"
|
||||
ng-value="ctrl.ApplicationPlacementTypes.MANDATORY"
|
||||
ng-model="ctrl.formValues.PlacementType"
|
||||
data-cy="k8sAppCreate-mandatoryPlacementButton"
|
||||
/>
|
||||
<label for="placement_hard">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'sliders'"></pr-icon>
|
||||
Mandatory
|
||||
</div>
|
||||
<p>Schedule this application <b>ONLY</b> on nodes that match <b>ALL</b> Rules</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="radio"
|
||||
id="placement_soft"
|
||||
ng-value="ctrl.ApplicationPlacementTypes.PREFERRED"
|
||||
ng-model="ctrl.formValues.PlacementType"
|
||||
data-cy="k8sAppCreate-prefferedPlacementButton"
|
||||
/>
|
||||
<label for="placement_soft">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'align-justify'"></pr-icon>
|
||||
Preferred
|
||||
</div>
|
||||
<p>Schedule this application on nodes that match the rules if possible</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !placement policy options -->
|
||||
<box-selector
|
||||
ng-if="ctrl.formValues.Placements.length"
|
||||
options="ctrl.placementOptions"
|
||||
slim="true"
|
||||
value="ctrl.formValues.PlacementType"
|
||||
on-change="(ctrl.onChangePlacementType)"
|
||||
radio-name="'placementType'"
|
||||
></box-selector>
|
||||
</div>
|
||||
<!-- #endregion -->
|
||||
</div>
|
||||
|
|
|
@ -34,6 +34,7 @@ import KubernetesNamespaceHelper from 'Kubernetes/helpers/namespaceHelper';
|
|||
import { KubernetesNodeHelper } from 'Kubernetes/node/helper';
|
||||
import { updateIngress, getIngresses } from '@/react/kubernetes/ingresses/service';
|
||||
import { confirmUpdateAppIngress } from '@/portainer/services/modal.service/prompt';
|
||||
import { placementOptions } from './placementTypes';
|
||||
|
||||
class KubernetesCreateApplicationController {
|
||||
/* #region CONSTRUCTOR */
|
||||
|
@ -85,6 +86,8 @@ class KubernetesCreateApplicationController {
|
|||
this.ServiceTypes = KubernetesServiceTypes;
|
||||
this.KubernetesDeploymentTypes = KubernetesDeploymentTypes;
|
||||
|
||||
this.placementOptions = placementOptions;
|
||||
|
||||
this.state = {
|
||||
appType: this.KubernetesDeploymentTypes.APPLICATION_FORM,
|
||||
updateWebEditorInProgress: false,
|
||||
|
@ -148,9 +151,25 @@ class KubernetesCreateApplicationController {
|
|||
this.onServicePublishChange = this.onServicePublishChange.bind(this);
|
||||
this.checkIngressesToUpdate = this.checkIngressesToUpdate.bind(this);
|
||||
this.confirmUpdateApplicationAsync = this.confirmUpdateApplicationAsync.bind(this);
|
||||
this.onDataAccessPolicyChange = this.onDataAccessPolicyChange.bind(this);
|
||||
this.onChangeDeploymentType = this.onChangeDeploymentType.bind(this);
|
||||
this.supportGlobalDeployment = this.supportGlobalDeployment.bind(this);
|
||||
this.onChangePlacementType = this.onChangePlacementType.bind(this);
|
||||
}
|
||||
/* #endregion */
|
||||
|
||||
onChangePlacementType(value) {
|
||||
this.$scope.$evalAsync(() => {
|
||||
this.formValues.PlacementType = value;
|
||||
});
|
||||
}
|
||||
|
||||
onChangeDeploymentType(value) {
|
||||
this.$scope.$evalAsync(() => {
|
||||
this.formValues.DeploymentType = value;
|
||||
});
|
||||
}
|
||||
|
||||
onChangeFileContent(value) {
|
||||
if (this.stackFileContent.replace(/(\r\n|\n|\r)/gm, '') !== value.replace(/(\r\n|\n|\r)/gm, '')) {
|
||||
this.state.isEditorDirty = true;
|
||||
|
@ -158,6 +177,13 @@ class KubernetesCreateApplicationController {
|
|||
}
|
||||
}
|
||||
|
||||
onDataAccessPolicyChange(value) {
|
||||
this.$scope.$evalAsync(() => {
|
||||
this.formValues.DataAccessPolicy = value;
|
||||
this.resetDeploymentType();
|
||||
});
|
||||
}
|
||||
|
||||
async updateApplicationViaWebEditor() {
|
||||
return this.$async(async () => {
|
||||
try {
|
||||
|
@ -616,6 +642,7 @@ class KubernetesCreateApplicationController {
|
|||
if (hasFolders && (hasRWOOnly || isIsolated)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
30
app/kubernetes/views/applications/create/placementTypes.tsx
Normal file
30
app/kubernetes/views/applications/create/placementTypes.tsx
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { AlignJustify, Sliders } from 'lucide-react';
|
||||
|
||||
import { KubernetesApplicationPlacementTypes } from '@/kubernetes/models/application/models';
|
||||
|
||||
import { BoxSelectorOption } from '@@/BoxSelector';
|
||||
|
||||
export const placementOptions: ReadonlyArray<BoxSelectorOption<number>> = [
|
||||
{
|
||||
id: 'placement_hard',
|
||||
value: KubernetesApplicationPlacementTypes.MANDATORY,
|
||||
icon: Sliders,
|
||||
iconType: 'badge',
|
||||
label: 'Mandatory',
|
||||
description: (
|
||||
<>
|
||||
Schedule this application <b>ONLY</b> on nodes that match <b>ALL</b>{' '}
|
||||
Rules
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'placement_soft',
|
||||
value: KubernetesApplicationPlacementTypes.PREFERRED,
|
||||
icon: AlignJustify,
|
||||
iconType: 'badge',
|
||||
label: 'Preferred',
|
||||
description:
|
||||
'Schedule this application on nodes that match the rules if possible',
|
||||
},
|
||||
] as const;
|
Loading…
Add table
Add a link
Reference in a new issue