blob: fbd0bed08114fbbcc40ca53584f4d2663b526eca [file] [log] [blame]
Adrià Vilanova Martínezf276ac72022-10-13 22:16:22 +02001import './actions/ReplyWithCR.js';
2
3import {css, html, LitElement, nothing} from 'lit';
4import {map} from 'lit/directives/map.js';
5import {createRef, ref} from 'lit/directives/ref.js';
6
7import * as pb from '../../proto/main_pb.js';
8
9// TODO: remove this and substitute it with proper localization.
10const kActionHeadings = {
11 0: 'Unknown action',
12 1: 'Reply',
13 2: 'Move to a forum',
14 3: 'Mark as duplicate of a thread',
15 4: 'Unmark duplicate',
16 5: 'Change thread attributes',
17 6: 'Reply with canned response',
18 16: 'Star/unstar thread',
19 17: 'Subscribe/unsubscribe to thread',
20 18: 'Vote thread',
21 19: 'Report thread',
22};
23const kSupportedActions = new Set([6]);
24const actionCases = Object.entries(pb.workflows.Action.ActionCase);
25
26export default class WFActionEditor extends LitElement {
27 static properties = {
28 action: {type: Object},
29 readOnly: {type: Boolean},
30 disableRemoveButton: {type: Boolean},
31 step: {type: Number},
32 };
33
34 static styles = css`
35 .action {
36 margin-bottom: 20px;
37 }
38
39 .header {
40 display: flex;
41 align-items: center;
42 margin-bottom: 8px;
43 }
44
45 .step {
46 display: flex;
47 align-items: center;
48 justify-content: center;
49
50 min-height: 30px;
51 min-width: 30px;
52 margin-inline-end: 8px;
53
54 font-weight: 500;
55 font-size: 18px;
56
57 border-radius: 50%;
58 color: white;
59 background-color: #018786;
60 }
61
62 .title {
63 font-weight: 500;
64 margin: 0;
65 flex-grow: 1;
66 }
67
68 .header .select {
69 flex-grow: 1;
70 width: 300px;
71 padding: 4px;
72 margin-inline-end: 8px;
73 font-size: 16px;
74 }
75 `;
76
77 selectRef = createRef();
78
79 constructor() {
80 super();
81 this.action = new pb.workflows.Action();
82 this.readOnly = false;
83 }
84
85 renderActionTitle() {
86 if (this.readOnly) return html`<h3 class="title">${this._stepTitle()}</h3>`;
87
88 let selectedActionCase = this._actionCase;
89
90 return html`
91 <select ${ref(this.selectRef)}
92 class="select"
93 @change=${this._actionCaseChanged}>
94 ${map(actionCases, ([actionName, num]) => {
95 if (num == 0) return nothing;
96 return html`
97 <option value=${num} ?selected=${selectedActionCase == num}>
98 ${kActionHeadings[num] ?? actionName}
99 </option>
100 `;
101 })}
102 </select>
103 `;
104 }
105
106 renderSpecificActionEditor() {
107 switch (this._actionCase) {
108 case pb.workflows.Action.ActionCase.REPLY_WITH_CR_ACTION:
109 return html`
110 <wf-action-reply-with-cr
111 ?readOnly=${this.readOnly}
112 .action=${this.action.getReplyWithCrAction()}>
113 </wf-action-reply-with-cr>
114 `;
115
116 default:
117 return html`<p>This action has not yet been implemented.</p>`;
118 }
119 }
120
121 render() {
122 return [
123 html`
124 <div class="action">
125 <div class="header">
126 <div class="step">${this.step}</div>
127 ${this.renderActionTitle()}
128 ${
129 !this.readOnly ?
130 html`
131 <button
132 ?disabled=${this.disableRemoveButton}
133 @click=${this._remove}>
134 Remove
135 </button>
136 ` :
137 nothing}
138 </div>
139 ${this.renderSpecificActionEditor()}
140 </div>
141 `,
142 ];
143 }
144
145 checkValidity() {
146 if (this.readOnly || !kSupportedActions.has(this._actionCase)) return true;
147 return this._specificActionEditor().checkValidity();
148 }
149
150 _actionCaseChanged() {
151 this._actionCaseString = this.selectRef.value.value;
152 }
153
154 _dispatchUpdateEvent() {
155 // Transmit to other components that the action has changed
156 const e = new Event('action-updated', {bubbles: true, composed: true});
157 this.renderRoot.dispatchEvent(e);
158 }
159
160 _remove() {
161 // Transmit to other components that the action has to be removed
162 const e = new Event('action-removed', {bubbles: true, composed: true});
163 this.renderRoot.dispatchEvent(e);
164 }
165
166 _stepTitle() {
167 return kActionHeadings[this._actionCase] ?? this._actionCase;
168 }
169
170 get _actionCase() {
171 return this.action.getActionCase();
172 }
173
174 set _actionCase(newCase) {
175 let value;
176 switch (newCase) {
177 case pb.workflows.Action.ActionCase.REPLY_ACTION:
178 value = new pb.workflows.Action.ReplyAction;
179 this.action.setReplyAction(value);
180 break;
181 case pb.workflows.Action.ActionCase.MOVE_ACTION:
182 value = new pb.workflows.Action.MoveAction;
183 this.action.setMoveAction(value);
184 break;
185 case pb.workflows.Action.ActionCase.MARK_DUPLICATE_ACTION:
186 value = new pb.workflows.Action.MarkDuplicateAction;
187 this.action.setMarkDuplicateAction(value);
188 break;
189 case pb.workflows.Action.ActionCase.UNMARK_DUPLICATE_ACTION:
190 value = new pb.workflows.Action.UnmarkDuplicateAction;
191 this.action.setUnmarkDuplicateAction(value);
192 break;
193 case pb.workflows.Action.ActionCase.ATTRIBUTE_ACTION:
194 value = new pb.workflows.Action.AttributeAction;
195 this.action.setAttributeAction(value);
196 break;
197 case pb.workflows.Action.ActionCase.REPLY_WITH_CR_ACTION:
198 value = new pb.workflows.Action.ReplyWithCRAction;
199 this.action.setReplyWithCrAction(value);
200 break;
201 case pb.workflows.Action.ActionCase.STAR_ACTION:
202 value = new pb.workflows.Action.StarAction;
203 this.action.setStarAction(value);
204 break;
205 case pb.workflows.Action.ActionCase.SUBSCRIBE_ACTION:
206 value = new pb.workflows.Action.SubscribeAction;
207 this.action.setSubscribeAction(value);
208 break;
209 case pb.workflows.Action.ActionCase.VOTE_ACTION:
210 value = new pb.workflows.Action.VoteAction;
211 this.action.setVoteAction(value);
212 break;
213 case pb.workflows.Action.ActionCase.REPORT_ACTION:
214 value = new pb.workflows.Action.ReportAction;
215 this.action.setReportAction(value);
216 break;
217 default:
218 this.action.clearReplyAction();
219 this.action.clearMoveAction();
220 this.action.clearMarkDuplicateAction();
221 this.action.clearUnmarkDuplicateAction();
222 this.action.clearAttributeAction();
223 this.action.clearReplyWithCrAction();
224 this.action.clearStarAction();
225 this.action.clearSubscribeAction();
226 this.action.clearVoteAction();
227 this.action.clearReportAction();
228 }
229
230 this.requestUpdate();
231 this._dispatchUpdateEvent();
232 }
233
234 // The same as _actionCase, but represented as a String instead of a Number
235 get _actionCaseString() {
236 return this._actionCase.toString();
237 }
238
239 set _actionCaseString(newCase) {
240 this._actionCase = parseInt(newCase);
241 }
242
243 _specificActionEditor() {
244 switch (this._actionCase) {
245 case pb.workflows.Action.ActionCase.REPLY_WITH_CR_ACTION:
246 return this.renderRoot.querySelector('wf-action-reply-with-cr');
247
248 default:
249 return null;
250 }
251 }
252}
253window.customElements.define('wf-action-editor', WFActionEditor);