mirror of https://github.com/portainer/portainer
parent
b40d22dc74
commit
9cef185db9
|
@ -1,8 +1,27 @@
|
||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
export default function CodeEditorController($scope) {
|
export default function CodeEditorController($scope) {
|
||||||
|
this.type = '';
|
||||||
|
|
||||||
this.handleChange = (value) => {
|
this.handleChange = (value) => {
|
||||||
$scope.$evalAsync(() => {
|
$scope.$evalAsync(() => {
|
||||||
this.onChange(value);
|
this.onChange(value);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.$onInit = () => {
|
||||||
|
this.type = getType({ yaml: this.yml, dockerFile: this.dockerFile, shell: this.shell });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getType({ yaml, dockerFile, shell }) {
|
||||||
|
if (yaml) {
|
||||||
|
return 'yaml';
|
||||||
|
}
|
||||||
|
if (dockerFile) {
|
||||||
|
return 'dockerfile';
|
||||||
|
}
|
||||||
|
if (shell) {
|
||||||
|
return 'shell';
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<react-code-editor
|
<react-code-editor
|
||||||
id="$ctrl.identifier"
|
id="$ctrl.identifier"
|
||||||
placeholder="$ctrl.placeholder"
|
placeholder="$ctrl.placeholder"
|
||||||
yaml="$ctrl.yml"
|
type="$ctrl.type"
|
||||||
docker-file="$ctrl.dockerFile"
|
|
||||||
shell="$ctrl.shell"
|
|
||||||
readonly="$ctrl.readOnly"
|
readonly="$ctrl.readOnly"
|
||||||
on-change="($ctrl.handleChange)"
|
on-change="($ctrl.handleChange)"
|
||||||
value="$ctrl.value"
|
value="$ctrl.value"
|
||||||
|
|
|
@ -223,9 +223,7 @@ export const ngModule = angular
|
||||||
r2a(CodeEditor, [
|
r2a(CodeEditor, [
|
||||||
'id',
|
'id',
|
||||||
'placeholder',
|
'placeholder',
|
||||||
'yaml',
|
'type',
|
||||||
'dockerFile',
|
|
||||||
'shell',
|
|
||||||
'readonly',
|
'readonly',
|
||||||
'onChange',
|
'onChange',
|
||||||
'value',
|
'value',
|
||||||
|
|
|
@ -15,12 +15,11 @@ import styles from './CodeEditor.module.css';
|
||||||
import { TextTip } from './Tip/TextTip';
|
import { TextTip } from './Tip/TextTip';
|
||||||
import { StackVersionSelector } from './StackVersionSelector';
|
import { StackVersionSelector } from './StackVersionSelector';
|
||||||
|
|
||||||
|
type Type = 'yaml' | 'shell' | 'dockerfile';
|
||||||
interface Props extends AutomationTestingProps {
|
interface Props extends AutomationTestingProps {
|
||||||
id: string;
|
id: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
yaml?: boolean;
|
type?: Type;
|
||||||
dockerFile?: boolean;
|
|
||||||
shell?: boolean;
|
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
value: string;
|
value: string;
|
||||||
|
@ -62,6 +61,12 @@ const dockerFileLanguage = new LanguageSupport(
|
||||||
);
|
);
|
||||||
const shellLanguage = new LanguageSupport(StreamLanguage.define(shell));
|
const shellLanguage = new LanguageSupport(StreamLanguage.define(shell));
|
||||||
|
|
||||||
|
const docTypeExtensionMap: Record<Type, LanguageSupport> = {
|
||||||
|
yaml: yamlLanguage,
|
||||||
|
dockerfile: dockerFileLanguage,
|
||||||
|
shell: shellLanguage,
|
||||||
|
};
|
||||||
|
|
||||||
export function CodeEditor({
|
export function CodeEditor({
|
||||||
id,
|
id,
|
||||||
onChange,
|
onChange,
|
||||||
|
@ -71,26 +76,18 @@ export function CodeEditor({
|
||||||
versions,
|
versions,
|
||||||
onVersionChange,
|
onVersionChange,
|
||||||
height = '500px',
|
height = '500px',
|
||||||
yaml: isYaml,
|
type,
|
||||||
dockerFile: isDockerFile,
|
|
||||||
shell: isShell,
|
|
||||||
'data-cy': dataCy,
|
'data-cy': dataCy,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [isRollback, setIsRollback] = useState(false);
|
const [isRollback, setIsRollback] = useState(false);
|
||||||
|
|
||||||
const extensions = useMemo(() => {
|
const extensions = useMemo(() => {
|
||||||
const extensions = [];
|
const extensions = [];
|
||||||
if (isYaml) {
|
if (type && docTypeExtensionMap[type]) {
|
||||||
extensions.push(yamlLanguage);
|
extensions.push(docTypeExtensionMap[type]);
|
||||||
}
|
|
||||||
if (isDockerFile) {
|
|
||||||
extensions.push(dockerFileLanguage);
|
|
||||||
}
|
|
||||||
if (isShell) {
|
|
||||||
extensions.push(shellLanguage);
|
|
||||||
}
|
}
|
||||||
return extensions;
|
return extensions;
|
||||||
}, [isYaml, isDockerFile, isShell]);
|
}, [type]);
|
||||||
|
|
||||||
function handleVersionChange(version: number) {
|
function handleVersionChange(version: number) {
|
||||||
if (versions && versions.length > 1) {
|
if (versions && versions.length > 1) {
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
import { PropsWithChildren, useEffect, useMemo } from 'react';
|
|
||||||
import { useTransitionHook } from '@uirouter/react';
|
import { useTransitionHook } from '@uirouter/react';
|
||||||
|
import {
|
||||||
|
ComponentProps,
|
||||||
|
PropsWithChildren,
|
||||||
|
ReactNode,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
} from 'react';
|
||||||
|
|
||||||
import { BROWSER_OS_PLATFORM } from '@/react/constants';
|
import { BROWSER_OS_PLATFORM } from '@/react/constants';
|
||||||
import { AutomationTestingProps } from '@/types';
|
|
||||||
|
|
||||||
import { CodeEditor } from '@@/CodeEditor';
|
import { CodeEditor } from '@@/CodeEditor';
|
||||||
import { Tooltip } from '@@/Tip/Tooltip';
|
import { Tooltip } from '@@/Tip/Tooltip';
|
||||||
|
|
||||||
import { FormSectionTitle } from './form-components/FormSectionTitle';
|
|
||||||
import { FormError } from './form-components/FormError';
|
import { FormError } from './form-components/FormError';
|
||||||
import { confirm } from './modals/confirm';
|
import { FormSectionTitle } from './form-components/FormSectionTitle';
|
||||||
import { ModalType } from './modals';
|
import { ModalType } from './modals';
|
||||||
|
import { confirm } from './modals/confirm';
|
||||||
import { buildConfirmButton } from './modals/utils';
|
import { buildConfirmButton } from './modals/utils';
|
||||||
|
|
||||||
const otherEditorConfig = {
|
const otherEditorConfig = {
|
||||||
|
@ -52,39 +57,21 @@ export const editorConfig = {
|
||||||
win: otherEditorConfig,
|
win: otherEditorConfig,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
interface Props extends AutomationTestingProps {
|
type CodeEditorProps = ComponentProps<typeof CodeEditor>;
|
||||||
value: string;
|
|
||||||
onChange: (value: string) => void;
|
|
||||||
|
|
||||||
id: string;
|
interface Props extends CodeEditorProps {
|
||||||
placeholder?: string;
|
titleContent?: ReactNode;
|
||||||
yaml?: boolean;
|
|
||||||
shell?: boolean;
|
|
||||||
readonly?: boolean;
|
|
||||||
titleContent?: React.ReactNode;
|
|
||||||
hideTitle?: boolean;
|
hideTitle?: boolean;
|
||||||
error?: string;
|
error?: string;
|
||||||
versions?: number[];
|
|
||||||
onVersionChange?: (version: number) => void;
|
|
||||||
height?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function WebEditorForm({
|
export function WebEditorForm({
|
||||||
id,
|
id,
|
||||||
onChange,
|
|
||||||
placeholder,
|
|
||||||
value,
|
|
||||||
titleContent = '',
|
titleContent = '',
|
||||||
hideTitle,
|
hideTitle,
|
||||||
readonly,
|
|
||||||
yaml,
|
|
||||||
shell,
|
|
||||||
children,
|
children,
|
||||||
error,
|
error,
|
||||||
versions,
|
...props
|
||||||
onVersionChange,
|
|
||||||
height,
|
|
||||||
'data-cy': dataCy,
|
|
||||||
}: PropsWithChildren<Props>) {
|
}: PropsWithChildren<Props>) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -107,16 +94,8 @@ export function WebEditorForm({
|
||||||
<div className="col-sm-12 col-lg-12">
|
<div className="col-sm-12 col-lg-12">
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
id={id}
|
id={id}
|
||||||
placeholder={placeholder}
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
readonly={readonly}
|
{...props}
|
||||||
yaml={yaml}
|
|
||||||
shell={shell}
|
|
||||||
value={value}
|
|
||||||
onChange={onChange}
|
|
||||||
versions={versions}
|
|
||||||
onVersionChange={(v) => onVersionChange && onVersionChange(v)}
|
|
||||||
height={height}
|
|
||||||
data-cy={dataCy}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -87,7 +87,7 @@ function InnerForm({ isLoading }: { isLoading: boolean }) {
|
||||||
onChange={(value) => setFieldValue('fileContent', value)}
|
onChange={(value) => setFieldValue('fileContent', value)}
|
||||||
value={values.fileContent}
|
value={values.fileContent}
|
||||||
placeholder="Define or paste the content of your script file here"
|
placeholder="Define or paste the content of your script file here"
|
||||||
shell
|
type="shell"
|
||||||
error={errors.fileContent}
|
error={errors.fileContent}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -83,7 +83,7 @@ function InnerForm({ isLoading }: { isLoading: boolean }) {
|
||||||
onChange={(value) => setFieldValue('fileContent', value)}
|
onChange={(value) => setFieldValue('fileContent', value)}
|
||||||
value={values.fileContent}
|
value={values.fileContent}
|
||||||
placeholder="Define or paste the content of your script file here"
|
placeholder="Define or paste the content of your script file here"
|
||||||
shell
|
type="shell"
|
||||||
error={errors.fileContent}
|
error={errors.fileContent}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ export function DockerContentField({
|
||||||
id="stack-creation-editor"
|
id="stack-creation-editor"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
yaml
|
type="yaml"
|
||||||
placeholder="Define or paste the content of your docker compose file here"
|
placeholder="Define or paste the content of your docker compose file here"
|
||||||
error={error}
|
error={error}
|
||||||
readonly={readonly}
|
readonly={readonly}
|
||||||
|
|
|
@ -72,7 +72,7 @@ export function KubeManifestForm({
|
||||||
id="stack-creation-editor"
|
id="stack-creation-editor"
|
||||||
value={values.fileContent}
|
value={values.fileContent}
|
||||||
onChange={(value) => handleChange({ fileContent: value })}
|
onChange={(value) => handleChange({ fileContent: value })}
|
||||||
yaml
|
type="yaml"
|
||||||
placeholder="Define or paste the content of your manifest file here"
|
placeholder="Define or paste the content of your manifest file here"
|
||||||
error={errors?.fileContent}
|
error={errors?.fileContent}
|
||||||
data-cy="stack-creation-editor"
|
data-cy="stack-creation-editor"
|
||||||
|
|
|
@ -60,7 +60,7 @@ export function ComposeForm({
|
||||||
<WebEditorForm
|
<WebEditorForm
|
||||||
data-cy="compose-editor"
|
data-cy="compose-editor"
|
||||||
value={values.content}
|
value={values.content}
|
||||||
yaml
|
type="yaml"
|
||||||
id="compose-editor"
|
id="compose-editor"
|
||||||
placeholder="Define or paste the content of your docker compose file here"
|
placeholder="Define or paste the content of your docker compose file here"
|
||||||
onChange={(value) => handleContentChange(DeploymentType.Compose, value)}
|
onChange={(value) => handleContentChange(DeploymentType.Compose, value)}
|
||||||
|
|
|
@ -35,7 +35,7 @@ export function KubernetesForm({
|
||||||
<WebEditorForm
|
<WebEditorForm
|
||||||
data-cy="kube-manifest-editor"
|
data-cy="kube-manifest-editor"
|
||||||
value={values.content}
|
value={values.content}
|
||||||
yaml
|
type="yaml"
|
||||||
id="kube-manifest-editor"
|
id="kube-manifest-editor"
|
||||||
placeholder="Define or paste the content of your manifest here"
|
placeholder="Define or paste the content of your manifest here"
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
|
|
|
@ -36,7 +36,7 @@ export function EditYamlFormSection({
|
||||||
onChange={(values) => onChange(values)}
|
onChange={(values) => onChange(values)}
|
||||||
id={formId}
|
id={formId}
|
||||||
placeholder="Define or paste the content of your manifest file here"
|
placeholder="Define or paste the content of your manifest file here"
|
||||||
yaml
|
type="yaml"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -37,7 +37,7 @@ export function YAMLInspector({
|
||||||
readonly
|
readonly
|
||||||
hideTitle
|
hideTitle
|
||||||
id={identifier}
|
id={identifier}
|
||||||
yaml
|
type="yaml"
|
||||||
height={expanded ? '800px' : '500px'}
|
height={expanded ? '800px' : '500px'}
|
||||||
onChange={() => {}} // all kube yaml inspectors in CE are read only
|
onChange={() => {}} // all kube yaml inspectors in CE are read only
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -100,7 +100,7 @@ export function InnerForm({
|
||||||
id="custom-template-creation-editor"
|
id="custom-template-creation-editor"
|
||||||
value={values.FileContent}
|
value={values.FileContent}
|
||||||
onChange={handleChangeFileContent}
|
onChange={handleChangeFileContent}
|
||||||
yaml
|
type="yaml"
|
||||||
placeholder={texts.editor.placeholder}
|
placeholder={texts.editor.placeholder}
|
||||||
error={errors.FileContent}
|
error={errors.FileContent}
|
||||||
>
|
>
|
||||||
|
|
|
@ -92,7 +92,7 @@ export function InnerForm({
|
||||||
id="edit-custom-template-editor"
|
id="edit-custom-template-editor"
|
||||||
value={gitFileContent || values.FileContent}
|
value={gitFileContent || values.FileContent}
|
||||||
onChange={handleChangeFileContent}
|
onChange={handleChangeFileContent}
|
||||||
yaml
|
type="yaml"
|
||||||
placeholder={
|
placeholder={
|
||||||
gitFileContent
|
gitFileContent
|
||||||
? 'Preview of the file from git repository'
|
? 'Preview of the file from git repository'
|
||||||
|
|
|
@ -119,7 +119,7 @@ export function DeployForm({
|
||||||
}
|
}
|
||||||
setFieldValue('fileContent', value);
|
setFieldValue('fileContent', value);
|
||||||
}}
|
}}
|
||||||
yaml
|
type="yaml"
|
||||||
error={errors.fileContent}
|
error={errors.fileContent}
|
||||||
placeholder="Define or paste the content of your docker compose file here"
|
placeholder="Define or paste the content of your docker compose file here"
|
||||||
readonly={isGit}
|
readonly={isGit}
|
||||||
|
|
Loading…
Reference in New Issue