argo-cd
166 строк · 8.4 Кб
1import {ErrorNotification, NotificationType} from 'argo-ui';
2import * as classNames from 'classnames';
3import * as React from 'react';
4import {Form, FormApi} from 'react-form';
5import {helpTip} from '../../../applications/components/utils';
6import {Consumer} from '../../context';
7import {Spinner} from '../spinner';
8
9export interface EditablePanelItem {
10title: string;
11customTitle?: string | React.ReactNode;
12key?: string;
13before?: React.ReactNode;
14view: string | React.ReactNode;
15edit?: (formApi: FormApi) => React.ReactNode;
16titleEdit?: (formApi: FormApi) => React.ReactNode;
17}
18
19export interface EditablePanelProps<T> {
20title?: string | React.ReactNode;
21values: T;
22validate?: (values: T) => any;
23save?: (input: T, query: {validate?: boolean}) => Promise<any>;
24items: EditablePanelItem[];
25onModeSwitch?: () => any;
26noReadonlyMode?: boolean;
27view?: string | React.ReactNode;
28edit?: (formApi: FormApi) => React.ReactNode;
29hasMultipleSources?: boolean;
30}
31
32interface EditablePanelState {
33edit: boolean;
34saving: boolean;
35}
36
37require('./editable-panel.scss');
38
39export class EditablePanel<T = {}> extends React.Component<EditablePanelProps<T>, EditablePanelState> {
40private formApi: FormApi;
41
42constructor(props: EditablePanelProps<T>) {
43super(props);
44this.state = {edit: !!props.noReadonlyMode, saving: false};
45}
46
47public UNSAFE_componentWillReceiveProps(nextProps: EditablePanelProps<T>) {
48if (this.formApi && JSON.stringify(this.props.values) !== JSON.stringify(nextProps.values)) {
49if (!!nextProps.noReadonlyMode) {
50this.formApi.setAllValues(nextProps.values);
51}
52}
53}
54
55public render() {
56return (
57<Consumer>
58{ctx => (
59<div className={classNames('white-box editable-panel', {'editable-panel--disabled': this.state.saving})}>
60<div className='white-box__details'>
61{!this.props.noReadonlyMode && this.props.save && (
62<div className='editable-panel__buttons'>
63{!this.state.edit && (
64<button
65onClick={() => {
66this.setState({edit: true});
67this.onModeSwitch();
68}}
69disabled={this.props.hasMultipleSources}
70className='argo-button argo-button--base'>
71{this.props.hasMultipleSources &&
72helpTip('Parameters are not editable for applications with multiple sources. You can edit them in the "Manifest" tab.')}{' '}
73Edit
74</button>
75)}
76{this.state.edit && (
77<React.Fragment>
78<button
79disabled={this.state.saving}
80onClick={() => !this.state.saving && this.formApi.submitForm(null)}
81className='argo-button argo-button--base'>
82<Spinner show={this.state.saving} style={{marginRight: '5px'}} />
83Save
84</button>{' '}
85<button
86onClick={() => {
87this.setState({edit: false});
88this.onModeSwitch();
89}}
90className='argo-button argo-button--base-o'>
91Cancel
92</button>
93</React.Fragment>
94)}
95</div>
96)}
97{this.props.title && <p>{this.props.title}</p>}
98{(!this.state.edit && (
99<React.Fragment>
100{this.props.view}
101{this.props.items
102.filter(item => item.view)
103.map(item => (
104<React.Fragment key={item.key || item.title}>
105{item.before}
106<div className='row white-box__details-row'>
107<div className='columns small-3'>{item.customTitle || item.title}</div>
108<div className='columns small-9'>{item.view}</div>
109</div>
110</React.Fragment>
111))}
112</React.Fragment>
113)) || (
114<Form
115getApi={api => (this.formApi = api)}
116formDidUpdate={async form => {
117if (this.props.noReadonlyMode && this.props.save) {
118await this.props.save(form.values as any, {});
119}
120}}
121onSubmit={async input => {
122try {
123this.setState({saving: true});
124await this.props.save(input as any, {});
125this.setState({edit: false, saving: false});
126this.onModeSwitch();
127} catch (e) {
128ctx.notifications.show({
129content: <ErrorNotification title='Unable to save changes' e={e} />,
130type: NotificationType.Error
131});
132} finally {
133this.setState({saving: false});
134}
135}}
136defaultValues={this.props.values}
137validateError={this.props.validate}>
138{api => (
139<React.Fragment>
140{this.props.edit && this.props.edit(api)}
141{this.props.items.map(item => (
142<React.Fragment key={item.key || item.title}>
143{item.before}
144<div className='row white-box__details-row'>
145<div className='columns small-3'>{(item.titleEdit && item.titleEdit(api)) || item.customTitle || item.title}</div>
146<div className='columns small-9'>{(item.edit && item.edit(api)) || item.view}</div>
147</div>
148</React.Fragment>
149))}
150</React.Fragment>
151)}
152</Form>
153)}
154</div>
155</div>
156)}
157</Consumer>
158);
159}
160
161private onModeSwitch() {
162if (this.props.onModeSwitch) {
163this.props.onModeSwitch();
164}
165}
166}
167