portainer/app/portainer/services/modal.service/prompt.ts

236 lines
5.4 KiB
TypeScript

import sanitize from 'sanitize-html';
import bootbox from 'bootbox';
import {
applyBoxCSS,
ButtonsOptions,
confirmButtons,
buildTitle,
ModalTypeIcon,
} from './utils';
type PromptCallback = ((value: string) => void) | ((value: string[]) => void);
interface InputOption {
text: string;
value: string;
}
interface PromptOptions {
title: string;
message?: string;
inputType?:
| 'text'
| 'textarea'
| 'email'
| 'select'
| 'checkbox'
| 'date'
| 'time'
| 'number'
| 'password'
| 'radio'
| 'range';
inputOptions: InputOption[];
buttons: ButtonsOptions;
value?: string;
callback: PromptCallback;
}
export async function promptAsync(options: Omit<PromptOptions, 'callback'>) {
return new Promise((resolve) => {
prompt({
...options,
callback: (result: string | string[]) => resolve(result),
});
});
}
// the ts-ignore is required because the bootbox typings are not up to date
// remove the ts-ignore when the typings are updated in
export function prompt(options: PromptOptions) {
const box = bootbox.prompt({
title: options.title,
message: options.message || '',
inputType: options.inputType,
inputOptions: options.inputOptions,
buttons: options.buttons ? confirmButtons(options.buttons) : undefined,
// casting is done because ts definition expects string=>any, but library code can emit different values, based on inputType
callback: options.callback as (value: string) => void,
value: options.value,
});
applyBoxCSS(box);
return box;
}
export function confirmContainerDeletion(
title: string,
callback: PromptCallback
) {
prompt({
title: buildTitle(title, ModalTypeIcon.Destructive),
inputType: 'checkbox',
inputOptions: [
{
text: 'Automatically remove non-persistent volumes<i></i>',
value: '1',
},
],
buttons: {
confirm: {
label: 'Remove',
className: 'btn-danger',
},
},
callback,
});
}
export function confirmUpdateAppIngress(
title: string,
message: string,
inputText: string,
callback: PromptCallback
) {
prompt({
title: buildTitle(title),
inputType: 'checkbox',
message,
inputOptions: [
{
text: `${inputText}<i></i>`,
value: '1',
},
],
buttons: {
confirm: {
label: 'Update',
className: 'btn-primary',
},
},
callback,
});
}
export function selectRegistry(options: PromptOptions) {
prompt(options);
}
export function confirmContainerRecreation(
cannotPullImage: boolean | null,
callback: PromptCallback
) {
const box = prompt({
title: buildTitle('Are you sure?', ModalTypeIcon.Destructive),
inputType: 'checkbox',
inputOptions: [
{
text: 'Re-pull image<i></i>',
value: '1',
},
],
buttons: {
confirm: {
label: 'Recreate',
className: 'btn-danger',
},
},
callback,
});
const message = `You're about to recreate this container and any non-persisted data will be lost. This container will be removed and another one will be created using the same configuration.`;
box.find('.bootbox-body').prepend(`<p>${message}</p>`);
const label = box.find('.form-check-label');
label.css('padding-left', '5px');
label.css('padding-right', '25px');
if (cannotPullImage) {
label.css('cursor', 'not-allowed');
label.find('i').css('cursor', 'not-allowed');
const checkbox = box.find('.bootbox-input-checkbox');
checkbox.prop('disabled', true);
const formCheck = box.find('.form-check');
formCheck.prop('style', 'height: 45px;');
const cannotPullImageMessage = `<pr-icon icon="'alert-triangle'" mode="'warning'"/>
<div class="inline-text text-warning">
<span>Cannot re-pull as the image is inaccessible - either it no longer exists or the tag or name is no longer correct.
</span>
</div>`;
formCheck.append(`${cannotPullImageMessage}`);
}
}
export function confirmServiceForceUpdate(
message: string,
callback: PromptCallback
) {
const sanitizedMessage = sanitize(message);
const box = prompt({
title: buildTitle('Are you sure?'),
inputType: 'checkbox',
inputOptions: [
{
text: 'Re-pull image<i></i>',
value: '1',
},
],
buttons: {
confirm: {
label: 'Update',
className: 'btn-primary',
},
},
callback,
});
customizeCheckboxPrompt(box, sanitizedMessage);
}
export function confirmStackUpdate(
message: string,
defaultToggle: boolean,
confirmButtonClass: string | undefined,
callback: PromptCallback
) {
const sanitizedMessage = sanitize(message);
const box = prompt({
title: buildTitle('Are you sure?'),
inputType: 'checkbox',
inputOptions: [
{
text: 'Re-pull image and redeploy<i></i>',
value: '1',
},
],
buttons: {
confirm: {
label: 'Update',
className: 'btn-primary',
},
},
callback,
});
customizeCheckboxPrompt(box, sanitizedMessage, defaultToggle);
}
function customizeCheckboxPrompt(
box: JQuery<HTMLElement>,
message: string,
toggleCheckbox = false,
showCheck = false
) {
box.find('.bootbox-body').prepend(`<p>${message}</p>`);
const checkbox = box.find('.bootbox-input-checkbox');
checkbox.prop('checked', toggleCheckbox);
if (showCheck) {
checkbox.addClass('visible');
}
}