mirror of
https://github.com/portainer/portainer.git
synced 2025-07-19 13:29:41 +02:00
fix(ui): apply controlled input to field [EE-6411] (#10738)
This commit is contained in:
parent
98157350b6
commit
e142939929
8 changed files with 41 additions and 50 deletions
|
@ -15,7 +15,7 @@ import { AssociatedEdgeEnvironmentsSelector } from '@/react/edge/components/Asso
|
||||||
import { EnvironmentsDatatable } from '@/react/edge/edge-stacks/ItemView/EnvironmentsDatatable';
|
import { EnvironmentsDatatable } from '@/react/edge/edge-stacks/ItemView/EnvironmentsDatatable';
|
||||||
import { TemplateFieldset } from '@/react/edge/edge-stacks/CreateView/TemplateFieldset';
|
import { TemplateFieldset } from '@/react/edge/edge-stacks/CreateView/TemplateFieldset';
|
||||||
|
|
||||||
export const componentsModule = angular
|
const ngModule = angular
|
||||||
.module('portainer.edge.react.components', [])
|
.module('portainer.edge.react.components', [])
|
||||||
.component(
|
.component(
|
||||||
'edgeStackEnvironmentsDatatable',
|
'edgeStackEnvironmentsDatatable',
|
||||||
|
@ -104,4 +104,6 @@ export const componentsModule = angular
|
||||||
.component(
|
.component(
|
||||||
'edgeStackCreateTemplateFieldset',
|
'edgeStackCreateTemplateFieldset',
|
||||||
r2a(withReactQuery(TemplateFieldset), ['setValues', 'values', 'errors'])
|
r2a(withReactQuery(TemplateFieldset), ['setValues', 'values', 'errors'])
|
||||||
).name;
|
);
|
||||||
|
|
||||||
|
export const componentsModule = ngModule.name;
|
||||||
|
|
6
app/kubernetes/react/components/applications.ts
Normal file
6
app/kubernetes/react/components/applications.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import angular from 'angular';
|
||||||
|
|
||||||
|
export const applicationsModule = angular.module(
|
||||||
|
'portainer.kubernetes.react.components.applications',
|
||||||
|
[]
|
||||||
|
).name;
|
|
@ -3,7 +3,6 @@ import angular from 'angular';
|
||||||
import { r2a } from '@/react-tools/react2angular';
|
import { r2a } from '@/react-tools/react2angular';
|
||||||
import { IngressClassDatatableAngular } from '@/react/kubernetes/cluster/ingressClass/IngressClassDatatable/IngressClassDatatableAngular';
|
import { IngressClassDatatableAngular } from '@/react/kubernetes/cluster/ingressClass/IngressClassDatatable/IngressClassDatatableAngular';
|
||||||
import { NamespacesSelector } from '@/react/kubernetes/cluster/RegistryAccessView/NamespacesSelector';
|
import { NamespacesSelector } from '@/react/kubernetes/cluster/RegistryAccessView/NamespacesSelector';
|
||||||
import { StorageAccessModeSelector } from '@/react/kubernetes/cluster/ConfigureView/ConfigureForm/StorageAccessModeSelector';
|
|
||||||
import { NamespaceAccessUsersSelector } from '@/react/kubernetes/namespaces/AccessView/NamespaceAccessUsersSelector';
|
import { NamespaceAccessUsersSelector } from '@/react/kubernetes/namespaces/AccessView/NamespaceAccessUsersSelector';
|
||||||
import { RegistriesSelector } from '@/react/kubernetes/namespaces/components/RegistriesFormSection/RegistriesSelector';
|
import { RegistriesSelector } from '@/react/kubernetes/namespaces/components/RegistriesFormSection/RegistriesSelector';
|
||||||
import { KubeServicesForm } from '@/react/kubernetes/applications/CreateView/application-services/KubeServicesForm';
|
import { KubeServicesForm } from '@/react/kubernetes/applications/CreateView/application-services/KubeServicesForm';
|
||||||
|
@ -51,8 +50,10 @@ import { withControlledInput } from '@/react-tools/withControlledInput';
|
||||||
|
|
||||||
import { EnvironmentVariablesFieldset } from '@@/form-components/EnvironmentVariablesFieldset';
|
import { EnvironmentVariablesFieldset } from '@@/form-components/EnvironmentVariablesFieldset';
|
||||||
|
|
||||||
|
import { applicationsModule } from './applications';
|
||||||
|
|
||||||
export const ngModule = angular
|
export const ngModule = angular
|
||||||
.module('portainer.kubernetes.react.components', [])
|
.module('portainer.kubernetes.react.components', [applicationsModule])
|
||||||
.component(
|
.component(
|
||||||
'ingressClassDatatable',
|
'ingressClassDatatable',
|
||||||
r2a(IngressClassDatatableAngular, [
|
r2a(IngressClassDatatableAngular, [
|
||||||
|
@ -78,16 +79,6 @@ export const ngModule = angular
|
||||||
'value',
|
'value',
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
.component(
|
|
||||||
'storageAccessModeSelector',
|
|
||||||
r2a(StorageAccessModeSelector, [
|
|
||||||
'inputId',
|
|
||||||
'onChange',
|
|
||||||
'options',
|
|
||||||
'value',
|
|
||||||
'storageClassName',
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.component(
|
.component(
|
||||||
'namespaceAccessUsersSelector',
|
'namespaceAccessUsersSelector',
|
||||||
r2a(NamespaceAccessUsersSelector, [
|
r2a(NamespaceAccessUsersSelector, [
|
||||||
|
@ -140,11 +131,12 @@ export const ngModule = angular
|
||||||
)
|
)
|
||||||
.component(
|
.component(
|
||||||
'kubeStackName',
|
'kubeStackName',
|
||||||
r2a(withUIRouter(withReactQuery(withCurrentUser(StackName))), [
|
r2a(
|
||||||
'setStackName',
|
withUIRouter(
|
||||||
'isAdmin',
|
withReactQuery(withCurrentUser(withControlledInput(StackName)))
|
||||||
'stackName',
|
),
|
||||||
])
|
['setStackName', 'isAdmin', 'stackName']
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.component(
|
.component(
|
||||||
'applicationSummaryWidget',
|
'applicationSummaryWidget',
|
||||||
|
@ -202,8 +194,12 @@ export const componentsModule = ngModule.name;
|
||||||
|
|
||||||
withFormValidation(
|
withFormValidation(
|
||||||
ngModule,
|
ngModule,
|
||||||
withControlledInput(
|
withUIRouter(
|
||||||
withUIRouter(withCurrentUser(withReactQuery(KubeServicesForm)))
|
withCurrentUser(
|
||||||
|
withReactQuery(
|
||||||
|
withControlledInput(KubeServicesForm, { values: 'onChange' })
|
||||||
|
)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
'kubeServicesForm',
|
'kubeServicesForm',
|
||||||
['values', 'onChange', 'appName', 'selector', 'isEditMode', 'namespace'],
|
['values', 'onChange', 'appName', 'selector', 'isEditMode', 'namespace'],
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
import angular from 'angular';
|
|
||||||
|
|
||||||
import { r2a } from '@/react-tools/react2angular';
|
|
||||||
import { ImportFdoDeviceButton } from '@/react/portainer/environments/ListView/ImportFdoDeviceButton';
|
|
||||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
|
||||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
|
||||||
|
|
||||||
export const envListModule = angular
|
|
||||||
.module('portainer.app.react.components.environments.list-view', [])
|
|
||||||
.component(
|
|
||||||
'importFdoDeviceButton',
|
|
||||||
r2a(withUIRouter(withReactQuery(ImportFdoDeviceButton)), [])
|
|
||||||
).name;
|
|
|
@ -9,6 +9,7 @@ import { withFormValidation } from '@/react-tools/withFormValidation';
|
||||||
import { GroupAssociationTable } from '@/react/portainer/environments/environment-groups/components/GroupAssociationTable';
|
import { GroupAssociationTable } from '@/react/portainer/environments/environment-groups/components/GroupAssociationTable';
|
||||||
import { AssociatedEnvironmentsSelector } from '@/react/portainer/environments/environment-groups/components/AssociatedEnvironmentsSelector';
|
import { AssociatedEnvironmentsSelector } from '@/react/portainer/environments/environment-groups/components/AssociatedEnvironmentsSelector';
|
||||||
import { HelmRepositoryDatatable } from '@/react/portainer/account/AccountView/HelmRepositoryDatatable';
|
import { HelmRepositoryDatatable } from '@/react/portainer/account/AccountView/HelmRepositoryDatatable';
|
||||||
|
import { withControlledInput } from '@/react-tools/withControlledInput';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
EnvironmentVariablesFieldset,
|
EnvironmentVariablesFieldset,
|
||||||
|
@ -21,7 +22,6 @@ import { PageHeader } from '@@/PageHeader';
|
||||||
import { TagSelector } from '@@/TagSelector';
|
import { TagSelector } from '@@/TagSelector';
|
||||||
import { Loading } from '@@/Widget/Loading';
|
import { Loading } from '@@/Widget/Loading';
|
||||||
import { PasswordCheckHint } from '@@/PasswordCheckHint';
|
import { PasswordCheckHint } from '@@/PasswordCheckHint';
|
||||||
import { ViewLoading } from '@@/ViewLoading';
|
|
||||||
import { Tooltip } from '@@/Tip/Tooltip';
|
import { Tooltip } from '@@/Tip/Tooltip';
|
||||||
import { Badge } from '@@/Badge';
|
import { Badge } from '@@/Badge';
|
||||||
import { TableColumnHeaderAngular } from '@@/datatables/TableHeaderCell';
|
import { TableColumnHeaderAngular } from '@@/datatables/TableHeaderCell';
|
||||||
|
@ -43,7 +43,6 @@ import { gitFormModule } from './git-form';
|
||||||
import { settingsModule } from './settings';
|
import { settingsModule } from './settings';
|
||||||
import { accessControlModule } from './access-control';
|
import { accessControlModule } from './access-control';
|
||||||
import { environmentsModule } from './environments';
|
import { environmentsModule } from './environments';
|
||||||
import { envListModule } from './environments-list-view-components';
|
|
||||||
import { registriesModule } from './registries';
|
import { registriesModule } from './registries';
|
||||||
import { accountModule } from './account';
|
import { accountModule } from './account';
|
||||||
|
|
||||||
|
@ -51,7 +50,6 @@ export const ngModule = angular
|
||||||
.module('portainer.app.react.components', [
|
.module('portainer.app.react.components', [
|
||||||
accessControlModule,
|
accessControlModule,
|
||||||
customTemplatesModule,
|
customTemplatesModule,
|
||||||
envListModule,
|
|
||||||
environmentsModule,
|
environmentsModule,
|
||||||
gitFormModule,
|
gitFormModule,
|
||||||
registriesModule,
|
registriesModule,
|
||||||
|
@ -106,7 +104,6 @@ export const ngModule = angular
|
||||||
'isSortedDesc',
|
'isSortedDesc',
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
.component('viewLoading', r2a(ViewLoading, ['message']))
|
|
||||||
.component(
|
.component(
|
||||||
'pageHeader',
|
'pageHeader',
|
||||||
r2a(withUIRouter(withReactQuery(withCurrentUser(PageHeader))), [
|
r2a(withUIRouter(withReactQuery(withCurrentUser(PageHeader))), [
|
||||||
|
@ -198,7 +195,6 @@ export const ngModule = angular
|
||||||
'dataCy',
|
'dataCy',
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
|
|
||||||
.component(
|
.component(
|
||||||
'reactCodeEditor',
|
'reactCodeEditor',
|
||||||
r2a(CodeEditor, [
|
r2a(CodeEditor, [
|
||||||
|
@ -240,7 +236,7 @@ export const componentsModule = ngModule.name;
|
||||||
|
|
||||||
withFormValidation(
|
withFormValidation(
|
||||||
ngModule,
|
ngModule,
|
||||||
EnvironmentVariablesFieldset,
|
withControlledInput(EnvironmentVariablesFieldset, { values: 'onChange' }),
|
||||||
'environmentVariablesFieldset',
|
'environmentVariablesFieldset',
|
||||||
['canUndoDelete'],
|
['canUndoDelete'],
|
||||||
envVarValidation
|
envVarValidation
|
||||||
|
@ -248,7 +244,7 @@ withFormValidation(
|
||||||
|
|
||||||
withFormValidation(
|
withFormValidation(
|
||||||
ngModule,
|
ngModule,
|
||||||
EnvironmentVariablesPanel,
|
withControlledInput(EnvironmentVariablesPanel, { values: 'onChange' }),
|
||||||
'environmentVariablesPanel',
|
'environmentVariablesPanel',
|
||||||
['explanation', 'showHelpMessage', 'isFoldable'],
|
['explanation', 'showHelpMessage', 'isFoldable'],
|
||||||
envVarValidation
|
envVarValidation
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
|
import { ComponentProps } from 'react';
|
||||||
|
|
||||||
import { FormSection } from '@@/form-components/FormSection';
|
import { FormSection } from '@@/form-components/FormSection';
|
||||||
import { TextTip } from '@@/Tip/TextTip';
|
import { TextTip } from '@@/Tip/TextTip';
|
||||||
|
|
||||||
import { ArrayError } from '../InputList/InputList';
|
|
||||||
|
|
||||||
import { Values } from './types';
|
|
||||||
import { EnvironmentVariablesFieldset } from './EnvironmentVariablesFieldset';
|
import { EnvironmentVariablesFieldset } from './EnvironmentVariablesFieldset';
|
||||||
|
|
||||||
|
type FieldsetProps = ComponentProps<typeof EnvironmentVariablesFieldset>;
|
||||||
|
|
||||||
export function EnvironmentVariablesPanel({
|
export function EnvironmentVariablesPanel({
|
||||||
explanation,
|
explanation,
|
||||||
onChange,
|
onChange,
|
||||||
|
@ -15,12 +16,9 @@ export function EnvironmentVariablesPanel({
|
||||||
isFoldable = false,
|
isFoldable = false,
|
||||||
}: {
|
}: {
|
||||||
explanation?: string;
|
explanation?: string;
|
||||||
values: Values;
|
|
||||||
onChange(value: Values): void;
|
|
||||||
showHelpMessage?: boolean;
|
showHelpMessage?: boolean;
|
||||||
errors?: ArrayError<Values>;
|
|
||||||
isFoldable?: boolean;
|
isFoldable?: boolean;
|
||||||
}) {
|
} & FieldsetProps) {
|
||||||
return (
|
return (
|
||||||
<FormSection
|
<FormSection
|
||||||
title="Environment variables"
|
title="Environment variables"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { FormikErrors } from 'formik';
|
import { FormikErrors } from 'formik';
|
||||||
import { boolean, number, object, SchemaOf, string } from 'yup';
|
import { boolean, number, object, SchemaOf, string } from 'yup';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { GitAuthModel } from '@/react/portainer/gitops/types';
|
import { GitAuthModel } from '@/react/portainer/gitops/types';
|
||||||
import { useDebounce } from '@/react/hooks/useDebounce';
|
import { useDebounce } from '@/react/hooks/useDebounce';
|
||||||
|
@ -23,11 +24,12 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AuthFieldset({
|
export function AuthFieldset({
|
||||||
value,
|
value: initialValue,
|
||||||
onChange,
|
onChange,
|
||||||
isAuthExplanationVisible,
|
isAuthExplanationVisible,
|
||||||
errors,
|
errors,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const [value, setValue] = useState(initialValue); // TODO: remove this state when form is not inside angularjs
|
||||||
const [username, setUsername] = useDebounce(
|
const [username, setUsername] = useDebounce(
|
||||||
value.RepositoryUsername || '',
|
value.RepositoryUsername || '',
|
||||||
(username) => handleChange({ RepositoryUsername: username })
|
(username) => handleChange({ RepositoryUsername: username })
|
||||||
|
@ -139,6 +141,7 @@ export function AuthFieldset({
|
||||||
|
|
||||||
function handleChange(partialValue: Partial<GitAuthModel>) {
|
function handleChange(partialValue: Partial<GitAuthModel>) {
|
||||||
onChange(partialValue);
|
onChange(partialValue);
|
||||||
|
setValue((value) => ({ ...value, ...partialValue }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { array, boolean, object, SchemaOf, string } from 'yup';
|
import { array, boolean, object, SchemaOf, string } from 'yup';
|
||||||
import { FormikErrors } from 'formik';
|
import { FormikErrors } from 'formik';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { ComposePathField } from '@/react/portainer/gitops/ComposePathField';
|
import { ComposePathField } from '@/react/portainer/gitops/ComposePathField';
|
||||||
import { RefField } from '@/react/portainer/gitops/RefField';
|
import { RefField } from '@/react/portainer/gitops/RefField';
|
||||||
|
@ -35,7 +36,7 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GitForm({
|
export function GitForm({
|
||||||
value,
|
value: initialValue,
|
||||||
onChange,
|
onChange,
|
||||||
environmentType = 'DOCKER',
|
environmentType = 'DOCKER',
|
||||||
deployMethod = 'compose',
|
deployMethod = 'compose',
|
||||||
|
@ -48,6 +49,7 @@ export function GitForm({
|
||||||
webhookId,
|
webhookId,
|
||||||
webhooksDocs,
|
webhooksDocs,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const [value, setValue] = useState(initialValue); // TODO: remove this state when form is not inside angularjs
|
||||||
return (
|
return (
|
||||||
<FormSection title="Git repository">
|
<FormSection title="Git repository">
|
||||||
<AuthFieldset
|
<AuthFieldset
|
||||||
|
@ -126,6 +128,7 @@ export function GitForm({
|
||||||
|
|
||||||
function handleChange(partialValue: Partial<GitFormModel>) {
|
function handleChange(partialValue: Partial<GitFormModel>) {
|
||||||
onChange(partialValue);
|
onChange(partialValue);
|
||||||
|
setValue((value) => ({ ...value, ...partialValue }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue