mirror of
https://github.com/portainer/portainer.git
synced 2025-08-03 21:05:23 +02:00
fix(edge-stack): sync CE code with EE EE-6163 (#10437)
This commit is contained in:
parent
a0dbabcc5f
commit
66ca73f98b
9 changed files with 397 additions and 3 deletions
|
@ -3,13 +3,18 @@ import { useRouter } from '@uirouter/react';
|
||||||
|
|
||||||
import { AuthFieldset } from '@/react/portainer/gitops/AuthFieldset';
|
import { AuthFieldset } from '@/react/portainer/gitops/AuthFieldset';
|
||||||
import { AutoUpdateFieldset } from '@/react/portainer/gitops/AutoUpdateFieldset';
|
import { AutoUpdateFieldset } from '@/react/portainer/gitops/AutoUpdateFieldset';
|
||||||
|
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
|
||||||
import {
|
import {
|
||||||
parseAutoUpdateResponse,
|
parseAutoUpdateResponse,
|
||||||
transformAutoUpdateViewModel,
|
transformAutoUpdateViewModel,
|
||||||
} from '@/react/portainer/gitops/AutoUpdateFieldset/utils';
|
} from '@/react/portainer/gitops/AutoUpdateFieldset/utils';
|
||||||
import { InfoPanel } from '@/react/portainer/gitops/InfoPanel';
|
import { InfoPanel } from '@/react/portainer/gitops/InfoPanel';
|
||||||
import { RefField } from '@/react/portainer/gitops/RefField';
|
import { RefField } from '@/react/portainer/gitops/RefField';
|
||||||
import { AutoUpdateModel, GitAuthModel } from '@/react/portainer/gitops/types';
|
import {
|
||||||
|
AutoUpdateModel,
|
||||||
|
GitAuthModel,
|
||||||
|
RelativePathModel,
|
||||||
|
} from '@/react/portainer/gitops/types';
|
||||||
import {
|
import {
|
||||||
baseEdgeStackWebhookUrl,
|
baseEdgeStackWebhookUrl,
|
||||||
createWebhookId,
|
createWebhookId,
|
||||||
|
@ -28,6 +33,8 @@ import { notifyError, notifySuccess } from '@/portainer/services/notifications';
|
||||||
import { EnvironmentType } from '@/react/portainer/environments/types';
|
import { EnvironmentType } from '@/react/portainer/environments/types';
|
||||||
import { Registry } from '@/react/portainer/registries/types';
|
import { Registry } from '@/react/portainer/registries/types';
|
||||||
import { useRegistries } from '@/react/portainer/registries/queries/useRegistries';
|
import { useRegistries } from '@/react/portainer/registries/queries/useRegistries';
|
||||||
|
import { RelativePathFieldset } from '@/react/portainer/gitops/RelativePathFieldset/RelativePathFieldset';
|
||||||
|
import { parseRelativePathResponse } from '@/react/portainer/gitops/RelativePathFieldset/utils';
|
||||||
|
|
||||||
import { LoadingButton } from '@@/buttons';
|
import { LoadingButton } from '@@/buttons';
|
||||||
import { FormSection } from '@@/form-components/FormSection';
|
import { FormSection } from '@@/form-components/FormSection';
|
||||||
|
@ -53,6 +60,7 @@ interface FormValues {
|
||||||
authentication: GitAuthModel;
|
authentication: GitAuthModel;
|
||||||
envVars: EnvVar[];
|
envVars: EnvVar[];
|
||||||
privateRegistryId?: Registry['Id'];
|
privateRegistryId?: Registry['Id'];
|
||||||
|
relativePath: RelativePathModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GitForm({ stack }: { stack: EdgeStack }) {
|
export function GitForm({ stack }: { stack: EdgeStack }) {
|
||||||
|
@ -73,6 +81,7 @@ export function GitForm({ stack }: { stack: EdgeStack }) {
|
||||||
autoUpdate: parseAutoUpdateResponse(stack.AutoUpdate),
|
autoUpdate: parseAutoUpdateResponse(stack.AutoUpdate),
|
||||||
refName: stack.GitConfig.ReferenceName,
|
refName: stack.GitConfig.ReferenceName,
|
||||||
authentication: parseAuthResponse(stack.GitConfig.Authentication),
|
authentication: parseAuthResponse(stack.GitConfig.Authentication),
|
||||||
|
relativePath: parseRelativePathResponse(stack),
|
||||||
envVars: stack.EnvVars || [],
|
envVars: stack.EnvVars || [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -270,6 +279,8 @@ function InnerForm({
|
||||||
errors={errors.authentication}
|
errors={errors.authentication}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{isBE && <RelativePathFieldset value={values.relativePath} readonly />}
|
||||||
|
|
||||||
<EnvironmentVariablesPanel
|
<EnvironmentVariablesPanel
|
||||||
onChange={(value) => setFieldValue('envVars', value)}
|
onChange={(value) => setFieldValue('envVars', value)}
|
||||||
values={values.envVars}
|
values={values.envVars}
|
||||||
|
|
|
@ -83,6 +83,12 @@ export type EdgeStack = {
|
||||||
Webhook?: string;
|
Webhook?: string;
|
||||||
StackFileVersion?: number;
|
StackFileVersion?: number;
|
||||||
EnvVars?: EnvVar[];
|
EnvVars?: EnvVar[];
|
||||||
|
SupportRelativePath: boolean;
|
||||||
|
FilesystemPath?: string;
|
||||||
|
SupportPerDeviceConfigs?: boolean;
|
||||||
|
PerDeviceConfigsPath?: string;
|
||||||
|
PerDeviceConfigsMatchType?: string;
|
||||||
|
PerDeviceConfigsGroupMatchType?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum EditorType {
|
export enum EditorType {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { ChangeEvent } from 'react';
|
||||||
import {
|
import {
|
||||||
Combobox,
|
Combobox,
|
||||||
ComboboxInput,
|
ComboboxInput,
|
||||||
|
@ -6,7 +7,6 @@ import {
|
||||||
ComboboxPopover,
|
ComboboxPopover,
|
||||||
} from '@reach/combobox';
|
} from '@reach/combobox';
|
||||||
import '@reach/combobox/styles.css';
|
import '@reach/combobox/styles.css';
|
||||||
import { ChangeEvent } from 'react';
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import { useSearch } from '@/react/portainer/gitops/queries/useSearch';
|
import { useSearch } from '@/react/portainer/gitops/queries/useSearch';
|
||||||
|
@ -22,11 +22,15 @@ export function PathSelector({
|
||||||
onChange,
|
onChange,
|
||||||
placeholder,
|
placeholder,
|
||||||
model,
|
model,
|
||||||
|
dirOnly,
|
||||||
|
readOnly,
|
||||||
}: {
|
}: {
|
||||||
value: string;
|
value: string;
|
||||||
onChange(value: string): void;
|
onChange(value: string): void;
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
model: GitFormModel;
|
model: GitFormModel;
|
||||||
|
dirOnly?: boolean;
|
||||||
|
readOnly?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const [searchTerm, setSearchTerm] = useDebounce(value, onChange);
|
const [searchTerm, setSearchTerm] = useDebounce(value, onChange);
|
||||||
|
|
||||||
|
@ -36,6 +40,7 @@ export function PathSelector({
|
||||||
keyword: searchTerm,
|
keyword: searchTerm,
|
||||||
reference: model.RepositoryReferenceName,
|
reference: model.RepositoryReferenceName,
|
||||||
tlsSkipVerify: model.TLSSkipVerify,
|
tlsSkipVerify: model.TLSSkipVerify,
|
||||||
|
dirOnly,
|
||||||
...creds,
|
...creds,
|
||||||
};
|
};
|
||||||
const enabled = Boolean(
|
const enabled = Boolean(
|
||||||
|
@ -51,10 +56,11 @@ export function PathSelector({
|
||||||
data-cy="component-gitComposeInput"
|
data-cy="component-gitComposeInput"
|
||||||
>
|
>
|
||||||
<ComboboxInput
|
<ComboboxInput
|
||||||
|
value={searchTerm}
|
||||||
className="form-control"
|
className="form-control"
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
value={searchTerm}
|
readOnly={readOnly}
|
||||||
/>
|
/>
|
||||||
{searchResults && searchResults.length > 0 && (
|
{searchResults && searchResults.length > 0 && (
|
||||||
<ComboboxPopover>
|
<ComboboxPopover>
|
||||||
|
|
|
@ -0,0 +1,251 @@
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
GitFormModel,
|
||||||
|
RelativePathModel,
|
||||||
|
} from '@/react/portainer/gitops/types';
|
||||||
|
import { PathSelector } from '@/react/portainer/gitops/ComposePathField/PathSelector';
|
||||||
|
import { dummyGitForm } from '@/react/portainer/gitops/RelativePathFieldset/utils';
|
||||||
|
import { useValidation } from '@/react/portainer/gitops/RelativePathFieldset/useValidation';
|
||||||
|
|
||||||
|
import { SwitchField } from '@@/form-components/SwitchField';
|
||||||
|
import { TextTip } from '@@/Tip/TextTip';
|
||||||
|
import { FormControl } from '@@/form-components/FormControl';
|
||||||
|
import { Input, Select } from '@@/form-components/Input';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
value: RelativePathModel;
|
||||||
|
gitModel?: GitFormModel;
|
||||||
|
onChange?: (value: Partial<RelativePathModel>) => void;
|
||||||
|
readonly?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RelativePathFieldset({
|
||||||
|
value,
|
||||||
|
gitModel,
|
||||||
|
onChange,
|
||||||
|
readonly,
|
||||||
|
}: Props) {
|
||||||
|
const innerOnChange = useCallback(
|
||||||
|
(value: Partial<RelativePathModel>) => onChange && onChange(value),
|
||||||
|
[onChange]
|
||||||
|
);
|
||||||
|
|
||||||
|
const { errors } = useValidation(value);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="form-group">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<TextTip color="blue">
|
||||||
|
'Gitops Edge Configuration' requires relative path volumes
|
||||||
|
to be enabled first, as it uses this feature as the base mechanism.
|
||||||
|
</TextTip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<SwitchField
|
||||||
|
name="EnableRelativePaths"
|
||||||
|
label="Enable relative path volumes"
|
||||||
|
labelClass="col-sm-3 col-lg-2"
|
||||||
|
tooltip="Enabling this means you can specify relative path volumes in your Compose files, with Portainer pulling the content from your git repository to the environment the stack is deployed to."
|
||||||
|
disabled={readonly}
|
||||||
|
checked={value.SupportRelativePath}
|
||||||
|
onChange={(value) => innerOnChange({ SupportRelativePath: value })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{value.SupportRelativePath && (
|
||||||
|
<>
|
||||||
|
<div className="form-group">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<TextTip color="blue">
|
||||||
|
For relative path volumes use with Docker Swarm, you must have a
|
||||||
|
network filesystem which all of your nodes can access.
|
||||||
|
</TextTip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<FormControl
|
||||||
|
label="Local filesystem path"
|
||||||
|
errors={errors.FilesystemPath}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
name="FilesystemPath"
|
||||||
|
placeholder="/mnt"
|
||||||
|
disabled={readonly}
|
||||||
|
value={value.FilesystemPath}
|
||||||
|
onChange={(e) =>
|
||||||
|
innerOnChange({ FilesystemPath: e.target.value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<TextTip color="blue">
|
||||||
|
When enabled, corresponding Edge ID will be passed through as an
|
||||||
|
environment variable: PORTAINER_EDGE_ID.
|
||||||
|
</TextTip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<SwitchField
|
||||||
|
name="EnablePerDeviceConfigs"
|
||||||
|
label="GitOps Edge configurations"
|
||||||
|
labelClass="col-sm-3 col-lg-2"
|
||||||
|
tooltip="By enabling the GitOps Edge Configurations feature, you gain the ability to define relative path volumes in your configuration files. Portainer will then automatically fetch the content from your git repository by matching the folder name or file name with the Portainer Edge ID, and apply it to the environment where the stack is deployed"
|
||||||
|
disabled={readonly}
|
||||||
|
checked={!!value.SupportPerDeviceConfigs}
|
||||||
|
onChange={(value) =>
|
||||||
|
innerOnChange({ SupportPerDeviceConfigs: value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{value.SupportPerDeviceConfigs && (
|
||||||
|
<>
|
||||||
|
<div className="form-group">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<TextTip color="blue">
|
||||||
|
Specify the directory name where your configuration will be
|
||||||
|
located. This will allow you to manage device configuration
|
||||||
|
settings with a Git repo as your template.
|
||||||
|
</TextTip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<FormControl
|
||||||
|
label="Directory"
|
||||||
|
errors={errors.PerDeviceConfigsPath}
|
||||||
|
>
|
||||||
|
<PathSelector
|
||||||
|
value={value.PerDeviceConfigsPath || ''}
|
||||||
|
onChange={(value) =>
|
||||||
|
innerOnChange({ PerDeviceConfigsPath: value })
|
||||||
|
}
|
||||||
|
placeholder="config"
|
||||||
|
model={gitModel || dummyGitForm}
|
||||||
|
readOnly={readonly}
|
||||||
|
dirOnly
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<TextTip color="blue">
|
||||||
|
Select which rule to use when matching configuration with
|
||||||
|
Portainer Edge ID either on a per-device basis or group-wide
|
||||||
|
with an Edge Group. Only configurations that match the
|
||||||
|
selected rule will be accessible through their corresponding
|
||||||
|
paths. Deployments that rely on accessing the configuration
|
||||||
|
may experience errors.
|
||||||
|
</TextTip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<FormControl label="Device matching rule">
|
||||||
|
<Select
|
||||||
|
value={value.PerDeviceConfigsMatchType}
|
||||||
|
onChange={(e) =>
|
||||||
|
innerOnChange({
|
||||||
|
PerDeviceConfigsMatchType: e.target.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Match file name with Portainer Edge ID',
|
||||||
|
value: 'file',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Match folder name with Portainer Edge ID',
|
||||||
|
value: 'dir',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
disabled={readonly}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<FormControl label="Group matching rule">
|
||||||
|
<Select
|
||||||
|
value={value.PerDeviceConfigsGroupMatchType}
|
||||||
|
onChange={(e) =>
|
||||||
|
innerOnChange({
|
||||||
|
PerDeviceConfigsGroupMatchType: e.target.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Match file name with Edge Group',
|
||||||
|
value: 'file',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Match folder name with Edge Group',
|
||||||
|
value: 'dir',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
disabled={readonly}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<TextTip color="blue">
|
||||||
|
<div>
|
||||||
|
You can use it as an environment variable with an image:{' '}
|
||||||
|
<code>myapp:${PORTAINER_EDGE_ID}</code> or{' '}
|
||||||
|
<code>myapp:${PORTAINER_EDGE_GROUP}</code>. You
|
||||||
|
can also use it with the relative path for volumes:{' '}
|
||||||
|
<code>
|
||||||
|
./config/${PORTAINER_EDGE_ID}:/myapp/config
|
||||||
|
</code>{' '}
|
||||||
|
or{' '}
|
||||||
|
<code>
|
||||||
|
./config/${PORTAINER_EDGE_GROUP}:/myapp/groupconfig
|
||||||
|
</code>
|
||||||
|
. More documentation can be found{' '}
|
||||||
|
<a href="https://docs.portainer.io/user/edge/stacks/add#gitops-edge-configurations">
|
||||||
|
here
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</div>
|
||||||
|
</TextTip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { FormikErrors, yupToFormErrors } from 'formik';
|
||||||
|
|
||||||
|
import { RelativePathModel } from '@/react/portainer/gitops/types';
|
||||||
|
import { relativePathValidation } from '@/react/portainer/gitops/RelativePathFieldset/validation';
|
||||||
|
|
||||||
|
export function useValidation(value: RelativePathModel) {
|
||||||
|
const [errors, setErrors] = useState<FormikErrors<RelativePathModel>>({});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function valide() {
|
||||||
|
try {
|
||||||
|
await relativePathValidation().validate(value, {
|
||||||
|
strict: true,
|
||||||
|
abortEarly: false,
|
||||||
|
});
|
||||||
|
setErrors({});
|
||||||
|
} catch (error) {
|
||||||
|
setErrors(yupToFormErrors(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
valide();
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
return { errors };
|
||||||
|
}
|
28
app/react/portainer/gitops/RelativePathFieldset/utils.ts
Normal file
28
app/react/portainer/gitops/RelativePathFieldset/utils.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { EdgeStack } from '@/react/edge/edge-stacks/types';
|
||||||
|
|
||||||
|
import { GitFormModel, RelativePathModel } from '../types';
|
||||||
|
|
||||||
|
export function parseRelativePathResponse(stack: EdgeStack): RelativePathModel {
|
||||||
|
return {
|
||||||
|
SupportRelativePath: stack.SupportRelativePath,
|
||||||
|
FilesystemPath: stack.FilesystemPath,
|
||||||
|
SupportPerDeviceConfigs: stack.SupportPerDeviceConfigs,
|
||||||
|
PerDeviceConfigsMatchType: stack.PerDeviceConfigsMatchType,
|
||||||
|
PerDeviceConfigsGroupMatchType: stack.PerDeviceConfigsGroupMatchType,
|
||||||
|
PerDeviceConfigsPath: stack.PerDeviceConfigsPath,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dummyGitForm: GitFormModel = {
|
||||||
|
RepositoryURL: '',
|
||||||
|
RepositoryURLValid: false,
|
||||||
|
RepositoryAuthentication: false,
|
||||||
|
RepositoryUsername: '',
|
||||||
|
RepositoryPassword: '',
|
||||||
|
AdditionalFiles: [],
|
||||||
|
RepositoryReferenceName: '',
|
||||||
|
ComposeFilePathInRepository: '',
|
||||||
|
NewCredentialName: '',
|
||||||
|
SaveCredential: false,
|
||||||
|
TLSSkipVerify: false,
|
||||||
|
};
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { boolean, object, SchemaOf, string } from 'yup';
|
||||||
|
|
||||||
|
import { RelativePathModel } from '@/react/portainer/gitops/types';
|
||||||
|
|
||||||
|
export function relativePathValidation(): SchemaOf<RelativePathModel> {
|
||||||
|
return object({
|
||||||
|
SupportRelativePath: boolean().default(false),
|
||||||
|
FilesystemPath: string()
|
||||||
|
.when(['SupportRelativePath'], {
|
||||||
|
is: true,
|
||||||
|
then: string().required('Local filesystem path is required'),
|
||||||
|
})
|
||||||
|
.default(''),
|
||||||
|
SupportPerDeviceConfigs: boolean().default(false),
|
||||||
|
PerDeviceConfigsPath: string()
|
||||||
|
.when(['SupportPerDeviceConfigs'], {
|
||||||
|
is: true,
|
||||||
|
then: string().required('Directory is required'),
|
||||||
|
})
|
||||||
|
.default(''),
|
||||||
|
PerDeviceConfigsMatchType: string().oneOf(['', 'file', 'dir']),
|
||||||
|
PerDeviceConfigsGroupMatchType: string().oneOf(['', 'file', 'dir']),
|
||||||
|
});
|
||||||
|
}
|
32
app/react/portainer/gitops/index.ts
Normal file
32
app/react/portainer/gitops/index.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import angular from 'angular';
|
||||||
|
|
||||||
|
import { r2a } from '@/react-tools/react2angular';
|
||||||
|
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||||
|
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||||
|
import { PathSelector } from '@/react/portainer/gitops/ComposePathField/PathSelector';
|
||||||
|
import { RelativePathFieldset } from '@/react/portainer/gitops/RelativePathFieldset/RelativePathFieldset';
|
||||||
|
|
||||||
|
export const ngModule = angular
|
||||||
|
.module('portainer.app.react.gitops', [])
|
||||||
|
.component(
|
||||||
|
'pathSelector',
|
||||||
|
r2a(withUIRouter(withReactQuery(PathSelector)), [
|
||||||
|
'value',
|
||||||
|
'onChange',
|
||||||
|
'placeholder',
|
||||||
|
'model',
|
||||||
|
'dirOnly',
|
||||||
|
'readOnly',
|
||||||
|
])
|
||||||
|
)
|
||||||
|
.component(
|
||||||
|
'relativePathFieldset',
|
||||||
|
r2a(withUIRouter(withReactQuery(RelativePathFieldset)), [
|
||||||
|
'value',
|
||||||
|
'gitModel',
|
||||||
|
'onChange',
|
||||||
|
'readonly',
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
export const gitopsModule = ngModule.name;
|
|
@ -69,3 +69,12 @@ export interface GitFormModel extends GitAuthModel {
|
||||||
*/
|
*/
|
||||||
AutoUpdate?: AutoUpdateModel;
|
AutoUpdate?: AutoUpdateModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RelativePathModel {
|
||||||
|
SupportRelativePath: boolean;
|
||||||
|
FilesystemPath?: string;
|
||||||
|
SupportPerDeviceConfigs?: boolean;
|
||||||
|
PerDeviceConfigsPath?: string;
|
||||||
|
PerDeviceConfigsMatchType?: string;
|
||||||
|
PerDeviceConfigsGroupMatchType?: string;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue