mirror of https://github.com/portainer/portainer
feat(ui): allow-different-modal-icons EE-3751 (#7299)
* feat(ui): update modal icons EE-3751pull/7374/head
parent
bb066cd58c
commit
d574a71cb1
|
@ -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 {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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?',
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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?',
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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.',
|
||||
|
|
|
@ -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: {
|
||||
|
|
Loading…
Reference in New Issue