mirror of https://github.com/portainer/portainer
fix(ui): box-selector fixes [EE-3949] (#7489)
parent
8d304b78cb
commit
ace01eac9d
|
@ -1,4 +1,8 @@
|
|||
<svg width="51" height="57" viewBox="0 0 51 57" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M49.4176 17.75L43.882 0.819107H7.28089L1.74531 17.75C1.74531 17.75 -4.79215 34.8935 10.4787 45.4348C24.3922 55.0404 25.5814 56.2077 25.5814 56.2077C25.5814 56.2077 26.7707 55.038 40.6842 45.4348C55.955 34.8935 49.4176 17.75 49.4176 17.75Z" fill="#F4552A"/>
|
||||
<path d="M25.5851 0.984695L31.4835 17.6745L49.4453 18.0361L35.1283 28.7097L40.3323 45.6217L25.5851 35.5293L10.838 45.6217L16.042 28.7097L1.72498 18.0361L19.6868 17.6745L25.5851 0.984695Z" fill="white"/>
|
||||
</svg>
|
||||
<svg width="auto" height="auto" viewBox="0 0 36 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M22.9751 15.3177L20.4526 7.52911H3.77358L1.25103 15.3177C1.25103 15.3177 -1.72806 23.2041 5.23082 28.0533C11.5711 32.4721 12.1131 33.0091 12.1131 33.0091C12.1131 33.0091 12.655 32.471 18.9953 28.0533C25.9542 23.2041 22.9751 15.3177 22.9751 15.3177Z"
|
||||
fill="#F4552A" />
|
||||
<path
|
||||
d="M12.1152 7.60529L14.803 15.283L22.9882 15.4493L16.4639 20.3594L18.8354 28.1393L12.1152 23.4966L5.39497 28.1393L7.76642 20.3594L1.24219 15.4493L9.42731 15.283L12.1152 7.60529Z"
|
||||
fill="white" />
|
||||
</svg>
|
Before Width: | Height: | Size: 572 B After Width: | Height: | Size: 604 B |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
@ -76,37 +76,39 @@
|
|||
<!-- build-method -->
|
||||
<div class="col-sm-12 form-section-title"> Build method </div>
|
||||
<div class="form-group"></div>
|
||||
<div class="form-group" class="mb-0">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="method_editor" ng-model="state.BuildType" value="editor" ng-click="toggleEditor()" />
|
||||
<label for="method_editor">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Web editor
|
||||
</div>
|
||||
<p>Use our Web editor</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_upload" ng-model="state.BuildType" value="upload" ng-click="saveEditorContent()" />
|
||||
<label for="method_upload">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'upload'" feather="true"></pr-icon>
|
||||
Upload
|
||||
</div>
|
||||
<p>Upload a tarball or a Dockerfile from your computer</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_url" ng-model="state.BuildType" value="url" ng-click="saveEditorContent()" />
|
||||
<label for="method_url">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'globe'" feather="true"></pr-icon>
|
||||
URL
|
||||
</div>
|
||||
<p>Specify a URL to a file</p>
|
||||
</label>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="method_editor" ng-model="state.BuildType" value="editor" ng-click="toggleEditor()" />
|
||||
<label for="method_editor">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Web editor
|
||||
</div>
|
||||
<p>Use our Web editor</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_upload" ng-model="state.BuildType" value="upload" ng-click="saveEditorContent()" />
|
||||
<label for="method_upload">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'upload'" feather="true"></pr-icon>
|
||||
Upload
|
||||
</div>
|
||||
<p>Upload a tarball or a Dockerfile from your computer</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_url" ng-model="state.BuildType" value="url" ng-click="saveEditorContent()" />
|
||||
<label for="method_url">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'globe'" feather="true"></pr-icon>
|
||||
URL
|
||||
</div>
|
||||
<p>Specify a URL to a file</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -34,27 +34,29 @@
|
|||
<!-- edge-job-method-select -->
|
||||
<div class="col-sm-12 form-section-title"> Edge job configuration </div>
|
||||
<div class="form-group"></div>
|
||||
<div class="form-group px-4">
|
||||
<div class="boxselector_wrapper !mt-0">
|
||||
<div>
|
||||
<input type="radio" id="config_basic" ng-model="$ctrl.formValues.cronMethod" value="basic" />
|
||||
<label for="config_basic">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'calendar'" feather="true"></pr-icon>
|
||||
Basic configuration
|
||||
</div>
|
||||
<p>Select date from calendar</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="config_advanced" ng-model="$ctrl.formValues.cronMethod" value="advanced" />
|
||||
<label for="config_advanced">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Advanced configuration
|
||||
</div>
|
||||
<p>Write your own cron rule</p>
|
||||
</label>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper !mt-0">
|
||||
<div>
|
||||
<input type="radio" id="config_basic" ng-model="$ctrl.formValues.cronMethod" value="basic" />
|
||||
<label for="config_basic">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'calendar'" feather="true"></pr-icon>
|
||||
Basic configuration
|
||||
</div>
|
||||
<p>Select date from calendar</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="config_advanced" ng-model="$ctrl.formValues.cronMethod" value="advanced" />
|
||||
<label for="config_advanced">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Advanced configuration
|
||||
</div>
|
||||
<p>Write your own cron rule</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -151,28 +153,29 @@
|
|||
<!-- execution-method -->
|
||||
<div ng-if="!$ctrl.model.Id">
|
||||
<div class="col-sm-12 form-section-title"> Job content </div>
|
||||
<div class="form-group"></div>
|
||||
<div class="form-group px-4">
|
||||
<div class="boxselector_wrapper !mt-0">
|
||||
<div>
|
||||
<input type="radio" id="method_editor" ng-model="$ctrl.formValues.method" value="editor" />
|
||||
<label for="method_editor">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Web editor
|
||||
</div>
|
||||
<p>Use our Web editor</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_upload" ng-model="$ctrl.formValues.method" value="upload" />
|
||||
<label for="method_upload">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'upload'" feather="true"></pr-icon>
|
||||
Upload
|
||||
</div>
|
||||
<p>Upload from your computer</p>
|
||||
</label>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="method_editor" ng-model="$ctrl.formValues.method" value="editor" />
|
||||
<label for="method_editor">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Web editor
|
||||
</div>
|
||||
<p>Use our Web editor</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_upload" ng-model="$ctrl.formValues.method" value="upload" />
|
||||
<label for="method_upload">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'upload'" feather="true"></pr-icon>
|
||||
Upload
|
||||
</div>
|
||||
<p>Upload from your computer</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import { compose, kubernetes } from '@@/BoxSelector/common-options/deployment-methods';
|
||||
|
||||
export default class EdgeStackDeploymentTypeSelectorController {
|
||||
/* @ngInject */
|
||||
constructor() {
|
||||
this.deploymentOptions = [
|
||||
{ id: 'deployment_compose', icon: 'fab fa-docker', label: 'Compose', description: 'Docker compose format', value: 0 },
|
||||
{
|
||||
id: 'deployment_kube',
|
||||
icon: 'fa fa-cubes',
|
||||
label: 'Kubernetes',
|
||||
description: 'Kubernetes manifest format',
|
||||
...compose,
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
...kubernetes,
|
||||
value: 1,
|
||||
disabled: () => {
|
||||
return this.hasDockerEndpoint();
|
||||
|
|
|
@ -26,27 +26,29 @@
|
|||
</div>
|
||||
|
||||
<div class="col-sm-12 form-section-title"> Group type </div>
|
||||
<div class="col-sm-12 !px-0">
|
||||
<div class="boxselector_wrapper">
|
||||
<div class="boxselector">
|
||||
<input type="radio" id="static-group" ng-model="$ctrl.model.Dynamic" ng-value="false" ng-checked="!$ctrl.model.Dynamic" />
|
||||
<label for="static-group">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'list'" feather="true"></pr-icon>
|
||||
Static
|
||||
</div>
|
||||
<p>Manually select Edge environments</p>
|
||||
</label>
|
||||
</div>
|
||||
<div class="boxselector">
|
||||
<input type="radio" id="dynamic-group" ng-model="$ctrl.model.Dynamic" ng-value="true" ng-checked="$ctrl.model.Dynamic" />
|
||||
<label for="dynamic-group">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'tag'" feather="true" className="'feather'"></pr-icon>
|
||||
Dynamic
|
||||
</div>
|
||||
<p>Automatically associate environments via tags</p>
|
||||
</label>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div class="boxselector">
|
||||
<input type="radio" id="static-group" ng-model="$ctrl.model.Dynamic" ng-value="false" ng-checked="!$ctrl.model.Dynamic" />
|
||||
<label for="static-group">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'list'" feather="true"></pr-icon>
|
||||
Static
|
||||
</div>
|
||||
<p>Manually select Edge environments</p>
|
||||
</label>
|
||||
</div>
|
||||
<div class="boxselector">
|
||||
<input type="radio" id="dynamic-group" ng-model="$ctrl.model.Dynamic" ng-value="true" ng-checked="$ctrl.model.Dynamic" />
|
||||
<label for="dynamic-group">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'tag'" feather="true"></pr-icon>
|
||||
Dynamic
|
||||
</div>
|
||||
<p>Automatically associate environments via tags</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -78,27 +80,29 @@
|
|||
<!-- DynamicGroup -->
|
||||
<div ng-if="$ctrl.model.Dynamic">
|
||||
<div class="col-sm-12 form-section-title"> Tags </div>
|
||||
<div ng-if="$ctrl.tags.length" class="form-group col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div class="boxselector">
|
||||
<input type="radio" id="or-selector" ng-model="$ctrl.model.PartialMatch" ng-value="true" ng-checked="$ctrl.model.PartialMatch" />
|
||||
<label for="or-selector">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'tag'" feather="true"></pr-icon>
|
||||
Partial match
|
||||
</div>
|
||||
<p>Associate any environment matching at least one of the selected tags</p>
|
||||
</label>
|
||||
</div>
|
||||
<div class="boxselector">
|
||||
<input type="radio" id="and-selector" ng-model="$ctrl.model.PartialMatch" ng-value="false" ng-checked="!$ctrl.model.PartialMatch" />
|
||||
<label for="and-selector">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'tag'" feather="true" className="'feather'"></pr-icon>
|
||||
Full match
|
||||
</div>
|
||||
<p>Associate any environment matching all of the selected tags</p>
|
||||
</label>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div class="boxselector">
|
||||
<input type="radio" id="or-selector" ng-model="$ctrl.model.PartialMatch" ng-value="true" ng-checked="$ctrl.model.PartialMatch" />
|
||||
<label for="or-selector">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'tag'" feather="true"></pr-icon>
|
||||
Partial match
|
||||
</div>
|
||||
<p>Associate any environment matching at least one of the selected tags</p>
|
||||
</label>
|
||||
</div>
|
||||
<div class="boxselector">
|
||||
<input type="radio" id="and-selector" ng-model="$ctrl.model.PartialMatch" ng-value="false" ng-checked="!$ctrl.model.PartialMatch" />
|
||||
<label for="and-selector">
|
||||
<div class="boxselector_header vertical-center">
|
||||
<pr-icon icon="'tag'" feather="true"></pr-icon>
|
||||
Full match
|
||||
</div>
|
||||
<p>Associate any environment matching all of the selected tags</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
import { editor, git, template, upload } from '@@/BoxSelector/common-options/build-methods';
|
||||
|
||||
class DockerComposeFormController {
|
||||
/* @ngInject */
|
||||
constructor($async, EdgeTemplateService, Notifications) {
|
||||
Object.assign(this, { $async, EdgeTemplateService, Notifications });
|
||||
|
||||
this.methodOptions = [
|
||||
{ id: 'method_editor', icon: 'edit', featherIcon: true, label: 'Web editor', description: 'Use our Web editor', value: 'editor' },
|
||||
{ id: 'method_upload', icon: 'upload', featherIcon: true, label: 'Upload', description: 'Upload from your computer', value: 'upload' },
|
||||
{ id: 'method_repository', icon: 'github', featherIcon: true, label: 'Repository', description: 'Use a git repository', value: 'repository' },
|
||||
{ id: 'method_template', icon: 'file-text', featherIcon: true, label: 'Template', description: 'Use an Edge stack template', value: 'template' },
|
||||
];
|
||||
this.methodOptions = [editor, upload, git, template];
|
||||
|
||||
this.selectedTemplate = null;
|
||||
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
import { editor, git, upload } from '@@/BoxSelector/common-options/build-methods';
|
||||
|
||||
class KubeManifestFormController {
|
||||
/* @ngInject */
|
||||
constructor($async) {
|
||||
Object.assign(this, { $async });
|
||||
|
||||
this.methodOptions = [
|
||||
{ id: 'method_editor', icon: 'edit', featherIcon: true, label: 'Web editor', description: 'Use our Web editor', value: 'editor' },
|
||||
{ id: 'method_upload', icon: 'upload', featherIcon: true, label: 'Upload', description: 'Upload from your computer', value: 'upload' },
|
||||
{ id: 'method_repository', icon: 'github', featherIcon: true, label: 'Repository', description: 'Use a git repository', value: 'repository' },
|
||||
];
|
||||
this.methodOptions = [editor, upload, git];
|
||||
|
||||
this.onChangeFileContent = this.onChangeFileContent.bind(this);
|
||||
this.onChangeFormValues = this.onChangeFormValues.bind(this);
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
import { buildOption } from '@/portainer/components/BoxSelector';
|
||||
import { AccessControlFormData } from '@/portainer/components/accessControlForm/porAccessControlFormModel';
|
||||
import { getTemplateVariables, intersectVariables } from '@/react/portainer/custom-templates/components/utils';
|
||||
import { isBE } from '@/portainer/feature-flags/feature-flags.service';
|
||||
import { editor, upload } from '@@/BoxSelector/common-options/build-methods';
|
||||
|
||||
class KubeCreateCustomTemplateViewController {
|
||||
/* @ngInject */
|
||||
constructor($async, $state, Authentication, CustomTemplateService, FormValidator, ModalService, Notifications, ResourceControlService) {
|
||||
Object.assign(this, { $async, $state, Authentication, CustomTemplateService, FormValidator, ModalService, Notifications, ResourceControlService });
|
||||
|
||||
this.methodOptions = [
|
||||
buildOption('method_editor', 'svg-custom', 'Web editor', 'Use our Web editor', 'editor'),
|
||||
buildOption('method_upload', 'svg-upload', 'Upload', 'Upload from your computer', 'upload'),
|
||||
];
|
||||
this.methodOptions = [editor, upload];
|
||||
|
||||
this.templates = null;
|
||||
this.isTemplateVariablesEnabled = isBE;
|
||||
|
|
|
@ -709,83 +709,85 @@
|
|||
</div>
|
||||
|
||||
<!-- access policy options -->
|
||||
<div class="form-group" style="margin-bottom: 0">
|
||||
<div class="boxselector_wrapper !px-[15px]">
|
||||
<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="'svg-cubes'"></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="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)
|
||||
"
|
||||
>
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'svg-cubes'"></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'" feather="true"></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"
|
||||
<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="'svg-cubes'"></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
|
||||
"
|
||||
>
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'sliders'" feather="true"></pr-icon>
|
||||
Shared
|
||||
</div>
|
||||
<p>Application will be deployed as a Deployment with a shared storage access</p>
|
||||
</label>
|
||||
<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="'svg-cubes'"></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'" feather="true"></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'" feather="true"></pr-icon>
|
||||
Shared
|
||||
</div>
|
||||
<p>Application will be deployed as a Deployment with a shared storage access</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -897,56 +899,58 @@
|
|||
</div>
|
||||
|
||||
<!-- deployment options -->
|
||||
<div class="form-group" style="margin-bottom: 0">
|
||||
<div class="boxselector_wrapper !px-[15px]">
|
||||
<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'" feather="true"></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="'svg-cubes'"></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="'svg-cubes'"></pr-icon>
|
||||
Global
|
||||
</div>
|
||||
<p>Application will be deployed as a DaemonSet with an instance on each node of the sdfh</p>
|
||||
</label>
|
||||
<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'" feather="true"></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="'svg-cubes'"></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="'svg-cubes'"></pr-icon>
|
||||
Global
|
||||
</div>
|
||||
<p>Application will be deployed as a DaemonSet with an instance on each node of the sdfh</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1234,39 +1238,41 @@
|
|||
</div>
|
||||
|
||||
<!-- placement policy options -->
|
||||
<div class="form-group" style="margin-bottom: 0" ng-if="ctrl.formValues.Placements.length">
|
||||
<div class="boxselector_wrapper !px-[15px]">
|
||||
<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'" feather="true"></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'" feather="true"></pr-icon>
|
||||
Preferred
|
||||
</div>
|
||||
<p>Schedule this application on nodes that match the rules if possible</p>
|
||||
</label>
|
||||
<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'" feather="true"></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'" feather="true"></pr-icon>
|
||||
Preferred
|
||||
</div>
|
||||
<p>Schedule this application on nodes that match the rules if possible</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -87,27 +87,29 @@
|
|||
</div>
|
||||
|
||||
<!-- type options -->
|
||||
<div class="form-group px-[15px]" style="margin-bottom: 0">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="type_basic" ng-value="ctrl.KubernetesConfigurationTypes.CONFIGMAP" ng-model="ctrl.formValues.Type" />
|
||||
<label for="type_basic" data-cy="k8sConfigCreate-nonSensitiveButton">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'svg-filecode'"></pr-icon>
|
||||
ConfigMap
|
||||
</div>
|
||||
<p>This configuration holds non-sensitive information</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="type_secret" ng-value="ctrl.KubernetesConfigurationTypes.SECRET" ng-model="ctrl.formValues.Type" />
|
||||
<label for="type_secret" data-cy="k8sConfigCreate-sensitiveButton">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'lock'" feather="true"></pr-icon>
|
||||
Secret
|
||||
</div>
|
||||
<p>This configuration holds sensitive information</p>
|
||||
</label>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="type_basic" ng-value="ctrl.KubernetesConfigurationTypes.CONFIGMAP" ng-model="ctrl.formValues.Type" />
|
||||
<label for="type_basic" data-cy="k8sConfigCreate-nonSensitiveButton">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'svg-filecode'"></pr-icon>
|
||||
ConfigMap
|
||||
</div>
|
||||
<p>This configuration holds non-sensitive information</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="type_secret" ng-value="ctrl.KubernetesConfigurationTypes.SECRET" ng-model="ctrl.formValues.Type" />
|
||||
<label for="type_secret" data-cy="k8sConfigCreate-sensitiveButton">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'lock'" feather="true"></pr-icon>
|
||||
Secret
|
||||
</div>
|
||||
<p>This configuration holds sensitive information</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,9 +5,10 @@ import uuidv4 from 'uuid/v4';
|
|||
|
||||
import PortainerError from '@/portainer/error';
|
||||
import { KubernetesDeployManifestTypes, KubernetesDeployBuildMethods, KubernetesDeployRequestMethods, RepositoryMechanismTypes } from 'Kubernetes/models/deploy';
|
||||
import { buildOption } from '@/portainer/components/BoxSelector';
|
||||
import { renderTemplate } from '@/react/portainer/custom-templates/components/utils';
|
||||
import { isBE } from '@/portainer/feature-flags/feature-flags.service';
|
||||
import { compose, kubernetes } from '@@/BoxSelector/common-options/deployment-methods';
|
||||
import { editor, git, template, url } from '@@/BoxSelector/common-options/build-methods';
|
||||
|
||||
class KubernetesDeployController {
|
||||
/* @ngInject */
|
||||
|
@ -27,15 +28,15 @@ class KubernetesDeployController {
|
|||
this.isTemplateVariablesEnabled = isBE;
|
||||
|
||||
this.deployOptions = [
|
||||
buildOption('method_kubernetes', 'svg-kubernetes', 'Kubernetes', 'Kubernetes manifest format', KubernetesDeployManifestTypes.KUBERNETES),
|
||||
buildOption('method_compose', 'svg-dockercompose', 'Compose', 'Docker compose format', KubernetesDeployManifestTypes.COMPOSE),
|
||||
{ ...kubernetes, value: KubernetesDeployManifestTypes.KUBERNETES },
|
||||
{ ...compose, value: KubernetesDeployManifestTypes.COMPOSE },
|
||||
];
|
||||
|
||||
this.methodOptions = [
|
||||
buildOption('method_repo', 'svg-git', 'Git Repository', 'Use a git repository', KubernetesDeployBuildMethods.GIT),
|
||||
buildOption('method_editor', 'svg-custom', 'Web editor', 'Use our Web editor', KubernetesDeployBuildMethods.WEB_EDITOR),
|
||||
buildOption('method_url', 'svg-url', 'URL', 'Specify a URL to a file', KubernetesDeployBuildMethods.URL),
|
||||
buildOption('method_template', 'svg-template', 'Custom Template', 'Use a custom template', KubernetesDeployBuildMethods.CUSTOM_TEMPLATE),
|
||||
{ ...git, value: KubernetesDeployBuildMethods.GIT },
|
||||
{ ...editor, value: KubernetesDeployBuildMethods.WEB_EDITOR },
|
||||
{ ...url, value: KubernetesDeployBuildMethods.URL },
|
||||
{ ...template, value: KubernetesDeployBuildMethods.CUSTOM_TEMPLATE },
|
||||
];
|
||||
|
||||
this.state = {
|
||||
|
|
|
@ -47,16 +47,12 @@ export function EditDetails({
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="form-group">
|
||||
<div className="col-sm-12">
|
||||
<BoxSelector
|
||||
radioName={withNamespace('ownership')}
|
||||
value={values.ownership}
|
||||
options={options}
|
||||
onChange={(ownership) => handleChangeOwnership(ownership)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<BoxSelector
|
||||
radioName={withNamespace('ownership')}
|
||||
value={values.ownership}
|
||||
options={options}
|
||||
onChange={(ownership) => handleChangeOwnership(ownership)}
|
||||
/>
|
||||
|
||||
{values.ownership === ResourceControlOwnership.RESTRICTED && (
|
||||
<div aria-label="extra-options">
|
||||
|
|
|
@ -6,6 +6,7 @@ import { ownershipIcon } from '@/portainer/filters/filters';
|
|||
import { Team } from '@/portainer/teams/types';
|
||||
|
||||
import { BoxSelectorOption } from '@@/BoxSelector/types';
|
||||
import { BadgeIcon } from '@@/BoxSelector/BadgeIcon';
|
||||
|
||||
import { ResourceControlOwnership } from '../types';
|
||||
|
||||
|
@ -15,7 +16,7 @@ const publicOption: BoxSelectorOption<ResourceControlOwnership> = {
|
|||
id: 'access_public',
|
||||
description:
|
||||
'I want any user with access to this environment to be able to manage this resource',
|
||||
icon: ownershipIcon('public'),
|
||||
icon: <BadgeIcon icon={ownershipIcon('public')} />,
|
||||
};
|
||||
|
||||
export function useOptions(
|
||||
|
@ -40,14 +41,14 @@ function adminOptions() {
|
|||
return [
|
||||
buildOption(
|
||||
'access_administrators',
|
||||
ownershipIcon('administrators'),
|
||||
<BadgeIcon icon={ownershipIcon('administrators')} />,
|
||||
'Administrators',
|
||||
'I want to restrict the management of this resource to administrators only',
|
||||
ResourceControlOwnership.ADMINISTRATORS
|
||||
),
|
||||
buildOption(
|
||||
'access_restricted',
|
||||
ownershipIcon('restricted'),
|
||||
<BadgeIcon icon={ownershipIcon('restricted')} />,
|
||||
'Restricted',
|
||||
'I want to restrict the management of this resource to a set of users and/or teams',
|
||||
ResourceControlOwnership.RESTRICTED
|
||||
|
@ -58,7 +59,7 @@ function nonAdminOptions(teams?: Team[]) {
|
|||
return _.compact([
|
||||
buildOption(
|
||||
'access_private',
|
||||
ownershipIcon('private'),
|
||||
<BadgeIcon icon={ownershipIcon('private')} />,
|
||||
'Private',
|
||||
'I want to this resource to be manageable by myself only',
|
||||
ResourceControlOwnership.PRIVATE
|
||||
|
@ -67,7 +68,7 @@ function nonAdminOptions(teams?: Team[]) {
|
|||
teams.length > 0 &&
|
||||
buildOption(
|
||||
'access_restricted',
|
||||
ownershipIcon('restricted'),
|
||||
<BadgeIcon icon={ownershipIcon('restricted')} />,
|
||||
'Restricted',
|
||||
teams.length === 1
|
||||
? `I want any member of my team (${teams[0].Name}) to be able to manage this resource`
|
|
@ -1,15 +1,16 @@
|
|||
import { FeatureId } from '@/portainer/feature-flags/enums';
|
||||
|
||||
import { BoxSelectorOption } from '@@/BoxSelector/types';
|
||||
import { IconProps } from '@@/Icon';
|
||||
|
||||
export function buildOption<T extends number | string>(
|
||||
id: string,
|
||||
icon: string,
|
||||
icon: IconProps['icon'],
|
||||
label: string,
|
||||
description: string,
|
||||
value: T,
|
||||
feature?: FeatureId,
|
||||
featherIcon?: boolean
|
||||
featherIcon?: IconProps['featherIcon']
|
||||
): BoxSelectorOption<T> {
|
||||
return { id, icon, label, description, value, feature, featherIcon };
|
||||
}
|
||||
|
|
|
@ -15,51 +15,54 @@
|
|||
</div>
|
||||
<!-- !access-control-switch -->
|
||||
<!-- restricted-access -->
|
||||
<div class="form-group" ng-if="$ctrl.formData.AccessControlEnabled" style="margin-bottom: 0">
|
||||
<div class="boxselector_wrapper px-[15px]">
|
||||
<div ng-if="$ctrl.isAdmin">
|
||||
<input type="radio" id="access_administrators" ng-model="$ctrl.formData.Ownership" value="administrators" />
|
||||
<label for="access_administrators" data-cy="portainer-selectAdminAccess">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'eye-off'" feather="true"></pr-icon>
|
||||
Administrators
|
||||
</div>
|
||||
<p class="boxselector_content">I want to restrict the management of this resource to administrators only</p>
|
||||
</label>
|
||||
</div>
|
||||
<div ng-if="$ctrl.isAdmin">
|
||||
<input type="radio" id="access_restricted" ng-model="$ctrl.formData.Ownership" value="restricted" />
|
||||
<label for="access_restricted" data-cy="portainer-selectRestrictedAccess">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'users'" feather="true"></pr-icon>
|
||||
Restricted
|
||||
</div>
|
||||
<p class="boxselector_content"> I want to restrict the management of this resource to a set of users and/or teams </p>
|
||||
</label>
|
||||
</div>
|
||||
<div ng-if="!$ctrl.isAdmin">
|
||||
<input type="radio" id="access_private" ng-model="$ctrl.formData.Ownership" value="private" />
|
||||
<label for="access_private">
|
||||
<div class="boxselector_header">
|
||||
<i ng-class="'private' | ownershipicon" aria-hidden="true" style="margin-right: 2px"></i>
|
||||
Private
|
||||
</div>
|
||||
<p> I want to this resource to be manageable by myself only </p>
|
||||
</label>
|
||||
</div>
|
||||
<div ng-if="!$ctrl.isAdmin && $ctrl.availableTeams.length > 0">
|
||||
<input type="radio" id="access_restricted" ng-model="$ctrl.formData.Ownership" value="restricted" />
|
||||
<label for="access_restricted">
|
||||
<div class="boxselector_header">
|
||||
<i ng-class="'restricted' | ownershipicon" aria-hidden="true" style="margin-right: 2px"></i>
|
||||
Restricted
|
||||
</div>
|
||||
<p ng-if="$ctrl.availableTeams.length === 1">
|
||||
I want any member of my team (<b>{{ $ctrl.availableTeams[0].Name }}</b
|
||||
>) to be able to manage this resource
|
||||
</p>
|
||||
<p ng-if="$ctrl.availableTeams.length > 1"> I want to restrict the management of this resource to one or more of my teams </p>
|
||||
</label>
|
||||
<div class="form-group" ng-if="$ctrl.formData.AccessControlEnabled">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div ng-if="$ctrl.isAdmin">
|
||||
<input type="radio" id="access_administrators" ng-model="$ctrl.formData.Ownership" value="administrators" />
|
||||
<label for="access_administrators" data-cy="portainer-selectAdminAccess">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'eye-off'" feather="true"></pr-icon>
|
||||
Administrators
|
||||
</div>
|
||||
<p class="boxselector_content">I want to restrict the management of this resource to administrators only</p>
|
||||
</label>
|
||||
</div>
|
||||
<div ng-if="$ctrl.isAdmin">
|
||||
<input type="radio" id="access_restricted" ng-model="$ctrl.formData.Ownership" value="restricted" />
|
||||
<label for="access_restricted" data-cy="portainer-selectRestrictedAccess">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'users'" feather="true"></pr-icon>
|
||||
Restricted
|
||||
</div>
|
||||
<p class="boxselector_content"> I want to restrict the management of this resource to a set of users and/or teams </p>
|
||||
</label>
|
||||
</div>
|
||||
<div ng-if="!$ctrl.isAdmin">
|
||||
<input type="radio" id="access_private" ng-model="$ctrl.formData.Ownership" value="private" />
|
||||
<label for="access_private">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'eye-off'" feather="true"></pr-icon>
|
||||
Private
|
||||
</div>
|
||||
<p> I want to this resource to be manageable by myself only </p>
|
||||
</label>
|
||||
</div>
|
||||
<div ng-if="!$ctrl.isAdmin && $ctrl.availableTeams.length > 0">
|
||||
<input type="radio" id="access_restricted" ng-model="$ctrl.formData.Ownership" value="restricted" />
|
||||
<label for="access_restricted">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'users'" feather="true"></pr-icon>
|
||||
|
||||
Restricted
|
||||
</div>
|
||||
<p ng-if="$ctrl.availableTeams.length === 1">
|
||||
I want any member of my team (<b>{{ $ctrl.availableTeams[0].Name }}</b
|
||||
>) to be able to manage this resource
|
||||
</p>
|
||||
<p ng-if="$ctrl.availableTeams.length > 1"> I want to restrict the management of this resource to one or more of my teams </p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -24,47 +24,49 @@
|
|||
</div>
|
||||
<div class="form-group"></div>
|
||||
<!-- endpoint-tls-mode -->
|
||||
<div class="form-group" style="margin-bottom: 0" ng-if="$ctrl.formData.TLS">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="tls_client_ca" ng-model="$ctrl.formData.TLSMode" value="tls_client_ca" />
|
||||
<label for="tls_client_ca">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'shield'" feather="true"></pr-icon>
|
||||
TLS with server and client verification
|
||||
</div>
|
||||
<p>Use client certificates and server verification</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="tls_client_noca" ng-model="$ctrl.formData.TLSMode" value="tls_client_noca" />
|
||||
<label for="tls_client_noca">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'shield'" feather="true"></pr-icon>
|
||||
TLS with client verification only
|
||||
</div>
|
||||
<p>Use client certificates without server verification</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="tls_ca" ng-model="$ctrl.formData.TLSMode" value="tls_ca" />
|
||||
<label for="tls_ca">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'shield'" feather="true"></pr-icon>
|
||||
TLS with server verification only
|
||||
</div>
|
||||
<p>Only verify the server certificate</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="tls_only" ng-model="$ctrl.formData.TLSMode" value="tls_only" />
|
||||
<label for="tls_only">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'shield'" feather="true"></pr-icon>
|
||||
TLS only
|
||||
</div>
|
||||
<p>No server/client verification</p>
|
||||
</label>
|
||||
<div class="form-group" ng-if="$ctrl.formData.TLS">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="tls_client_ca" ng-model="$ctrl.formData.TLSMode" value="tls_client_ca" />
|
||||
<label for="tls_client_ca">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'shield'" feather="true"></pr-icon>
|
||||
TLS with server and client verification
|
||||
</div>
|
||||
<p>Use client certificates and server verification</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="tls_client_noca" ng-model="$ctrl.formData.TLSMode" value="tls_client_noca" />
|
||||
<label for="tls_client_noca">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'shield'" feather="true"></pr-icon>
|
||||
TLS with client verification only
|
||||
</div>
|
||||
<p>Use client certificates without server verification</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="tls_ca" ng-model="$ctrl.formData.TLSMode" value="tls_ca" />
|
||||
<label for="tls_ca">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'shield'" feather="true"></pr-icon>
|
||||
TLS with server verification only
|
||||
</div>
|
||||
<p>Only verify the server certificate</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="tls_only" ng-model="$ctrl.formData.TLSMode" value="tls_only" />
|
||||
<label for="tls_only">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'shield'" feather="true"></pr-icon>
|
||||
TLS only
|
||||
</div>
|
||||
<p>No server/client verification</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,10 +2,8 @@
|
|||
<rd-widget>
|
||||
<rd-widget-header icon="sliders" feather-icon="true" title-text="User theme"></rd-widget-header>
|
||||
<rd-widget-body>
|
||||
<form class="theme-panel">
|
||||
<!-- Theme Selector-->
|
||||
<form class="form-horizontal">
|
||||
<box-selector radio-name="'theme'" value="$ctrl.state.userTheme" options="$ctrl.state.availableThemes" on-change="($ctrl.setTheme)"></box-selector>
|
||||
<!-- !Theme -->
|
||||
</form>
|
||||
<p class="mt-2 vertical-center">
|
||||
<pr-icon icon="'alert-circle'" class-name="'icon-primary'" feather="true"></pr-icon>
|
||||
|
|
|
@ -2,6 +2,7 @@ import moment from 'moment';
|
|||
import _ from 'lodash-es';
|
||||
import filesize from 'filesize';
|
||||
|
||||
import { Eye, EyeOff, Users } from 'react-feather';
|
||||
import { ResourceControlOwnership as RCO } from '@/portainer/access-control/types';
|
||||
|
||||
export function truncateLeftRight(text, max, left, right) {
|
||||
|
@ -106,13 +107,13 @@ export function environmentTypeIcon(type) {
|
|||
export function ownershipIcon(ownership) {
|
||||
switch (ownership) {
|
||||
case RCO.PRIVATE:
|
||||
return 'eye-off';
|
||||
return EyeOff;
|
||||
case RCO.ADMINISTRATORS:
|
||||
return 'eye-off';
|
||||
return EyeOff;
|
||||
case RCO.RESTRICTED:
|
||||
return 'users';
|
||||
return Users;
|
||||
default:
|
||||
return 'eye';
|
||||
return Eye;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import { Edit } from 'react-feather';
|
||||
|
||||
import { FeatureId } from '@/portainer/feature-flags/enums';
|
||||
import Microsoft from '@/assets/ico/vendor/microsoft.svg?c';
|
||||
import Google from '@/assets/ico/vendor/google.svg?c';
|
||||
import Github from '@/assets/ico/vendor/github.svg?c';
|
||||
import Custom from '@/assets/ico/custom.svg?c';
|
||||
|
||||
import { BadgeIcon } from '@@/BoxSelector/BadgeIcon';
|
||||
|
||||
export const options = [
|
||||
{
|
||||
|
@ -32,7 +35,7 @@ export const options = [
|
|||
},
|
||||
{
|
||||
id: 'custom',
|
||||
icon: Custom,
|
||||
icon: <BadgeIcon icon={Edit} />,
|
||||
label: 'Custom',
|
||||
description: 'Custom OAuth provider',
|
||||
value: 'custom',
|
||||
|
|
|
@ -15,6 +15,7 @@ import { TableColumnHeaderAngular } from '@@/datatables/TableHeaderCell';
|
|||
import { DashboardItem } from '@@/DashboardItem';
|
||||
import { SearchBar } from '@@/datatables/SearchBar';
|
||||
import { FallbackImage } from '@@/FallbackImage';
|
||||
import { BadgeIcon } from '@@/BoxSelector/BadgeIcon';
|
||||
|
||||
import { fileUploadField } from './file-upload-field';
|
||||
import { switchField } from './switch-field';
|
||||
|
@ -83,4 +84,8 @@ export const componentsModule = angular
|
|||
.component(
|
||||
'datatableSearchbar',
|
||||
r2a(SearchBar, ['data-cy', 'onChange', 'value', 'placeholder'])
|
||||
)
|
||||
.component(
|
||||
'boxSelectorBadgeIcon',
|
||||
react2angular(BadgeIcon, ['featherIcon', 'icon'])
|
||||
).name;
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { Edit } from 'react-feather';
|
||||
|
||||
import { FeatureId } from '@/portainer/feature-flags/enums';
|
||||
import Openldap from '@/assets/ico/vendor/openldap.svg?c';
|
||||
import Custom from '@/assets/ico/custom.svg?c';
|
||||
|
||||
import { BadgeIcon } from '@@/BoxSelector/BadgeIcon';
|
||||
|
||||
const SERVER_TYPES = {
|
||||
CUSTOM: 0,
|
||||
|
@ -11,7 +14,7 @@ const SERVER_TYPES = {
|
|||
export const options = [
|
||||
{
|
||||
id: 'ldap_custom',
|
||||
icon: Custom,
|
||||
icon: <BadgeIcon icon={Edit} />,
|
||||
label: 'Custom',
|
||||
value: SERVER_TYPES.CUSTOM,
|
||||
},
|
||||
|
|
|
@ -15,38 +15,39 @@
|
|||
<!-- build-method -->
|
||||
<div ng-if="!$ctrl.state.fromStack">
|
||||
<div class="col-sm-12 form-section-title"> Build method </div>
|
||||
<div class="form-group"></div>
|
||||
<div class="form-group mb-0">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="method_editor" ng-model="$ctrl.state.Method" value="editor" ng-change="$ctrl.onChangeMethod()" />
|
||||
<label for="method_editor">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Web editor
|
||||
</div>
|
||||
<p>Use our Web editor</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_upload" ng-model="$ctrl.state.Method" value="upload" ng-change="$ctrl.onChangeMethod()" />
|
||||
<label for="method_upload">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'upload'" feather="true"></pr-icon>
|
||||
Upload
|
||||
</div>
|
||||
<p>Upload from your computer</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_repository" ng-model="$ctrl.state.Method" value="repository" ng-change="$ctrl.onChangeMethod()" />
|
||||
<label for="method_repository">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'git-pull-request'" feather="true"></pr-icon>
|
||||
Repository
|
||||
</div>
|
||||
<p>Use a git repository</p>
|
||||
</label>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="method_editor" ng-model="$ctrl.state.Method" value="editor" ng-change="$ctrl.onChangeMethod()" />
|
||||
<label for="method_editor">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Web editor
|
||||
</div>
|
||||
<p>Use our Web editor</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_upload" ng-model="$ctrl.state.Method" value="upload" ng-change="$ctrl.onChangeMethod()" />
|
||||
<label for="method_upload">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'upload'" feather="true"></pr-icon>
|
||||
Upload
|
||||
</div>
|
||||
<p>Upload from your computer</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_repository" ng-model="$ctrl.state.Method" value="repository" ng-change="$ctrl.onChangeMethod()" />
|
||||
<label for="method_repository">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'git-pull-request'" feather="true"></pr-icon>
|
||||
Repository
|
||||
</div>
|
||||
<p>Use a git repository</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -16,18 +16,19 @@
|
|||
<!-- !name-input -->
|
||||
<!-- build-method -->
|
||||
<div class="col-sm-12 form-section-title"> Profile configuration </div>
|
||||
<div class="form-group"></div>
|
||||
<div class="form-group" style="margin-bottom: 0">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="method_editor" ng-model="state.method" value="editor" />
|
||||
<label for="method_editor">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Web editor
|
||||
</div>
|
||||
<p>Use our Web editor</p>
|
||||
</label>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="method_editor" ng-model="state.method" value="editor" />
|
||||
<label for="method_editor">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Web editor
|
||||
</div>
|
||||
<p>Use our Web editor</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -17,17 +17,19 @@
|
|||
<!-- build-method -->
|
||||
<div class="col-sm-12 form-section-title"> Profile configuration </div>
|
||||
<div class="form-group"></div>
|
||||
<div class="form-group" style="margin-bottom: 0">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="method_editor" ng-model="state.method" value="editor" />
|
||||
<label for="method_editor">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Web editor
|
||||
</div>
|
||||
<p>Use our Web editor</p>
|
||||
</label>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="method_editor" ng-model="state.method" value="editor" />
|
||||
<label for="method_editor">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Web editor
|
||||
</div>
|
||||
<p>Use our Web editor</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -138,29 +138,33 @@
|
|||
</div>
|
||||
</div>
|
||||
<!-- !note -->
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="restore_file" checked="checked" />
|
||||
<label for="restore_file" data-cy="init-selectLocalFile">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'upload'" feather="true"></pr-icon>
|
||||
Upload backup file
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="restore_file" checked="checked" />
|
||||
<label for="restore_file" data-cy="init-selectLocalFile">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'upload'" feather="true"></pr-icon>
|
||||
Upload backup file
|
||||
</div>
|
||||
<p></p>
|
||||
</label>
|
||||
</div>
|
||||
<p></p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="restore_s3" disabled />
|
||||
<label for="restore_s3" class="boxselector_disabled">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'download'" feather="true"></pr-icon>
|
||||
Retrieve from S3
|
||||
<div>
|
||||
<input type="radio" id="restore_s3" disabled />
|
||||
<label for="restore_s3" class="boxselector_disabled">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'download'" feather="true"></pr-icon>
|
||||
Retrieve from S3
|
||||
</div>
|
||||
<p
|
||||
>This feature is available in
|
||||
<a class="hyperlink" href="https://www.portainer.io/business-upsell?from=restore-s3-form" target="_blank"> Portainer Business Edition</a></p
|
||||
>
|
||||
</label>
|
||||
</div>
|
||||
<p
|
||||
>This feature is available in
|
||||
<a class="hyperlink" href="https://www.portainer.io/business-upsell?from=restore-s3-form" target="_blank"> Portainer Business Edition</a></p
|
||||
>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- note -->
|
||||
|
|
|
@ -21,17 +21,19 @@
|
|||
</div>
|
||||
<!-- !note -->
|
||||
<!-- environment-type -->
|
||||
<div class="form-group" style="margin-bottom: 0">
|
||||
<div class="boxselector_wrapper">
|
||||
<div ng-repeat="type in ctrl.endpointSections">
|
||||
<input type="radio" id="{{ type.Id }}" ng-model="ctrl.formValues.ConnectionType" ng-value="type.Value" />
|
||||
<label for="{{ type.Id }}">
|
||||
<div class="boxselector_header">
|
||||
<i ng-class="type.Classes" aria-hidden="true" style="margin-right: 2px"></i>
|
||||
{{ type.Title }}
|
||||
</div>
|
||||
<p>{{ type.Description }}</p>
|
||||
</label>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div ng-repeat="type in ctrl.endpointSections">
|
||||
<input type="radio" id="{{ type.Id }}" ng-model="ctrl.formValues.ConnectionType" ng-value="type.Value" />
|
||||
<label for="{{ type.Id }}">
|
||||
<div class="boxselector_header">
|
||||
<i ng-class="type.Classes" aria-hidden="true" style="margin-right: 2px"></i>
|
||||
{{ type.Title }}
|
||||
</div>
|
||||
<p>{{ type.Description }}</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,11 +7,7 @@
|
|||
<form class="form-horizontal">
|
||||
<div class="col-sm-12 form-section-title"> Registry provider </div>
|
||||
|
||||
<div class="form-group"></div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 0">
|
||||
<box-selector radio-name="'registry'" value="$ctrl.state.registryValue" options="$ctrl.state.availableRegistry" on-change="($ctrl.setRegistry)"></box-selector>
|
||||
</div>
|
||||
<box-selector radio-name="'availableRegistry'" value="$ctrl.state.registryValue" options="$ctrl.state.availableRegistry" on-change="($ctrl.setRegistry)"></box-selector>
|
||||
|
||||
<registry-form-quay
|
||||
ng-if="$ctrl.model.Type === $ctrl.RegistryTypes.QUAY"
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import { Edit } from 'react-feather';
|
||||
|
||||
import Docker from '@/assets/ico/vendor/docker.svg?c';
|
||||
import Ecr from '@/assets/ico/vendor/ecr.svg?c';
|
||||
import Quay from '@/assets/ico/vendor/quay.svg?c';
|
||||
import Proget from '@/assets/ico/vendor/proget.svg?c';
|
||||
import Azure from '@/assets/ico/vendor/azure.svg?c';
|
||||
import Gitlab from '@/assets/ico/vendor/gitlab.svg?c';
|
||||
import Custom from '@/assets/ico/custom.svg?c';
|
||||
|
||||
import { BadgeIcon } from '@@/BoxSelector/BadgeIcon';
|
||||
|
||||
export const options = [
|
||||
{
|
||||
|
@ -51,7 +54,7 @@ export const options = [
|
|||
},
|
||||
{
|
||||
id: 'registry_custom',
|
||||
icon: Custom,
|
||||
icon: <BadgeIcon icon={Edit} />,
|
||||
label: 'Custom registry',
|
||||
description: 'Define your own registry',
|
||||
value: '3',
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
import { ArrowDownCircle } from 'react-feather';
|
||||
|
||||
import { FeatureId } from '@/portainer/feature-flags/enums';
|
||||
import Microsoft from '@/assets/ico/vendor/microsoft.svg?c';
|
||||
import Ldap from '@/assets/ico/ldap.svg?c';
|
||||
import Oauth from '@/assets/ico/oauth.svg?c';
|
||||
import OAuth from '@/assets/ico/oauth.svg?c';
|
||||
|
||||
import { BadgeIcon } from '@@/BoxSelector/BadgeIcon';
|
||||
|
||||
export const options = [
|
||||
{
|
||||
id: 'auth_internal',
|
||||
icon: 'svg-internal',
|
||||
icon: <BadgeIcon icon={ArrowDownCircle} />,
|
||||
label: 'Internal',
|
||||
description: 'Internal authentication mechanism',
|
||||
value: 1,
|
||||
|
@ -28,7 +32,7 @@ export const options = [
|
|||
},
|
||||
{
|
||||
id: 'auth_oauth',
|
||||
icon: Oauth,
|
||||
icon: OAuth,
|
||||
label: 'OAuth',
|
||||
description: 'OAuth authentication',
|
||||
value: 3,
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
</div>
|
||||
|
||||
<div class="col-sm-12 form-section-title"> Authentication method </div>
|
||||
|
||||
<box-selector radio-name="'authOptions'" value="authMethod" options="authOptions" on-change="(onChangeAuthMethod)"></box-selector>
|
||||
|
||||
<internal-auth
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
import { DownloadCloud, UploadCloud } from 'react-feather';
|
||||
|
||||
import { FeatureId } from '@/portainer/feature-flags/enums';
|
||||
|
||||
import { BadgeIcon } from '@@/BoxSelector/BadgeIcon';
|
||||
|
||||
export const options = [
|
||||
{
|
||||
id: 'backup_file',
|
||||
icon: 'download',
|
||||
icon: <BadgeIcon icon={DownloadCloud} />,
|
||||
featherIcon: true,
|
||||
label: 'Download backup file',
|
||||
value: 'file',
|
||||
},
|
||||
{
|
||||
id: 'backup_s3',
|
||||
icon: 'upload',
|
||||
icon: <BadgeIcon icon={UploadCloud} />,
|
||||
featherIcon: true,
|
||||
label: 'Store in S3',
|
||||
description: 'Define a cron schedule',
|
||||
|
|
|
@ -209,7 +209,9 @@
|
|||
<rd-widget-body>
|
||||
<form class="form-horizontal" ng-submit="backupPortainer()" name="backupPortainerForm">
|
||||
<div class="col-sm-12 form-section-title"> Backup configuration </div>
|
||||
|
||||
<box-selector options="backupOptions" value="formValues.backupFormType" on-change="(onBackupOptionsChange)" radio-name="'backupOptions'"></box-selector>
|
||||
|
||||
<div ng-if="formValues.backupFormType === BACKUP_FORM_TYPES.S3">
|
||||
<!-- Schedule automatic backups -->
|
||||
<div class="form-group mt-3">
|
||||
|
|
|
@ -49,48 +49,49 @@
|
|||
</div>
|
||||
<!-- build-method -->
|
||||
<div class="col-sm-12 form-section-title"> Build method </div>
|
||||
<div class="form-group"></div>
|
||||
<div class="form-group" style="margin-bottom: 0">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="method_editor" ng-model="state.Method" value="editor" />
|
||||
<label for="method_editor">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Web editor
|
||||
</div>
|
||||
<p>Use our Web editor</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_upload" ng-model="state.Method" value="upload" />
|
||||
<label for="method_upload">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'upload'" feather="true"></pr-icon>
|
||||
Upload
|
||||
</div>
|
||||
<p>Upload from your computer</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_repository" ng-model="state.Method" value="repository" />
|
||||
<label for="method_repository">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'git-pull-request'" feather="true"></pr-icon>
|
||||
Repository
|
||||
</div>
|
||||
<p>Use a git repository</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_template" ng-model="state.Method" value="template" />
|
||||
<label for="method_template">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Custom template
|
||||
</div>
|
||||
<p>Use a custom template</p>
|
||||
</label>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<div class="boxselector_wrapper">
|
||||
<div>
|
||||
<input type="radio" id="method_editor" ng-model="state.Method" value="editor" />
|
||||
<label for="method_editor">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Web editor
|
||||
</div>
|
||||
<p>Use our Web editor</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_upload" ng-model="state.Method" value="upload" />
|
||||
<label for="method_upload">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'upload'" feather="true"></pr-icon>
|
||||
Upload
|
||||
</div>
|
||||
<p>Upload from your computer</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_repository" ng-model="state.Method" value="repository" />
|
||||
<label for="method_repository">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'git-pull-request'" feather="true"></pr-icon>
|
||||
Repository
|
||||
</div>
|
||||
<p>Use a git repository</p>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="method_template" ng-model="state.Method" value="template" />
|
||||
<label for="method_template">
|
||||
<div class="boxselector_header">
|
||||
<pr-icon icon="'edit'" feather="true"></pr-icon>
|
||||
Custom template
|
||||
</div>
|
||||
<p>Use a custom template</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import { Icon, IconProps } from '@@/Icon';
|
||||
|
||||
type Props = IconProps;
|
||||
|
||||
export function BadgeIcon({ icon, featherIcon }: Props) {
|
||||
return (
|
||||
<div
|
||||
className={`badge-icon
|
||||
text-3xl h-14 w-14
|
||||
bg-blue-3 text-blue-8
|
||||
th-dark:bg-gray-9 th-dark:text-blue-3
|
||||
rounded-full
|
||||
inline-flex items-center justify-center
|
||||
`}
|
||||
>
|
||||
<Icon icon={icon} feather={featherIcon} className="feather !flex" />
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -19,20 +19,27 @@ export function BoxSelector<T extends number | string>({
|
|||
onChange,
|
||||
}: Props<T>) {
|
||||
return (
|
||||
<div className={clsx('boxselector_wrapper', styles.root)} role="radiogroup">
|
||||
{options.map((option) =>
|
||||
option.hide ? null : (
|
||||
<BoxSelectorItem
|
||||
key={option.id}
|
||||
radioName={radioName}
|
||||
option={option}
|
||||
onChange={onChange}
|
||||
selectedValue={value}
|
||||
disabled={option.disabled && option.disabled()}
|
||||
tooltip={option.tooltip && option.tooltip()}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
<div className="form-group">
|
||||
<div className="col-sm-12">
|
||||
<div
|
||||
className={clsx('boxselector_wrapper', styles.root)}
|
||||
role="radiogroup"
|
||||
>
|
||||
{options
|
||||
.filter((option) => !option.hide)
|
||||
.map((option) => (
|
||||
<BoxSelectorItem
|
||||
key={option.id}
|
||||
radioName={radioName}
|
||||
option={option}
|
||||
onChange={onChange}
|
||||
selectedValue={value}
|
||||
disabled={option.disabled && option.disabled()}
|
||||
tooltip={option.tooltip && option.tooltip()}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
font-weight: bold;
|
||||
user-select: none;
|
||||
color: var(--text-boxselector-header);
|
||||
padding: 0px 10px;
|
||||
}
|
||||
|
||||
.boxselector_header .fa,
|
||||
|
@ -46,6 +45,8 @@
|
|||
/* not disabled */
|
||||
.boxselector_wrapper input[type='radio']:not(:disabled) ~ label,
|
||||
.box-selector-item input[type='radio']:not(:disabled) ~ label {
|
||||
background-color: var(--bg-boxselector-color);
|
||||
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -70,7 +71,7 @@
|
|||
/* checked */
|
||||
.boxselector_wrapper input[type='radio']:checked + label,
|
||||
.box-selector-item input[type='radio']:checked + label {
|
||||
@apply bg-blue-3 border-blue-6;
|
||||
@apply bg-blue-2 border-blue-6;
|
||||
@apply th-dark:bg-blue-10 th-dark:border-blue-7;
|
||||
|
||||
background-image: url(../../../assets/ico/checked.svg);
|
||||
|
@ -106,7 +107,10 @@
|
|||
.boxselector_icon,
|
||||
.boxselector_icon img {
|
||||
font-size: 90px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.boxselector_icon > svg {
|
||||
margin-left: -5px;
|
||||
}
|
||||
|
||||
.boxselector_header pr-icon {
|
||||
|
@ -117,11 +121,6 @@
|
|||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.boxselector_wrapper input[type='radio']:not(:disabled) ~ label,
|
||||
.box-selector-item input[type='radio']:not(:disabled) ~ label {
|
||||
background-color: var(--bg-boxselector-color);
|
||||
}
|
||||
|
||||
.boxselector_img_container {
|
||||
line-height: 90px;
|
||||
margin-bottom: 0;
|
||||
|
|
|
@ -52,7 +52,7 @@ export function BoxSelectorItem<T extends number | string>({
|
|||
<Icon
|
||||
icon={option.icon}
|
||||
feather={option.featherIcon}
|
||||
className="boxselector_icon space-right"
|
||||
className="boxselector_icon !flex items-center"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import { Icon, IconProps } from '@@/Icon';
|
||||
|
||||
type Props = IconProps;
|
||||
|
||||
export function LogoIcon({ icon, featherIcon }: Props) {
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
text-6xl h-14 w-14
|
||||
inline-flex items-center justify-center
|
||||
`}
|
||||
>
|
||||
<Icon icon={icon} feather={featherIcon} className="feather !flex" />
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
import { Edit, FileText, Globe, Upload } from 'react-feather';
|
||||
|
||||
import GitIcon from '@/assets/ico/git.svg?c';
|
||||
|
||||
import { BadgeIcon } from '../BadgeIcon';
|
||||
import { BoxSelectorOption } from '../types';
|
||||
|
||||
export const editor: BoxSelectorOption<'editor'> = {
|
||||
id: 'method_editor',
|
||||
icon: <BadgeIcon icon={Edit} />,
|
||||
label: 'Web editor',
|
||||
description: 'Use our Web editor',
|
||||
value: 'editor',
|
||||
};
|
||||
export const upload: BoxSelectorOption<'upload'> = {
|
||||
id: 'method_upload',
|
||||
icon: <BadgeIcon icon={Upload} />,
|
||||
label: 'Upload',
|
||||
description: 'Upload from your computer',
|
||||
value: 'upload',
|
||||
};
|
||||
export const git: BoxSelectorOption<'repository'> = {
|
||||
id: 'method_repository',
|
||||
icon: <GitIcon />,
|
||||
label: 'Repository',
|
||||
description: 'Use a git repository',
|
||||
value: 'repository',
|
||||
};
|
||||
|
||||
export const template: BoxSelectorOption<'template'> = {
|
||||
id: 'method_template',
|
||||
icon: <BadgeIcon icon={FileText} />,
|
||||
label: 'Template',
|
||||
description: 'Use an Edge stack template',
|
||||
value: 'template',
|
||||
};
|
||||
|
||||
export const url: BoxSelectorOption<'url'> = {
|
||||
id: 'method_url',
|
||||
icon: <BadgeIcon icon={Globe} />,
|
||||
label: 'URL',
|
||||
description: 'Specify a URL to a file',
|
||||
value: 'url',
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
import Kubernetes from '@/assets/ico/vendor/kubernetes.svg?c';
|
||||
import DockerCompose from '@/assets/ico/vendor/docker-compose.svg?c';
|
||||
|
||||
import { BoxSelectorOption } from '../types';
|
||||
|
||||
export const kubernetes: BoxSelectorOption<'kubernetes'> = {
|
||||
id: 'method_kubernetes',
|
||||
icon: Kubernetes,
|
||||
label: 'Kubernetes',
|
||||
description: 'Kubernetes manifest format',
|
||||
value: 'kubernetes',
|
||||
};
|
||||
|
||||
export const compose: BoxSelectorOption<'compose'> = {
|
||||
id: 'method_compose',
|
||||
icon: DockerCompose,
|
||||
label: 'Compose',
|
||||
description: 'docker-compose format',
|
||||
value: 'compose',
|
||||
};
|
|
@ -67,6 +67,9 @@ export function Icon({ icon, feather, className, mode, size }: Props) {
|
|||
.map((s) => s.slice(0, 1).toUpperCase() + s.slice(1))
|
||||
.join('') as keyof typeof featherIcons;
|
||||
const IconComponent = featherIcons[iconName];
|
||||
if (!IconComponent) {
|
||||
throw new Error(`Feather icon not found: ${iconName}`);
|
||||
}
|
||||
return <IconComponent className={classes} />;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ import azure from '@/assets/ico/vendor/azure.svg?c';
|
|||
import civo from '@/assets/ico/vendor/civo.svg?c';
|
||||
import digitalocean from '@/assets/ico/vendor/digitalocean.svg?c';
|
||||
import docker from '@/assets/ico/vendor/docker.svg?c';
|
||||
import dockercompose from '@/assets/ico/vendor/dockercompose.svg?c';
|
||||
import dockercompose from '@/assets/ico/vendor/docker-compose.svg?c';
|
||||
import ecr from '@/assets/ico/vendor/ecr.svg?c';
|
||||
import github from '@/assets/ico/vendor/github.svg?c';
|
||||
import gitlab from '@/assets/ico/vendor/gitlab.svg?c';
|
||||
|
|
|
@ -60,16 +60,12 @@ export function WizardDocker({ onCreate }: Props) {
|
|||
|
||||
return (
|
||||
<div className="form-horizontal">
|
||||
<div className="form-group">
|
||||
<div className="col-sm-12">
|
||||
<BoxSelector
|
||||
onChange={(v) => setCreationType(v)}
|
||||
options={options}
|
||||
value={creationType}
|
||||
radioName="creation-type"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<BoxSelector
|
||||
onChange={(v) => setCreationType(v)}
|
||||
options={options}
|
||||
value={creationType}
|
||||
radioName="creation-type"
|
||||
/>
|
||||
|
||||
{tab}
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue