feat(ui): allow-different-modal-icons EE-3751 (#7299)

* feat(ui): update modal icons EE-3751
pull/7374/head
Ali 2022-07-28 17:33:21 +12:00 committed by GitHub
parent bb066cd58c
commit d574a71cb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 113 additions and 39 deletions

View File

@ -247,19 +247,31 @@ input:checked + .slider:before {
}
.modal-content {
padding: 55px 20px 20px 20px;
padding: 20px;
}
.background-error {
padding-top: 55px;
background-image: url(../images/icon-error.svg);
background-repeat: no-repeat;
background-position: top left;
}
.background-warning {
padding-top: 55px;
background-image: url(../images/icon-warning.svg);
background-repeat: no-repeat;
background-position: top 10px left 10px;
background-position: top left;
}
.modal-header {
padding: 10px 0px 10px 0px;
margin-bottom: 10px;
padding: 0px;
border-bottom: none;
}
.modal-header .close {
margin-top: -40px;
margin-top: 0px;
}
.modal-header .modal-title {

View File

@ -983,7 +983,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
function showConfirmationModal() {
var deferred = $q.defer();
ModalService.confirm({
ModalService.confirmDestructive({
title: 'Are you sure ?',
message: 'A container with the same name already exists. Portainer can automatically remove it and re-create one. Do you want to replace it?',
buttons: {

View File

@ -550,7 +550,7 @@ angular.module('portainer.docker').controller('ServiceController', [
}
$scope.rollbackService = function (service) {
ModalService.confirm({
ModalService.confirmWarn({
title: 'Rollback service',
message: 'Are you sure you want to rollback?',
buttons: {

View File

@ -1,7 +1,10 @@
import { useRouter } from '@uirouter/react';
import type { Environment } from '@/portainer/environments/types';
import { confirmAsync } from '@/portainer/services/modal.service/confirm';
import {
confirmAsync,
confirmDestructiveAsync,
} from '@/portainer/services/modal.service/confirm';
import { promptAsync } from '@/portainer/services/modal.service/prompt';
import * as notifications from '@/portainer/services/notifications';
import { activateDevice } from '@/portainer/hostmanagement/open-amt/open-amt.service';
@ -63,7 +66,7 @@ export function EdgeDevicesDatatableActions({
);
async function onDeleteEdgeDeviceClick() {
const confirmed = await confirmAsync({
const confirmed = await confirmDestructiveAsync({
title: 'Are you sure ?',
message:
'This action will remove all configurations associated to your environment(s). Continue?',

View File

@ -1,5 +1,5 @@
import _ from 'lodash-es';
import { confirmAsync } from '@/portainer/services/modal.service/confirm';
import { confirmDestructiveAsync } from '@/portainer/services/modal.service/confirm';
import { EdgeTypes } from '@/portainer/environments/types';
import { getEnvironments } from '@/portainer/environments/environment.service';
@ -50,7 +50,7 @@ export class EdgeGroupFormController {
dissociateEndpoint(endpoint) {
return this.$async(async () => {
const confirmed = await confirmAsync({
const confirmed = await confirmDestructiveAsync({
title: 'Confirm action',
message: 'Removing the environment from this group will remove its corresponding edge stacks',
buttons: {

View File

@ -10,6 +10,7 @@ import { Environment } from '../environments/types';
import { snapshotEndpoints } from '../environments/environment.service';
import { isEdgeEnvironment } from '../environments/utils';
import { confirmAsync } from '../services/modal.service/confirm';
import { buildTitle } from '../services/modal.service/utils';
import { EnvironmentList } from './EnvironmentList';
import { EdgeLoadingSpinner } from './EdgeLoadingSpinner';
@ -76,7 +77,7 @@ export const HomeViewAngular = r2a(HomeView, []);
async function confirmEndpointSnapshot() {
return confirmAsync({
title: 'Are you sure?',
title: buildTitle('Are you sure?'),
message:
'Triggering a manual refresh will poll each environment to retrieve its information, this may take a few moments.',
buttons: {

View File

@ -1,7 +1,13 @@
import sanitize from 'sanitize-html';
import bootbox from 'bootbox';
import { applyBoxCSS, ButtonsOptions, confirmButtons } from './utils';
import {
applyBoxCSS,
ButtonsOptions,
confirmButtons,
buildTitle,
ModalTypeIcon,
} from './utils';
type ConfirmCallback = (confirmed: boolean) => void;
@ -17,7 +23,7 @@ interface ConfirmOptions extends ConfirmAsyncOptions {
export function confirmWebEditorDiscard() {
const options = {
title: 'Are you sure ?',
title: buildTitle('Are you sure?'),
message:
'You currently have unsaved changes in the editor. Are you sure you want to leave?',
buttons: {
@ -39,6 +45,17 @@ export function confirmAsync(options: ConfirmAsyncOptions) {
return new Promise((resolve) => {
confirm({
...options,
title: buildTitle(options.title),
callback: (confirmed) => resolve(confirmed),
});
});
}
export function confirmDestructiveAsync(options: ConfirmAsyncOptions) {
return new Promise((resolve) => {
confirm({
...options,
title: buildTitle(options.title, ModalTypeIcon.Destructive),
callback: (confirmed) => resolve(confirmed),
});
});
@ -55,9 +72,20 @@ export function confirm(options: ConfirmOptions) {
applyBoxCSS(box);
}
export function confirmWarn(options: ConfirmOptions) {
confirm({ ...options, title: buildTitle(options.title, ModalTypeIcon.Warn) });
}
export function confirmDestructive(options: ConfirmOptions) {
confirm({
...options,
title: buildTitle(options.title, ModalTypeIcon.Destructive),
});
}
export function confirmImageForceRemoval(callback: ConfirmCallback) {
confirm({
title: 'Are you sure?',
title: buildTitle('Are you sure?', ModalTypeIcon.Destructive),
message:
'Forcing the removal of the image will remove the image even if it has multiple tags or if it is used by stopped containers.',
buttons: {
@ -72,7 +100,7 @@ export function confirmImageForceRemoval(callback: ConfirmCallback) {
export function cancelRegistryRepositoryAction(callback: ConfirmCallback) {
confirm({
title: 'Are you sure?',
title: buildTitle('Are you sure?', ModalTypeIcon.Destructive),
message:
'WARNING: interrupting this operation before it has finished will result in the loss of all tags. Are you sure you want to do this?',
buttons: {
@ -88,7 +116,7 @@ export function cancelRegistryRepositoryAction(callback: ConfirmCallback) {
export function confirmDeletion(message: string, callback: ConfirmCallback) {
const messageSanitized = sanitize(message);
confirm({
title: 'Are you sure ?',
title: buildTitle('Are you sure?', ModalTypeIcon.Destructive),
message: messageSanitized,
buttons: {
confirm: {
@ -107,7 +135,7 @@ export function confirmWithTitle(
) {
const messageSanitized = sanitize(message);
confirm({
title: sanitize(title),
title: buildTitle(title, ModalTypeIcon.Destructive),
message: messageSanitized,
buttons: {
confirm: {
@ -122,7 +150,7 @@ export function confirmWithTitle(
export function confirmDetachment(message: string, callback: ConfirmCallback) {
const messageSanitized = sanitize(message);
confirm({
title: 'Are you sure ?',
title: buildTitle('Are you sure?'),
message: messageSanitized,
buttons: {
confirm: {
@ -140,7 +168,7 @@ export function confirmDisassociate(callback: ConfirmCallback) {
'<p>Any agent started with the Edge key associated to this environment will be able to re-associate with this environment.</p>' +
'<p>You can re-use the Edge ID and Edge key that you used to deploy the existing Edge agent to associate a new Edge device to this environment.</p>';
confirm({
title: 'About disassociating',
title: buildTitle('About disassociating'),
message: sanitize(message),
buttons: {
confirm: {
@ -156,7 +184,7 @@ export function confirmUpdate(message: string, callback: ConfirmCallback) {
const messageSanitized = sanitize(message);
confirm({
title: 'Are you sure ?',
title: buildTitle('Are you sure?'),
message: messageSanitized,
buttons: {
confirm: {
@ -195,7 +223,7 @@ export function confirmDeletionAsync(message: string) {
export function confirmImageExport(callback: ConfirmCallback) {
confirm({
title: 'Caution',
title: buildTitle('Caution'),
message:
'The export may take several minutes, do not navigate away whilst the export is in progress.',
buttons: {
@ -210,7 +238,7 @@ export function confirmImageExport(callback: ConfirmCallback) {
export function confirmChangePassword() {
return confirmAsync({
title: 'Are you sure?',
title: buildTitle('Are you sure?'),
message:
'You will be logged out after the password change. Do you want to change your password?',
buttons: {

View File

@ -4,6 +4,9 @@ import bootbox from 'bootbox';
import {
cancelRegistryRepositoryAction,
confirmAsync,
confirmWarn,
confirmDestructive,
confirmDestructiveAsync,
confirmDisassociate,
confirmDeletion,
confirmDetachment,
@ -42,6 +45,9 @@ export function ModalServiceAngular() {
enlargeImage,
confirmWebEditorDiscard,
confirmAsync,
confirmWarn,
confirmDestructive,
confirmDestructiveAsync,
confirm,
confirmImageForceRemoval,
cancelRegistryRepositoryAction,

View File

@ -1,8 +1,13 @@
import sanitize from 'sanitize-html';
import bootbox from 'bootbox';
import '@@/BoxSelector/BoxSelectorItem.css';
import { applyBoxCSS, ButtonsOptions, confirmButtons } from './utils';
import {
applyBoxCSS,
ButtonsOptions,
confirmButtons,
buildTitle,
ModalTypeIcon,
} from './utils';
type PromptCallback = ((value: string) => void) | ((value: string[]) => void);
@ -60,10 +65,8 @@ export function confirmContainerDeletion(
title: string,
callback: PromptCallback
) {
const sanitizedTitle = sanitize(title);
prompt({
title: sanitizedTitle,
title: buildTitle(title, ModalTypeIcon.Destructive),
inputType: 'checkbox',
inputOptions: [
{
@ -90,7 +93,7 @@ export function confirmContainerRecreation(
callback: PromptCallback
) {
const box = prompt({
title: 'Are you sure?',
title: buildTitle('Are you sure?', ModalTypeIcon.Destructive),
inputType: 'checkbox',
inputOptions: [
@ -137,7 +140,7 @@ export function confirmServiceForceUpdate(
const sanitizedMessage = sanitize(message);
const box = prompt({
title: 'Are you sure?',
title: buildTitle('Are you sure?'),
inputType: 'checkbox',
inputOptions: [
{
@ -164,8 +167,10 @@ export function confirmStackUpdate(
confirmButtonClassName: string | undefined,
callback: PromptCallback
) {
const sanitizedMessage = sanitize(message);
const box = prompt({
title: 'Are you sure?',
title: buildTitle('Are you sure?'),
inputType: 'checkbox',
inputOptions: [
{
@ -181,7 +186,7 @@ export function confirmStackUpdate(
},
callback,
});
box.find('.bootbox-body').prepend(message);
box.find('.bootbox-body').prepend(sanitizedMessage);
const checkbox = box.find('.bootbox-input-checkbox');
checkbox.prop('checked', defaultToggle);
checkbox.prop('disabled', defaultDisabled);

View File

@ -10,6 +10,11 @@ export interface ButtonsOptions {
cancel?: Button;
}
export enum ModalTypeIcon {
Warn = 'warning',
Destructive = 'error',
}
export function confirmButtons(options: ButtonsOptions) {
return {
confirm: {
@ -27,6 +32,17 @@ export function confirmButtons(options: ButtonsOptions) {
};
}
export function buildTitle(
title: string,
modalType: ModalTypeIcon = ModalTypeIcon.Warn
) {
return `
<div class="background-${modalType}">
<h5 class="modal-title">${sanitize(title)}</h5>
</div>
`;
}
export function applyBoxCSS(box: JQuery<HTMLElement>) {
box.css({
'vertical-align': 'middle',

View File

@ -1,5 +1,5 @@
import { react2angular } from '@/react-tools/react2angular';
import { confirm } from '@/portainer/services/modal.service/confirm';
import { confirmDestructive } from '@/portainer/services/modal.service/confirm';
import { FormSectionTitle } from '@@/form-components/FormSectionTitle';
@ -23,7 +23,7 @@ export function InternalAuth({
}: Props) {
function onSubmit() {
if (value.RequiredPasswordLength < 10) {
confirm({
confirmDestructive({
title: 'Allow weak passwords?',
message:
'You have set an insecure minimum password length. This could leave your system vulnerable to attack, are you sure?',

View File

@ -2,7 +2,10 @@ import { useQueryClient } from 'react-query';
import { useRouter } from '@uirouter/react';
import { Profile } from '@/portainer/hostmanagement/fdo/model';
import { confirmAsync } from '@/portainer/services/modal.service/confirm';
import {
confirmAsync,
confirmDestructiveAsync,
} from '@/portainer/services/modal.service/confirm';
import * as notifications from '@/portainer/services/notifications';
import {
deleteProfile,
@ -86,7 +89,7 @@ export function FDOProfilesDatatableActions({
}
async function onDeleteProfileClick() {
const confirmed = await confirmAsync({
const confirmed = await confirmDestructiveAsync({
title: 'Are you sure ?',
message: 'This action will delete the selected profile(s). Continue?',
buttons: {

View File

@ -5,7 +5,7 @@ import { PortainerEndpointTypes } from '@/portainer/models/endpoint/models';
import { EndpointSecurityFormData } from '@/portainer/components/endpointSecurity/porEndpointSecurityModel';
import EndpointHelper from '@/portainer/helpers/endpointHelper';
import { getAMTInfo } from 'Portainer/hostmanagement/open-amt/open-amt.service';
import { confirmAsync } from '@/portainer/services/modal.service/confirm';
import { confirmDestructiveAsync } from '@/portainer/services/modal.service/confirm';
import { isEdgeEnvironment } from '@/portainer/environments/utils';
import { commandsTabs } from '@/react/edge/components/EdgeScriptForm/scripts';
@ -192,7 +192,7 @@ function EndpointController(
var TLSSkipClientVerify = TLS && (TLSMode === 'tls_ca' || TLSMode === 'tls_only');
if (isEdgeEnvironment(endpoint.Type) && _.difference($scope.initialTagIds, endpoint.TagIds).length > 0) {
let confirmed = await confirmAsync({
let confirmed = await confirmDestructiveAsync({
title: 'Confirm action',
message: 'Removing tags from this environment will remove the corresponding edge stacks when dynamic grouping is being used',
buttons: {

View File

@ -120,7 +120,7 @@ angular.module('portainer.app').controller('StackController', [
$scope.migrateStack = function (name, endpointId) {
return $q(function (resolve) {
ModalService.confirm({
ModalService.confirmWarn({
title: 'Are you sure?',
message:
'This action will deploy a new instance of this stack on the target environment, please note that this does NOT relocate the content of any persistent volumes that may be attached to this stack.',

View File

@ -36,7 +36,7 @@ angular.module('portainer.app').controller('UserController', [
let promise = Promise.resolve(true);
if (username != oldUsername) {
promise = new Promise((resolve) =>
ModalService.confirm({
ModalService.confirmWarn({
title: 'Are you sure?',
message: `Are you sure you want to rename the user ${oldUsername} to ${username}?`,
buttons: {