mirror of
https://github.com/portainer/portainer.git
synced 2025-08-04 21:35:23 +02:00
feat(edge/templates): introduce custom templates [EE-6208] (#10561)
This commit is contained in:
parent
a0f583a17d
commit
68950fbb24
81 changed files with 2047 additions and 334 deletions
|
@ -23,7 +23,7 @@ export function BlocklistItem<T extends ElementType>({
|
|||
type="button"
|
||||
className={clsx(
|
||||
className,
|
||||
'blocklist-item flex items-stretch overflow-hidden bg-transparent w-full !ml-0 text-left',
|
||||
'blocklist-item flex items-stretch overflow-hidden bg-transparent w-full !ml-0 no-link text-left',
|
||||
{
|
||||
'blocklist-item--selected': isSelected,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { PropsWithChildren } from 'react';
|
||||
import { PropsWithChildren, useEffect, useMemo } from 'react';
|
||||
import { useTransitionHook } from '@uirouter/react';
|
||||
|
||||
import { BROWSER_OS_PLATFORM } from '@/react/constants';
|
||||
|
||||
|
@ -6,6 +7,10 @@ import { CodeEditor } from '@@/CodeEditor';
|
|||
import { Tooltip } from '@@/Tip/Tooltip';
|
||||
|
||||
import { FormSectionTitle } from './form-components/FormSectionTitle';
|
||||
import { FormError } from './form-components/FormError';
|
||||
import { confirm } from './modals/confirm';
|
||||
import { ModalType } from './modals';
|
||||
import { buildConfirmButton } from './modals/utils';
|
||||
|
||||
const otherEditorConfig = {
|
||||
tooltip: (
|
||||
|
@ -91,6 +96,8 @@ export function WebEditorForm({
|
|||
</div>
|
||||
)}
|
||||
|
||||
{error && <FormError>{error}</FormError>}
|
||||
|
||||
<div className="form-group">
|
||||
<div className="col-sm-12 col-lg-12">
|
||||
<CodeEditor
|
||||
|
@ -104,11 +111,59 @@ export function WebEditorForm({
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<div className="col-sm-12 col-lg-12">{error}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function usePreventExit(
|
||||
initialValue: string,
|
||||
value: string,
|
||||
check: boolean
|
||||
) {
|
||||
const isChanged = useMemo(
|
||||
() => cleanText(initialValue) !== cleanText(value),
|
||||
[initialValue, value]
|
||||
);
|
||||
|
||||
const preventExit = check && isChanged;
|
||||
|
||||
// when navigating away from the page with unsaved changes, show a portainer prompt to confirm
|
||||
useTransitionHook('onBefore', {}, async () => {
|
||||
if (!preventExit) {
|
||||
return true;
|
||||
}
|
||||
const confirmed = await confirm({
|
||||
modalType: ModalType.Warn,
|
||||
title: 'Are you sure?',
|
||||
message:
|
||||
'You currently have unsaved changes in the text editor. Are you sure you want to leave?',
|
||||
confirmButton: buildConfirmButton('Yes', 'danger'),
|
||||
});
|
||||
return confirmed;
|
||||
});
|
||||
|
||||
// when reloading or exiting the page with unsaved changes, show a browser prompt to confirm
|
||||
useEffect(() => {
|
||||
function handler(event: BeforeUnloadEvent) {
|
||||
if (!preventExit) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
event.returnValue = '';
|
||||
return '';
|
||||
}
|
||||
|
||||
// if the form is changed, then set the onbeforeunload
|
||||
window.addEventListener('beforeunload', handler);
|
||||
return () => {
|
||||
window.removeEventListener('beforeunload', handler);
|
||||
};
|
||||
}, [preventExit]);
|
||||
}
|
||||
|
||||
function cleanText(value: string) {
|
||||
return value.replace(/(\r\n|\n|\r)/gm, '');
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import { PropsWithChildren } from 'react';
|
||||
|
||||
import { AutomationTestingProps } from '@/types';
|
||||
|
||||
import { LoadingButton } from '@@/buttons';
|
||||
|
||||
interface Props {
|
||||
import { FormSection } from './FormSection';
|
||||
|
||||
interface Props extends AutomationTestingProps {
|
||||
submitLabel: string;
|
||||
loadingText: string;
|
||||
isLoading: boolean;
|
||||
isValid: boolean;
|
||||
'data-cy'?: string;
|
||||
}
|
||||
|
||||
export function FormActions({
|
||||
|
@ -19,20 +22,22 @@ export function FormActions({
|
|||
'data-cy': dataCy,
|
||||
}: PropsWithChildren<Props>) {
|
||||
return (
|
||||
<div className="form-group">
|
||||
<div className="col-sm-12">
|
||||
<LoadingButton
|
||||
className="!ml-0"
|
||||
loadingText={loadingText}
|
||||
isLoading={isLoading}
|
||||
disabled={!isValid}
|
||||
data-cy={dataCy}
|
||||
>
|
||||
{submitLabel}
|
||||
</LoadingButton>
|
||||
<FormSection title="Actions">
|
||||
<div className="form-group">
|
||||
<div className="col-sm-12">
|
||||
<LoadingButton
|
||||
className="!ml-0"
|
||||
loadingText={loadingText}
|
||||
isLoading={isLoading}
|
||||
disabled={!isValid}
|
||||
data-cy={dataCy}
|
||||
>
|
||||
{submitLabel}
|
||||
</LoadingButton>
|
||||
|
||||
{children}
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FormSection>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue