diff options
Diffstat (limited to 'src/features/workspaces/components/EditWorkspaceForm.tsx')
-rw-r--r-- | src/features/workspaces/components/EditWorkspaceForm.tsx | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/src/features/workspaces/components/EditWorkspaceForm.tsx b/src/features/workspaces/components/EditWorkspaceForm.tsx new file mode 100644 index 000000000..a860ac2e8 --- /dev/null +++ b/src/features/workspaces/components/EditWorkspaceForm.tsx | |||
@@ -0,0 +1,247 @@ | |||
1 | import { Component, ReactElement } from 'react'; | ||
2 | import { observer } from 'mobx-react'; | ||
3 | import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl'; | ||
4 | import { Link } from 'react-router-dom'; | ||
5 | import withStyles, { WithStylesProps } from 'react-jss'; | ||
6 | import Infobox from '../../../components/ui/infobox/index'; | ||
7 | import Input from '../../../components/ui/input'; | ||
8 | import Button from '../../../components/ui/button'; | ||
9 | import Workspace from '../models/Workspace'; | ||
10 | import Service from '../../../models/Service'; | ||
11 | import Form from '../../../lib/Form'; | ||
12 | import { required } from '../../../helpers/validation-helpers'; | ||
13 | import WorkspaceServiceListItem from './WorkspaceServiceListItem'; | ||
14 | import Request from '../../../stores/lib/Request'; | ||
15 | import { KEEP_WS_LOADED_USID } from '../../../config'; | ||
16 | import Toggle from '../../../components/ui/toggle'; | ||
17 | import { H2 } from '../../../components/ui/headline'; | ||
18 | |||
19 | const messages = defineMessages({ | ||
20 | buttonDelete: { | ||
21 | id: 'settings.workspace.form.buttonDelete', | ||
22 | defaultMessage: 'Delete workspace', | ||
23 | }, | ||
24 | buttonSave: { | ||
25 | id: 'settings.workspace.form.buttonSave', | ||
26 | defaultMessage: 'Save workspace', | ||
27 | }, | ||
28 | name: { | ||
29 | id: 'settings.workspace.form.name', | ||
30 | defaultMessage: 'Name', | ||
31 | }, | ||
32 | yourWorkspaces: { | ||
33 | id: 'settings.workspace.form.yourWorkspaces', | ||
34 | defaultMessage: 'Your workspaces', | ||
35 | }, | ||
36 | keepLoaded: { | ||
37 | id: 'settings.workspace.form.keepLoaded', | ||
38 | defaultMessage: 'Keep this workspace loaded*', | ||
39 | }, | ||
40 | keepLoadedInfo: { | ||
41 | id: 'settings.workspace.form.keepLoadedInfo', | ||
42 | defaultMessage: | ||
43 | '*This option will be overwritten by the global "Keep all workspaces loaded" option.', | ||
44 | }, | ||
45 | servicesInWorkspaceHeadline: { | ||
46 | id: 'settings.workspace.form.servicesInWorkspaceHeadline', | ||
47 | defaultMessage: 'Services in this Workspace', | ||
48 | }, | ||
49 | noServicesAdded: { | ||
50 | id: 'settings.services.noServicesAdded', | ||
51 | defaultMessage: 'Start by adding a service.', | ||
52 | }, | ||
53 | discoverServices: { | ||
54 | id: 'settings.services.discoverServices', | ||
55 | defaultMessage: 'Discover services', | ||
56 | }, | ||
57 | }); | ||
58 | |||
59 | const styles = { | ||
60 | nameInput: { | ||
61 | height: 'auto', | ||
62 | }, | ||
63 | serviceList: { | ||
64 | height: 'auto', | ||
65 | }, | ||
66 | keepLoadedInfo: { | ||
67 | marginBottom: '2rem !important', | ||
68 | }, | ||
69 | }; | ||
70 | |||
71 | interface IProps extends WithStylesProps<typeof styles>, WrappedComponentProps { | ||
72 | onDelete: () => void; | ||
73 | onSave: (...args: any[]) => void; | ||
74 | services: Service[]; | ||
75 | workspace: Workspace; | ||
76 | updateWorkspaceRequest: Request; | ||
77 | deleteWorkspaceRequest: Request; | ||
78 | } | ||
79 | |||
80 | @observer | ||
81 | class EditWorkspaceForm extends Component<IProps> { | ||
82 | form: Form; | ||
83 | |||
84 | constructor(props: IProps) { | ||
85 | super(props); | ||
86 | |||
87 | this.form = this.prepareWorkspaceForm(this.props.workspace); | ||
88 | } | ||
89 | |||
90 | UNSAFE_componentWillReceiveProps(nextProps): void { | ||
91 | const { workspace } = this.props; | ||
92 | if (workspace.id !== nextProps.workspace.id) { | ||
93 | this.form = this.prepareWorkspaceForm(nextProps.workspace); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | prepareWorkspaceForm(workspace: Workspace): Form { | ||
98 | const { intl, updateWorkspaceRequest } = this.props; | ||
99 | updateWorkspaceRequest.reset(); | ||
100 | |||
101 | return new Form({ | ||
102 | fields: { | ||
103 | name: { | ||
104 | label: intl.formatMessage(messages.name), | ||
105 | placeholder: intl.formatMessage(messages.name), | ||
106 | value: workspace.name, | ||
107 | validators: [required], | ||
108 | }, | ||
109 | keepLoaded: { | ||
110 | label: intl.formatMessage(messages.keepLoaded), | ||
111 | value: workspace.services.includes(KEEP_WS_LOADED_USID), | ||
112 | default: false, | ||
113 | type: 'checkbox', | ||
114 | }, | ||
115 | services: { | ||
116 | value: [...workspace.services], | ||
117 | }, | ||
118 | }, | ||
119 | }); | ||
120 | } | ||
121 | |||
122 | save(form): void { | ||
123 | this.props.updateWorkspaceRequest.reset(); | ||
124 | form.submit({ | ||
125 | onSuccess: async f => { | ||
126 | const { onSave } = this.props; | ||
127 | const values = f.values(); | ||
128 | onSave(values); | ||
129 | }, | ||
130 | onError: async () => {}, | ||
131 | }); | ||
132 | } | ||
133 | |||
134 | delete(): void { | ||
135 | const { onDelete } = this.props; | ||
136 | onDelete(); | ||
137 | } | ||
138 | |||
139 | toggleService(service: Service): void { | ||
140 | const servicesField = this.form.$('services'); | ||
141 | const serviceIds = servicesField.value; | ||
142 | if (serviceIds.includes(service.id)) { | ||
143 | serviceIds.splice(serviceIds.indexOf(service.id), 1); | ||
144 | } else { | ||
145 | serviceIds.push(service.id); | ||
146 | } | ||
147 | servicesField.set(serviceIds); | ||
148 | } | ||
149 | |||
150 | render(): ReactElement { | ||
151 | const { | ||
152 | classes, | ||
153 | workspace, | ||
154 | services, | ||
155 | deleteWorkspaceRequest, | ||
156 | updateWorkspaceRequest, | ||
157 | intl, | ||
158 | } = this.props; | ||
159 | const { form } = this; | ||
160 | const workspaceServices = form.$('services').value; | ||
161 | const isDeleting = deleteWorkspaceRequest.isExecuting; | ||
162 | const isSaving = updateWorkspaceRequest.isExecuting; | ||
163 | |||
164 | return ( | ||
165 | <div className="settings__main"> | ||
166 | <div className="settings__header"> | ||
167 | <span className="settings__header-item"> | ||
168 | <Link to="/settings/workspaces"> | ||
169 | {intl.formatMessage(messages.yourWorkspaces)} | ||
170 | </Link> | ||
171 | </span> | ||
172 | <span className="separator" /> | ||
173 | <span className="settings__header-item">{workspace.name}</span> | ||
174 | </div> | ||
175 | <div className="settings__body"> | ||
176 | {updateWorkspaceRequest.error && ( | ||
177 | <Infobox icon="alert" type="danger"> | ||
178 | Error while saving workspace | ||
179 | </Infobox> | ||
180 | )} | ||
181 | <div className={classes.nameInput}> | ||
182 | <Input {...form.$('name').bind()} /> | ||
183 | <Toggle {...form.$('keepLoaded').bind()} /> | ||
184 | <p className={`${classes.keepLoadedInfo} franz-form__label`}> | ||
185 | {intl.formatMessage(messages.keepLoadedInfo)} | ||
186 | </p> | ||
187 | </div> | ||
188 | <H2>{intl.formatMessage(messages.servicesInWorkspaceHeadline)}</H2> | ||
189 | <div className={classes.serviceList}> | ||
190 | {services.length === 0 ? ( | ||
191 | <div className="align-middle settings__empty-state"> | ||
192 | {/* ===== Empty state ===== */} | ||
193 | <p className="settings__empty-text"> | ||
194 | <span className="emoji"> | ||
195 | <img src="./assets/images/emoji/sad.png" alt="" /> | ||
196 | </span> | ||
197 | {intl.formatMessage(messages.noServicesAdded)} | ||
198 | </p> | ||
199 | <Link to="/settings/recipes" className="button"> | ||
200 | {intl.formatMessage(messages.discoverServices)} | ||
201 | </Link> | ||
202 | </div> | ||
203 | ) : ( | ||
204 | <> | ||
205 | {services.map(service => ( | ||
206 | <WorkspaceServiceListItem | ||
207 | key={service.id} | ||
208 | service={service} | ||
209 | isInWorkspace={workspaceServices.includes(service.id)} | ||
210 | onToggle={() => this.toggleService(service)} | ||
211 | /> | ||
212 | ))} | ||
213 | </> | ||
214 | )} | ||
215 | </div> | ||
216 | </div> | ||
217 | <div className="settings__controls"> | ||
218 | {/* ===== Delete Button ===== */} | ||
219 | <Button | ||
220 | label={intl.formatMessage(messages.buttonDelete)} | ||
221 | loaded={false} | ||
222 | busy={isDeleting} | ||
223 | buttonType={isDeleting ? 'secondary' : 'danger'} | ||
224 | className="settings__delete-button" | ||
225 | disabled={isDeleting} | ||
226 | onClick={this.delete.bind(this)} | ||
227 | /> | ||
228 | {/* ===== Save Button ===== */} | ||
229 | <Button | ||
230 | type="submit" | ||
231 | label={intl.formatMessage(messages.buttonSave)} | ||
232 | busy={isSaving} | ||
233 | className="franz-form__button" | ||
234 | buttonType={isSaving ? 'secondary' : 'primary'} | ||
235 | onClick={this.save.bind(this, form)} | ||
236 | // TODO: Need to disable if no services have been added to this workspace | ||
237 | disabled={isSaving} | ||
238 | /> | ||
239 | </div> | ||
240 | </div> | ||
241 | ); | ||
242 | } | ||
243 | } | ||
244 | |||
245 | export default injectIntl( | ||
246 | withStyles(styles, { injectTheme: true })(EditWorkspaceForm), | ||
247 | ); | ||