feat(ui): ui improvements create template EE-3628 (#7352)

pull/7332/head
Prabhat Khera 2022-08-02 14:10:39 +12:00 committed by GitHub
parent 75c1b485ab
commit e1c7079c81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 75 additions and 70 deletions

View File

@ -9,8 +9,8 @@ class KubeCreateCustomTemplateViewController {
Object.assign(this, { $async, $state, Authentication, CustomTemplateService, FormValidator, ModalService, Notifications, ResourceControlService }); Object.assign(this, { $async, $state, Authentication, CustomTemplateService, FormValidator, ModalService, Notifications, ResourceControlService });
this.methodOptions = [ this.methodOptions = [
buildOption('method_editor', 'fa fa-edit', 'Web editor', 'Use our Web editor', 'editor'), buildOption('method_editor', 'svg-custom', 'Web editor', 'Use our Web editor', 'editor'),
buildOption('method_upload', 'fa fa-upload', 'Upload', 'Upload from your computer', 'upload'), buildOption('method_upload', 'svg-upload', 'Upload', 'Upload from your computer', 'upload'),
]; ];
this.templates = null; this.templates = null;
@ -97,7 +97,12 @@ class KubeCreateCustomTemplateViewController {
this.state.actionInProgress = true; this.state.actionInProgress = true;
try { try {
const customTemplate = await this.createCustomTemplateByMethod(method, this.formValues); const formValues = { ...this.formValues, Variables: null };
if (this.formValues.Variables.length > 0) {
formValues.Variables = JSON.stringify(this.formValues.Variables);
}
const customTemplate = await this.createCustomTemplateByMethod(method, formValues);
const accessControlData = this.formValues.AccessControlData; const accessControlData = this.formValues.AccessControlData;
const userDetails = this.Authentication.getUserDetails(); const userDetails = this.Authentication.getUserDetails();

View File

@ -11,23 +11,25 @@
<div class="col-sm-12 form-section-title"> Build method </div> <div class="col-sm-12 form-section-title"> Build method </div>
<box-selector radio-name="'method'" value="$ctrl.state.method" options="$ctrl.methodOptions" on-change="($ctrl.onChangeMethod)"></box-selector> <box-selector radio-name="'method'" value="$ctrl.state.method" options="$ctrl.methodOptions" on-change="($ctrl.onChangeMethod)"></box-selector>
<web-editor-form <div class="mt-4">
ng-if="$ctrl.state.method === 'editor'" <web-editor-form
identifier="template-creation-editor" ng-if="$ctrl.state.method === 'editor'"
value="$ctrl.formValues.FileContent" identifier="template-creation-editor"
on-change="($ctrl.onChangeFileContent)" value="$ctrl.formValues.FileContent"
ng-required="true" on-change="($ctrl.onChangeFileContent)"
yml="true" ng-required="true"
placeholder="# Define or paste the content of your manifest file here" yml="true"
> placeholder="# Define or paste the content of your manifest file here"
<editor-description> >
<div>Templates allow deploying any kind of Kubernetes resource (Deployment, Secret, ConfigMap...)</div> <editor-description>
<div> <p>Templates allow deploying any kind of Kubernetes resource (Deployment, Secret, ConfigMap...)</p>
You can get more information about Kubernetes file format in the <p>
<a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/" target="_blank">official documentation</a>. You can get more information about Kubernetes file format in the
</div> <a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/" target="_blank">official documentation</a>.
</editor-description> </p>
</web-editor-form> </editor-description>
</web-editor-form>
</div>
<file-upload-form ng-if="$ctrl.state.method === 'upload'" file="$ctrl.formValues.File" on-change="($ctrl.onChangeFile)" ng-required="true"> <file-upload-form ng-if="$ctrl.state.method === 'upload'" file="$ctrl.formValues.File" on-change="($ctrl.onChangeFile)" ng-required="true">
<file-upload-description> You can upload a Manifest file from your computer. </file-upload-description> <file-upload-description> You can upload a Manifest file from your computer. </file-upload-description>
@ -48,7 +50,7 @@
<div class="col-sm-12"> <div class="col-sm-12">
<button <button
type="button" type="button"
class="btn btn-primary btn-sm" class="btn btn-primary btn-sm !ml-0"
ng-disabled="!$ctrl.state.isTemplateValid ||$ctrl.state.actionInProgress || $ctrl.form.$invalid || ($ctrl.state.method === 'editor' && !$ctrl.formValues.FileContent)" ng-disabled="!$ctrl.state.isTemplateValid ||$ctrl.state.actionInProgress || $ctrl.form.$invalid || ($ctrl.state.method === 'editor' && !$ctrl.formValues.FileContent)"
ng-click="$ctrl.createCustomTemplate()" ng-click="$ctrl.createCustomTemplate()"
button-spinner="$ctrl.state.actionInProgress" button-spinner="$ctrl.state.actionInProgress"

View File

@ -66,11 +66,11 @@
<!-- restricted-access --> <!-- restricted-access -->
<!-- authorized-teams --> <!-- authorized-teams -->
<div <div
class="form-group" class="form-group mt-4"
ng-if="$ctrl.formData.AccessControlEnabled && $ctrl.formData.Ownership === $ctrl.RCO.RESTRICTED && ($ctrl.isAdmin || (!$ctrl.isAdmin && $ctrl.availableTeams.length > 1))" ng-if="$ctrl.formData.AccessControlEnabled && $ctrl.formData.Ownership === $ctrl.RCO.RESTRICTED && ($ctrl.isAdmin || (!$ctrl.isAdmin && $ctrl.availableTeams.length > 1))"
> >
<div class="col-sm-12"> <div class="col-sm-12">
<label for="group-access" class="control-label text-left"> <label for="group-access" class="control-label text-left col-sm-3 col-sm-2 !p-0">
Authorized teams Authorized teams
<portainer-tooltip <portainer-tooltip
ng-if="$ctrl.isAdmin && $ctrl.availableTeams.length > 0" ng-if="$ctrl.isAdmin && $ctrl.availableTeams.length > 0"
@ -105,7 +105,7 @@
<!-- authorized-users --> <!-- authorized-users -->
<div class="form-group" ng-if="$ctrl.formData.AccessControlEnabled && $ctrl.formData.Ownership === $ctrl.RCO.RESTRICTED && $ctrl.isAdmin"> <div class="form-group" ng-if="$ctrl.formData.AccessControlEnabled && $ctrl.formData.Ownership === $ctrl.RCO.RESTRICTED && $ctrl.isAdmin">
<div class="col-sm-12"> <div class="col-sm-12">
<label for="group-access" class="control-label text-left"> <label for="group-access" class="control-label text-left col-sm-3 col-sm-2 !p-0">
Authorized users Authorized users
<portainer-tooltip <portainer-tooltip
ng-if="$ctrl.isAdmin && $ctrl.availableUsers.length > 0" ng-if="$ctrl.isAdmin && $ctrl.availableUsers.length > 0"

View File

@ -1,8 +1,8 @@
<ng-form name="commonCustomTemplateForm"> <ng-form name="commonCustomTemplateForm">
<!-- title-input --> <!-- title-input -->
<div class="form-group"> <div class="form-group mb-0">
<label for="template_title" class="col-sm-3 col-lg-2 control-label text-left"> Title </label> <label for="template_title" class="col-sm-3 col-lg-2 control-label text-left"> Title </label>
<div class="col-sm-9 col-lg-10"> <div class="col-sm-8">
<input <input
type="text" type="text"
class="form-control" class="form-control"
@ -14,39 +14,37 @@
auto-focus auto-focus
required required
/> />
</div> <span class="help-block">
</div> <div ng-show="commonCustomTemplateForm.template_title.$invalid">
<div class="form-group" ng-show="commonCustomTemplateForm.template_title.$invalid"> <div class="mt-2 small text-muted">
<div class="col-sm-12 small text-warning"> <div ng-messages="commonCustomTemplateForm.template_title.$error">
<div ng-messages="commonCustomTemplateForm.template_title.$error"> <p class="vertical-center" ng-message="required"> <pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> Title is required. </p>
<p ng-message="pattern"> <p class="vertical-center" ng-message="pattern">
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> <pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
<span>This field must consist of lower case alphanumeric characters, '_' or '-' (e.g. 'my-name', or 'abc-123').</span> This field must consist of lower case alphanumeric characters, '_' or '-' (e.g. 'my-name', or 'abc-123').
</p> </p>
</div> </div>
</div> </div>
</div> </div>
<div class="form-group" ng-show="commonCustomTemplateForm.template_title.$invalid"> </span>
<div class="col-sm-12 small text-warning">
<div ng-messages="commonCustomTemplateForm.template_title.$error">
<p ng-message="required"> <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Title is required.</p>
</div>
</div> </div>
</div> </div>
<!-- !title-input --> <!-- !title-input -->
<!-- description-input --> <!-- description-input -->
<div class="form-group"> <div class="form-group mb-0">
<label for="description" class="col-sm-3 col-lg-2 control-label text-left">Description</label> <label for="description" class="col-sm-3 col-lg-2 control-label text-left">Description</label>
<div class="col-sm-9 col-lg-10"> <div class="col-sm-8">
<input type="text" class="form-control" id="description" ng-model="$ctrl.formValues.Description" name="description" required /> <input type="text" class="form-control" id="description" ng-model="$ctrl.formValues.Description" name="description" required />
</div> <span class="help-block">
</div> <div class="mt-2 small text-muted">
<div class="form-group" ng-show="commonCustomTemplateForm.description.$invalid"> <div ng-show="commonCustomTemplateForm.description.$invalid">
<div class="col-sm-12 small text-warning"> <div ng-messages="commonCustomTemplateForm.description.$error">
<div ng-messages="commonCustomTemplateForm.description.$error"> <p class="vertical-center" ng-message="required"> <pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> Description is required.</p>
<p ng-message="required"> <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Description is required.</p> </div>
</div> </div>
</div>
</span>
</div> </div>
</div> </div>
<!-- !description-input --> <!-- !description-input -->
@ -54,7 +52,7 @@
<!-- note-input --> <!-- note-input -->
<div class="form-group"> <div class="form-group">
<label for="note" class="col-sm-3 col-lg-2 control-label text-left">Note</label> <label for="note" class="col-sm-3 col-lg-2 control-label text-left">Note</label>
<div class="col-sm-9 col-lg-10"> <div class="col-sm-8">
<input type="text" class="form-control" id="note" ng-model="$ctrl.formValues.Note" /> <input type="text" class="form-control" id="note" ng-model="$ctrl.formValues.Note" />
</div> </div>
</div> </div>
@ -63,7 +61,7 @@
<!-- icon-url-input --> <!-- icon-url-input -->
<div class="form-group"> <div class="form-group">
<label for="icon-url" class="col-sm-3 col-lg-2 control-label text-left">Icon URL</label> <label for="icon-url" class="col-sm-3 col-lg-2 control-label text-left">Icon URL</label>
<div class="col-sm-9 col-lg-10"> <div class="col-sm-8">
<input type="text" class="form-control" id="icon-url" ng-model="$ctrl.formValues.Logo" /> <input type="text" class="form-control" id="icon-url" ng-model="$ctrl.formValues.Logo" />
</div> </div>
</div> </div>
@ -72,7 +70,7 @@
<!-- platform-input --> <!-- platform-input -->
<div ng-if="$ctrl.showPlatformField" class="form-group"> <div ng-if="$ctrl.showPlatformField" class="form-group">
<label for="platform" class="col-sm-3 col-lg-2 control-label text-left">Platform</label> <label for="platform" class="col-sm-3 col-lg-2 control-label text-left">Platform</label>
<div class="col-sm-9 col-lg-10"> <div class="col-sm-8">
<select class="form-control" ng-model="$ctrl.formValues.Platform" ng-options="+(opt.value) as opt.label for opt in $ctrl.platformTypes"> </select> <select class="form-control" ng-model="$ctrl.formValues.Platform" ng-options="+(opt.value) as opt.label for opt in $ctrl.platformTypes"> </select>
</div> </div>
</div> </div>
@ -81,7 +79,7 @@
<!-- platform-input --> <!-- platform-input -->
<div ng-if="$ctrl.showTypeField" class="form-group"> <div ng-if="$ctrl.showTypeField" class="form-group">
<label for="platform" class="col-sm-3 col-lg-2 control-label text-left">Type</label> <label for="platform" class="col-sm-3 col-lg-2 control-label text-left">Type</label>
<div class="col-sm-9 col-lg-10"> <div class="col-sm-8">
<select class="form-control" ng-model="$ctrl.formValues.Type" ng-options="+(opt.value) as opt.label for opt in $ctrl.templateTypes"> </select> <select class="form-control" ng-model="$ctrl.formValues.Type" ng-options="+(opt.value) as opt.label for opt in $ctrl.templateTypes"> </select>
</div> </div>
</div> </div>

View File

@ -118,7 +118,7 @@
<div class="col-sm-12"> <div class="col-sm-12">
<button <button
type="button" type="button"
class="btn btn-primary btn-sm" class="btn btn-primary btn-sm !ml-0"
ng-disabled="$ctrl.state.actionInProgress || customTemplateForm.$invalid ng-disabled="$ctrl.state.actionInProgress || customTemplateForm.$invalid
|| ($ctrl.state.Method === 'editor' && !$ctrl.formValues.FileContent) || ($ctrl.state.Method === 'editor' && !$ctrl.formValues.FileContent)
|| ($ctrl.state.Method === 'upload' && !$ctrl.formValues.File) || ($ctrl.state.Method === 'upload' && !$ctrl.formValues.File)

View File

@ -18,6 +18,7 @@ export function AddButton({ label, onClick, className, disabled }: Props) {
className, className,
'label', 'label',
'label-default', 'label-default',
'vertical-center',
'interactive', 'interactive',
'vertical-center', 'vertical-center',
styles.addButton styles.addButton

View File

@ -1,6 +1,7 @@
import { ChangeEvent, createRef } from 'react'; import { ChangeEvent, createRef } from 'react';
import { Button } from '@@/buttons'; import { Button } from '@@/buttons';
import { Icon } from '@@/Icon';
import styles from './FileUploadField.module.css'; import styles from './FileUploadField.module.css';
@ -24,7 +25,7 @@ export function FileUploadField({
const fileRef = createRef<HTMLInputElement>(); const fileRef = createRef<HTMLInputElement>();
return ( return (
<div className="file-upload-field"> <div className="file-upload-field vertical-center">
<input <input
id={inputId} id={inputId}
ref={fileRef} ref={fileRef}
@ -44,12 +45,8 @@ export function FileUploadField({
{title} {title}
</Button> </Button>
<span className="space-left"> <span className="vertical-center">
{value ? ( {value ? value.name : <Icon icon="x" feather mode="danger" />}
value.name
) : (
<i className="fa fa-times red-icon" aria-hidden="true" />
)}
</span> </span>
</div> </div>
); );

View File

@ -94,7 +94,7 @@ export function InputList<T = DefaultType>({
</div> </div>
{textTip && ( {textTip && (
<div className="col-sm-12 my-5"> <div className="col-sm-12 mt-5">
<TextTip color="blue">{textTip}</TextTip> <TextTip color="blue">{textTip}</TextTip>
</div> </div>
)} )}
@ -131,6 +131,7 @@ export function InputList<T = DefaultType>({
size="small" size="small"
disabled={disabled || index === 0} disabled={disabled || index === 0}
onClick={() => handleMoveUp(index)} onClick={() => handleMoveUp(index)}
className="vertical-center btn-only-icon"
> >
<Icon icon="arrow-up" feather /> <Icon icon="arrow-up" feather />
</Button> </Button>
@ -139,6 +140,7 @@ export function InputList<T = DefaultType>({
type="button" type="button"
disabled={disabled || index === value.length - 1} disabled={disabled || index === value.length - 1}
onClick={() => handleMoveDown(index)} onClick={() => handleMoveDown(index)}
className="vertical-center btn-only-icon"
> >
<Icon icon="arrow-down" feather /> <Icon icon="arrow-down" feather />
</Button> </Button>
@ -146,12 +148,12 @@ export function InputList<T = DefaultType>({
)} )}
{!readOnly && ( {!readOnly && (
<Button <Button
color="danger" color="dangerlight"
size="medium" size="small"
onClick={() => handleRemoveItem(key, item)} onClick={() => handleRemoveItem(key, item)}
disabled={disabled} className="vertical-center btn-only-icon"
> >
<Icon icon="trash-2" feather /> <Icon icon="trash-2" feather size="md" />
</Button> </Button>
)} )}
</div> </div>

View File

@ -27,7 +27,7 @@ export function CustomTemplatesVariablesDefinitionField({
}: Props) { }: Props) {
return ( return (
<InputList <InputList
label="Variables Definition" label="Variables definition"
onChange={onChange} onChange={onChange}
value={value} value={value}
renderItem={(item, onChange, error) => ( renderItem={(item, onChange, error) => (