saby-customizer 0.0.0-pre.7 → 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/features/doc-copy-link.js +17 -0
- package/features/git-branch.js +770 -40
- package/lib/context.js +43 -0
- package/lib/database.js +4 -1
- package/lib/layout.js +75 -20
- package/lib/popup-dialog.js +69 -31
- package/{saby-lib → lib/saby-lib}/cloud-statistic.js +1 -0
- package/{saby-lib → lib/saby-lib}/edo.js +49 -7
- package/lib/saby-lib/rpc.js +19 -0
- package/lib/saby-lib/toolbar.js +272 -0
- package/lib.js +8 -0
- package/material.js +9161 -5144
- package/octicons.js +4673 -0
- package/package.json +25 -17
- package/{lib → third-party}/material.js +5 -0
- package/third-party/octicons.js +3 -0
- package/userscript.js +9 -4
package/features/git-branch.js
CHANGED
|
@@ -1,52 +1,632 @@
|
|
|
1
1
|
import { oom } from '@notml/core'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { getListOfOpenCards } from '../saby-lib/edo.js'
|
|
2
|
+
import { keysMapping, toolbar, PopupDialog, getListOfOpenCards, snackbar, context, db } from 'saby-customizer/lib.js'
|
|
3
|
+
import { octicons } from 'saby-customizer/octicons.js'
|
|
5
4
|
|
|
6
5
|
|
|
6
|
+
/** Класс для управления данными карточки задачи */
|
|
7
|
+
export class GitBranchCardData {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef GitCardData
|
|
11
|
+
* @property {string} [branchSubName] Имя ветки указанное пользователем
|
|
12
|
+
*/
|
|
13
|
+
/** @param {import('saby-customizer/lib.js').CardData & GitCardData} data Данные о задаче */
|
|
14
|
+
constructor(data) {
|
|
15
|
+
/** @type {import('saby-customizer/lib.js').CardData & GitCardData} Данные о задаче */
|
|
16
|
+
this.raw = {
|
|
17
|
+
id: data.id,
|
|
18
|
+
number: data.number,
|
|
19
|
+
branchSubName: data.branchSubName || data.number,
|
|
20
|
+
date: data.date,
|
|
21
|
+
name: data.name,
|
|
22
|
+
uuid: data.uuid,
|
|
23
|
+
url: data.url,
|
|
24
|
+
author: data.author,
|
|
25
|
+
milestones: data.milestones,
|
|
26
|
+
version: data.version,
|
|
27
|
+
description: data.description
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** @returns {string} Название регламента Задача/Ошибка и т.д. */
|
|
32
|
+
get name() {
|
|
33
|
+
return this.raw.name
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** @returns {string} Заголовок для описания задачи */
|
|
37
|
+
get branchTitle() {
|
|
38
|
+
const { name } = this.raw
|
|
39
|
+
const docNumber = ' № ' + this.raw.number
|
|
40
|
+
const version = ' веха ' + this.raw.version
|
|
41
|
+
const date = ' от ' + this.raw.date
|
|
42
|
+
const author = ' ' + this.raw.author
|
|
43
|
+
|
|
44
|
+
return name + docNumber + version + date + author
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** @returns {string} Версия задачи (веха), выбранная пользователем */
|
|
48
|
+
get version() {
|
|
49
|
+
return this.raw.version
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Обновление выбранной версии и обновление карточки задачи
|
|
54
|
+
*
|
|
55
|
+
* @param {string} value Версия
|
|
56
|
+
*/
|
|
57
|
+
set version(value) {
|
|
58
|
+
this.raw.version = value || this.raw.version
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** @returns {string} Часть имени ветки, зависящая от регламента задачи */
|
|
62
|
+
get branchType() {
|
|
63
|
+
return this.raw.name === 'Ошибка' ? 'bugfix' : 'feature'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** @returns {string} Часть имени ветки, определяемая пользователем */
|
|
67
|
+
get branchSubName() {
|
|
68
|
+
return this.raw.branchSubName
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Обновление доп. имени ветки и обновление карточки задачи
|
|
73
|
+
*
|
|
74
|
+
* @param {string} value Доп. имя ветки
|
|
75
|
+
*/
|
|
76
|
+
set branchSubName(value) {
|
|
77
|
+
this.raw.branchSubName = value || this.raw.number
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** @returns {string} Краткое описание задачи */
|
|
81
|
+
get description() {
|
|
82
|
+
return this.raw.description
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Обновление краткого описания и карточки задачи
|
|
87
|
+
*
|
|
88
|
+
* @param {string} value Доп. имя ветки
|
|
89
|
+
*/
|
|
90
|
+
set description(value) {
|
|
91
|
+
this.raw.description = value || ''
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** @returns {string[]} Список доступных вех (версий) */
|
|
95
|
+
get milestones() {
|
|
96
|
+
return this.raw.milestones
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** @returns {string} Ссылка на документ в отдельной вкладке */
|
|
100
|
+
get url() {
|
|
101
|
+
return this.raw.url
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Получение имени ветки с учетом выбора вехи и доп. имени ветки
|
|
106
|
+
*
|
|
107
|
+
* @returns {Promise<string>} Имя ветки
|
|
108
|
+
*/
|
|
109
|
+
async getBranchName() {
|
|
110
|
+
const userLogin = await context.userLogin
|
|
111
|
+
|
|
112
|
+
return `${this.version}/${this.branchType}/${userLogin}/${this.branchSubName}`
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Копирование ссылки на задачу */
|
|
116
|
+
copyLink() {
|
|
117
|
+
navigator.clipboard.writeText(this.raw.url)
|
|
118
|
+
snackbar.show(`Скопирована ссылка: ${this.raw.url}`)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Копирование имени ветки */
|
|
122
|
+
async copyBranchName() {
|
|
123
|
+
const branchName = await this.getBranchName()
|
|
124
|
+
|
|
125
|
+
navigator.clipboard.writeText(branchName)
|
|
126
|
+
snackbar.show(`Скопировано имя ветки: ${branchName}`)
|
|
127
|
+
|
|
128
|
+
await this.saveToHistory()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Копирование описания для git commit */
|
|
132
|
+
async copyDescription() {
|
|
133
|
+
const description = this.branchTitle + '\n' +
|
|
134
|
+
this.raw.url + '\n' +
|
|
135
|
+
this.raw.description
|
|
136
|
+
|
|
137
|
+
navigator.clipboard.writeText(description)
|
|
138
|
+
snackbar.show(`Скопировано описание для git commit:\n${description}`)
|
|
139
|
+
|
|
140
|
+
await this.saveToHistory()
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Сохраняет данные в историю по карточкам для которых копировали имя ветки или описание */
|
|
144
|
+
async saveToHistory() {
|
|
145
|
+
const branchName = await this.getBranchName()
|
|
146
|
+
const gitBranchHistory = db.table('gitBranchHistory')
|
|
147
|
+
const historyOldData = await gitBranchHistory.get({
|
|
148
|
+
id: this.raw.id,
|
|
149
|
+
branch: branchName
|
|
150
|
+
})
|
|
151
|
+
const historyData = {
|
|
152
|
+
id: this.raw.id,
|
|
153
|
+
branch: branchName,
|
|
154
|
+
version: this.version,
|
|
155
|
+
useDate: new Date(),
|
|
156
|
+
data: this.raw
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (historyOldData) {
|
|
160
|
+
await gitBranchHistory.update(historyOldData.pk, historyData)
|
|
161
|
+
} else {
|
|
162
|
+
await gitBranchHistory.add(historyData)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Восстановление из истории последнего сохраненного состояния карточки */
|
|
167
|
+
async restoreFromHistory() {
|
|
168
|
+
const gitBranchHistory = db.table('gitBranchHistory')
|
|
169
|
+
const historyData = await gitBranchHistory
|
|
170
|
+
.where({ id: this.raw.id })
|
|
171
|
+
.reverse()
|
|
172
|
+
.sortBy('useDate')
|
|
173
|
+
|
|
174
|
+
if (historyData && historyData.length > 0) {
|
|
175
|
+
const [{ data: { version, branchSubName, description } }] = historyData
|
|
176
|
+
|
|
177
|
+
this.version = version
|
|
178
|
+
this.branchSubName = branchSubName
|
|
179
|
+
this.description = description
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Удаление карточки задачи из истории
|
|
185
|
+
*
|
|
186
|
+
* @param {number} primaryKey Ид записи в истории
|
|
187
|
+
*/
|
|
188
|
+
async removeFromHistory(primaryKey) {
|
|
189
|
+
const gitBranchHistory = db.table('gitBranchHistory')
|
|
190
|
+
|
|
191
|
+
await gitBranchHistory.delete(primaryKey)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
|
|
7
196
|
/** Карточка со сведениями о задаче для копирования ветки */
|
|
8
197
|
class GitBranchCard extends oom.extends(HTMLElement) {
|
|
9
198
|
|
|
10
199
|
static tagName = 'sc-git-branch-сard'
|
|
11
200
|
static style = oom.style({
|
|
12
|
-
'display': '
|
|
201
|
+
'display': 'flex',
|
|
202
|
+
'padding': '12px 12px 0',
|
|
203
|
+
'width': '600px',
|
|
204
|
+
'background': 'var(--mdc-theme-background)',
|
|
205
|
+
'sc-git-branch-сard:last-child': {
|
|
206
|
+
paddingBottom: '12px'
|
|
207
|
+
},
|
|
13
208
|
'.mdc-card': {
|
|
14
|
-
|
|
15
|
-
|
|
209
|
+
padding: '12px',
|
|
210
|
+
minWidth: '0',
|
|
211
|
+
width: '100%'
|
|
16
212
|
},
|
|
17
213
|
'.title': {
|
|
18
|
-
fontWeight: 'bold'
|
|
214
|
+
fontWeight: 'bold',
|
|
215
|
+
fontSize: '18px',
|
|
216
|
+
overflow: 'hidden',
|
|
217
|
+
whiteSpace: 'nowrap',
|
|
218
|
+
textOverflow: 'ellipsis'
|
|
219
|
+
},
|
|
220
|
+
'.history-info': {
|
|
221
|
+
fontSize: '13px',
|
|
222
|
+
fontStyle: 'italic'
|
|
19
223
|
},
|
|
20
224
|
'.link': {
|
|
21
|
-
fontSize: '14px'
|
|
225
|
+
fontSize: '14px',
|
|
226
|
+
color: 'var(--mdc-theme-primary, #6200ee)'
|
|
227
|
+
},
|
|
228
|
+
'.branch-line': {
|
|
229
|
+
display: 'flex',
|
|
230
|
+
alignItems: 'center',
|
|
231
|
+
justifyContent: 'space-between'
|
|
232
|
+
},
|
|
233
|
+
'.branch': {
|
|
234
|
+
display: 'flex',
|
|
235
|
+
alignItems: 'baseline',
|
|
236
|
+
maxWidth: '460px',
|
|
237
|
+
height: '48px'
|
|
238
|
+
},
|
|
239
|
+
'.version-button': {
|
|
240
|
+
borderBottom: '1px dashed',
|
|
241
|
+
cursor: 'pointer',
|
|
242
|
+
marginBottom: '-1px',
|
|
243
|
+
color: 'var(--mdc-theme-primary, #6200ee)'
|
|
244
|
+
},
|
|
245
|
+
'.sub-name-button': {
|
|
246
|
+
borderBottom: '1px dashed',
|
|
247
|
+
marginBottom: '-1px',
|
|
248
|
+
cursor: 'pointer',
|
|
249
|
+
color: 'var(--mdc-theme-primary, #6200ee)',
|
|
250
|
+
whiteSpace: 'nowrap',
|
|
251
|
+
overflow: 'hidden',
|
|
252
|
+
textOverflow: 'ellipsis'
|
|
253
|
+
},
|
|
254
|
+
'.branch-part': {
|
|
255
|
+
padding: '0 2px',
|
|
256
|
+
lineHeight: '48px'
|
|
257
|
+
},
|
|
258
|
+
'.branch-sub-name': {
|
|
259
|
+
height: '48px',
|
|
260
|
+
marginTop: '-1px'
|
|
261
|
+
},
|
|
262
|
+
'.branch-sub-name-version': {
|
|
263
|
+
width: '132px'
|
|
264
|
+
},
|
|
265
|
+
'.actions': {
|
|
266
|
+
display: 'flex',
|
|
267
|
+
marginLeft: '12px'
|
|
268
|
+
},
|
|
269
|
+
'.primary-action': {
|
|
270
|
+
color: 'var(--mdc-theme-primary, #6200ee)'
|
|
271
|
+
},
|
|
272
|
+
'.description-line': {
|
|
273
|
+
display: 'flex'
|
|
22
274
|
},
|
|
23
275
|
'.description': {
|
|
24
276
|
fontSize: '14px',
|
|
25
277
|
whiteSpace: 'nowrap',
|
|
26
278
|
overflow: 'hidden',
|
|
27
|
-
textOverflow: 'ellipsis'
|
|
279
|
+
textOverflow: 'ellipsis',
|
|
280
|
+
flexGrow: '1'
|
|
281
|
+
},
|
|
282
|
+
'.description-textarea': {
|
|
283
|
+
width: '100%'
|
|
284
|
+
},
|
|
285
|
+
'.icon_16': {
|
|
286
|
+
'--mdc-icon-size': '16px',
|
|
287
|
+
'--mdc-icon-button-size': '24px'
|
|
288
|
+
},
|
|
289
|
+
'.icon_18': {
|
|
290
|
+
'--mdc-icon-size': '18px',
|
|
291
|
+
'--mdc-icon-button-size': '24px'
|
|
292
|
+
},
|
|
293
|
+
'.hide': {
|
|
294
|
+
display: 'none'
|
|
28
295
|
}
|
|
29
296
|
})
|
|
30
297
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
298
|
+
/**
|
|
299
|
+
* @param {string} str Текст для подсчета отображаемых строк
|
|
300
|
+
* @returns {string} Количество строк для descriptionTextarea
|
|
301
|
+
*/
|
|
302
|
+
static maxRows(str) {
|
|
303
|
+
const rows = str.split('\n').reduce((rows, subStr) => {
|
|
304
|
+
return rows + (subStr || ' ').match(/.{1,63}/g)?.length
|
|
305
|
+
}, 0)
|
|
306
|
+
|
|
307
|
+
return String(Math.min(Math.max(1, rows), 5))
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
data = new GitBranchCardData(this.options.data)
|
|
311
|
+
versionsList = this.data.milestones.concat(['Произвольная'])
|
|
312
|
+
|
|
313
|
+
elements = {
|
|
314
|
+
/** @type {HTMLSpanElement} */
|
|
315
|
+
cardTitle: oom.span(this.data.branchTitle, { title: this.data.branchTitle }).dom,
|
|
316
|
+
/** @type {import('@material/mwc-icon-button').IconButton} */// @ts-ignore
|
|
317
|
+
copyLinkButton: oom.mwcIconButton({
|
|
318
|
+
title: 'Скопировать ссылку',
|
|
319
|
+
class: 'icon_18',
|
|
320
|
+
innerHTML: octicons.link.toSVG({ width: 18 }),
|
|
321
|
+
onclick: () => this.copyLink()
|
|
322
|
+
}).dom,
|
|
323
|
+
/** @type {import('@material/mwc-icon-button').IconButton} */// @ts-ignore
|
|
324
|
+
descriptionEdit: oom.mwcIconButton({
|
|
325
|
+
title: 'Редактировать описание для git commit',
|
|
326
|
+
class: 'icon_18',
|
|
327
|
+
innerHTML: octicons.pencil.toSVG({ width: 18 }),
|
|
328
|
+
onclick: () => this.editDescription()
|
|
329
|
+
}).dom,
|
|
330
|
+
/** @type {HTMLSpanElement} */
|
|
331
|
+
description: oom.span({
|
|
332
|
+
class: 'description',
|
|
333
|
+
title: this.data.description,
|
|
334
|
+
onclick: () => this.editDescription()
|
|
335
|
+
}, this.data.description).dom,
|
|
336
|
+
/** @type {import('@material/mwc-textarea').TextArea} */// @ts-ignore
|
|
337
|
+
descriptionTextarea: oom.mwcTextarea({
|
|
338
|
+
class: 'description-textarea hide',
|
|
339
|
+
rows: GitBranchCard.maxRows(this.data.description),
|
|
340
|
+
label: 'Описание для git commit',
|
|
341
|
+
value: this.data.description,
|
|
342
|
+
oninput: () => this.oninputDescription()
|
|
343
|
+
}).dom,
|
|
344
|
+
/** @type {import('@material/mwc-menu').Menu} */// @ts-ignore
|
|
345
|
+
versions: this.versionsList.reduce((mwcMenu, item) => {
|
|
346
|
+
return mwcMenu(oom.mwcListItem(item))
|
|
347
|
+
}, oom.mwcMenu({ fixed: true, activatable: true })).dom,
|
|
348
|
+
/** @type {import('@material/mwc-textfield').TextField} */// @ts-ignore
|
|
349
|
+
branchVersionTextfield: oom.mwcTextfield({
|
|
350
|
+
class: 'branch-sub-name branch-sub-name-version hide',
|
|
351
|
+
value: this.data.version,
|
|
352
|
+
placeholder: 'YY.XXXX',
|
|
353
|
+
pattern: '^\\d\\d.\\d\\d\\d\\d$',
|
|
354
|
+
validationmessage: 'Пример: 99.9999',
|
|
355
|
+
oninput: () => this.oninputBranchVersion(),
|
|
356
|
+
onblur: () => this.onblurBranchVersion()
|
|
357
|
+
}).dom,
|
|
358
|
+
/** @type {HTMLDivElement} */// @ts-ignore
|
|
359
|
+
branchButton: oom.div({
|
|
360
|
+
class: 'version-button',
|
|
361
|
+
onclick: () => this.editBranchVersion()
|
|
362
|
+
}, this.data.version).dom,
|
|
363
|
+
/** @type {HTMLSpanElement} */
|
|
364
|
+
branchNamePart: oom.span({
|
|
365
|
+
class: 'branch-part'
|
|
366
|
+
}, `/${this.data.branchType}/***/`).dom,
|
|
367
|
+
/** @type {HTMLSpanElement} */
|
|
368
|
+
branchSubName: oom.span({
|
|
369
|
+
title: this.data.branchSubName,
|
|
370
|
+
class: 'sub-name-button',
|
|
371
|
+
onclick: () => this.editBranchSubName()
|
|
372
|
+
}, this.data.branchSubName).dom,
|
|
373
|
+
/** @type {import('@material/mwc-textfield').TextField} */// @ts-ignore
|
|
374
|
+
branchSubNameTextfield: oom.mwcTextfield({
|
|
375
|
+
class: 'branch-sub-name hide',
|
|
376
|
+
value: this.data.branchSubName,
|
|
377
|
+
placeholder: this.data.branchSubName,
|
|
378
|
+
pattern: '^\\w+[\\w()-]*$',
|
|
379
|
+
validationmessage: 'Латинские буквы, цифры и _()-',
|
|
380
|
+
oninput: () => this.oninputBranchSubName(),
|
|
381
|
+
onblur: () => this.onblurBranchSubName()
|
|
382
|
+
}).dom,
|
|
383
|
+
/** @type {import('@material/mwc-icon-button').IconButton} */// @ts-ignore
|
|
384
|
+
copyBranchButton: oom.mwcIconButton({
|
|
385
|
+
title: 'Скопировать имя ветки',
|
|
386
|
+
class: 'primary-action',
|
|
387
|
+
innerHTML: octicons['git-branch'].toSVG({ width: 24 }),
|
|
388
|
+
onclick: () => this.copyBranchName().catch(console.error)
|
|
389
|
+
}).dom,
|
|
390
|
+
/** @type {import('@material/mwc-icon-button').IconButton} */// @ts-ignore
|
|
391
|
+
copyDescriptionButton: oom.mwcIconButton({
|
|
392
|
+
title: 'Скопировать описание',
|
|
393
|
+
innerHTML: octicons.copy.toSVG({ width: 24 }),
|
|
394
|
+
onclick: () => this.copyDescription().catch(console.error)
|
|
395
|
+
}).dom
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/** @returns {string} Версия задачи (веха), выбранная пользователем */
|
|
399
|
+
get version() {
|
|
400
|
+
return this.data.version
|
|
401
|
+
}
|
|
38
402
|
|
|
39
403
|
/**
|
|
40
|
-
*
|
|
404
|
+
* Обновление выбранной версии и обновление карточки задачи
|
|
405
|
+
*
|
|
406
|
+
* @param {string} value Версия
|
|
41
407
|
*/
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
408
|
+
set version(value) {
|
|
409
|
+
this.data.version = value
|
|
410
|
+
if (this.data.version === value) {
|
|
411
|
+
this.elements.branchButton.textContent = this.data.version
|
|
412
|
+
this.elements.branchVersionTextfield.value = this.data.version
|
|
413
|
+
this.elements.cardTitle.textContent = this.data.branchTitle
|
|
414
|
+
}
|
|
415
|
+
}
|
|
48
416
|
|
|
49
|
-
|
|
417
|
+
/** @returns {string} Часть имени ветки, определяемая пользователем */
|
|
418
|
+
get branchSubName() {
|
|
419
|
+
return this.data.branchSubName
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Обновление доп. имени ветки и обновление карточки задачи
|
|
424
|
+
*
|
|
425
|
+
* @param {string} value Доп. имя ветки
|
|
426
|
+
*/
|
|
427
|
+
set branchSubName(value) {
|
|
428
|
+
this.data.branchSubName = value
|
|
429
|
+
oom(this.elements.branchSubName, { innerHTML: '', title: this.data.branchSubName }, this.data.branchSubName)
|
|
430
|
+
if (this.elements.branchSubNameTextfield.value !== this.data.branchSubName) {
|
|
431
|
+
this.elements.branchSubNameTextfield.value = this.data.branchSubName
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/** @returns {string} Краткое описание задачи */
|
|
436
|
+
get description() {
|
|
437
|
+
return this.data.description
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Обновление краткого описания и карточки задачи
|
|
442
|
+
*
|
|
443
|
+
* @param {string} value Доп. имя ветки
|
|
444
|
+
*/
|
|
445
|
+
set description(value) {
|
|
446
|
+
this.data.description = value
|
|
447
|
+
this.elements.description.title = this.data.description
|
|
448
|
+
this.elements.description.textContent = this.data.description
|
|
449
|
+
if (this.elements.descriptionTextarea.value !== this.data.description) {
|
|
450
|
+
this.elements.descriptionTextarea.value = this.data.description
|
|
451
|
+
}
|
|
452
|
+
oom(this.elements.descriptionTextarea, { rows: GitBranchCard.maxRows(this.data.description) })
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
template = () => {
|
|
456
|
+
this.elements.versions.anchor = this.elements.branchButton
|
|
457
|
+
this.elements.versions.addEventListener('selected', (/** @type {CustomEvent<import('@material/mwc-list/mwc-list-foundation').ActionDetail>} */event) => {
|
|
458
|
+
this.selectedVersion(event.detail.index)
|
|
459
|
+
})
|
|
460
|
+
|
|
461
|
+
this.updateBranchNamePart().catch(console.error)
|
|
462
|
+
|
|
463
|
+
const cardElement = oom.div({ class: 'mdc-card' }, oom
|
|
464
|
+
.div({ class: 'title' }, this.elements.cardTitle))
|
|
465
|
+
|
|
466
|
+
if (this.options.pk) {
|
|
467
|
+
// Добавим элементы для карточки задачи из истории
|
|
468
|
+
const useDate = this.options.useDate.toLocaleString()
|
|
469
|
+
|
|
470
|
+
cardElement(oom.div(oom
|
|
471
|
+
.span({ class: 'history-info' }, `Скопировано: ${useDate}`)
|
|
472
|
+
.mwcIconButton({
|
|
473
|
+
title: 'Удалить из истории',
|
|
474
|
+
class: 'icon_16',
|
|
475
|
+
innerHTML: octicons.x.toSVG({ width: 16 }),
|
|
476
|
+
onclick: () => {
|
|
477
|
+
/** @type {GitBranchCardList} */// @ts-ignore
|
|
478
|
+
const cardList = this.parentElement.parentElement
|
|
479
|
+
|
|
480
|
+
this.remove()
|
|
481
|
+
this.data.removeFromHistory(this.options.pk)
|
|
482
|
+
.then(() => cardList.buildHistoryList())
|
|
483
|
+
.catch(console.error)
|
|
484
|
+
}
|
|
485
|
+
})))
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
return cardElement(oom
|
|
489
|
+
.div(oom
|
|
490
|
+
.a({ class: 'link' }, this.data.url, {
|
|
491
|
+
target: '_blank',
|
|
492
|
+
href: this.data.url
|
|
493
|
+
}), this.elements.copyLinkButton)
|
|
494
|
+
.div({
|
|
495
|
+
class: 'description-line'
|
|
496
|
+
}, this.elements.descriptionEdit, this.elements.description, this.elements.descriptionTextarea)
|
|
497
|
+
.div({ class: 'branch-line' }, oom
|
|
498
|
+
.div({ class: 'branch' },
|
|
499
|
+
this.elements.branchButton,
|
|
500
|
+
this.elements.versions,
|
|
501
|
+
this.elements.branchVersionTextfield,
|
|
502
|
+
this.elements.branchNamePart,
|
|
503
|
+
this.elements.branchSubName,
|
|
504
|
+
this.elements.branchSubNameTextfield)
|
|
505
|
+
.div({ class: 'actions' }, this.elements.copyBranchButton, this.elements.copyDescriptionButton)
|
|
506
|
+
)
|
|
507
|
+
)
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/** Обновляет имя ветки после получения данных пользователя */
|
|
511
|
+
async updateBranchNamePart() {
|
|
512
|
+
const userLogin = await context.userLogin
|
|
513
|
+
|
|
514
|
+
this.elements.branchNamePart.textContent = `/${this.data.branchType}/${userLogin}/`
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/** Открывает форму редактирования редактирование описания для коммита */
|
|
518
|
+
editDescription() {
|
|
519
|
+
this.elements.descriptionEdit.classList.toggle('hide')
|
|
520
|
+
this.elements.description.classList.toggle('hide')
|
|
521
|
+
this.elements.descriptionTextarea.classList.toggle('hide')
|
|
522
|
+
this.elements.descriptionTextarea.focus()
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/** Обработка события при вводе текста в описание для расчета отображаемого кол-ва строк */
|
|
526
|
+
oninputDescription() {
|
|
527
|
+
this.description = this.elements.descriptionTextarea.value
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Обработчик выбора версии из меню
|
|
532
|
+
*
|
|
533
|
+
* @param {number} index Выбранная в меню позиция
|
|
534
|
+
*/
|
|
535
|
+
selectedVersion(index) {
|
|
536
|
+
const version = this.versionsList[index]
|
|
537
|
+
|
|
538
|
+
if (version === 'Произвольная') {
|
|
539
|
+
this.elements.branchVersionTextfield.classList.toggle('hide')
|
|
540
|
+
this.elements.branchButton.classList.toggle('hide')
|
|
541
|
+
this.elements.branchVersionTextfield.focus()
|
|
542
|
+
this.elements.branchVersionTextfield.select()
|
|
543
|
+
} else {
|
|
544
|
+
this.version = version
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/** Открывает форму редактирования версии ветки */
|
|
549
|
+
editBranchVersion() {
|
|
550
|
+
if (this.data.milestones.length === 0) {
|
|
551
|
+
this.elements.branchVersionTextfield.classList.toggle('hide')
|
|
552
|
+
this.elements.branchButton.classList.toggle('hide')
|
|
553
|
+
this.elements.branchVersionTextfield.focus()
|
|
554
|
+
this.elements.branchVersionTextfield.select()
|
|
555
|
+
} else {
|
|
556
|
+
this.elements.versions.open = true
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/** Сохранение данных о версии ветки при вводе */
|
|
561
|
+
oninputBranchVersion() {
|
|
562
|
+
if (this.elements.branchVersionTextfield.checkValidity()) {
|
|
563
|
+
this.version = this.elements.branchVersionTextfield.value
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/** Скрывает поле ввода версии ветки при потере фокуса */
|
|
568
|
+
onblurBranchVersion() {
|
|
569
|
+
if (this.elements.branchVersionTextfield.checkValidity()) {
|
|
570
|
+
this.elements.branchVersionTextfield.classList.toggle('hide')
|
|
571
|
+
this.elements.branchButton.classList.toggle('hide')
|
|
572
|
+
this.version = this.elements.branchVersionTextfield.value
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/** Открывает форму редактирования доп. имени ветки */
|
|
577
|
+
editBranchSubName() {
|
|
578
|
+
this.elements.branchSubName.classList.toggle('hide')
|
|
579
|
+
this.elements.branchSubNameTextfield.classList.toggle('hide')
|
|
580
|
+
this.elements.branchSubNameTextfield.focus()
|
|
581
|
+
this.elements.branchSubNameTextfield.select()
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/** Сохранение данных о доп. имени ветки при вводе */
|
|
585
|
+
oninputBranchSubName() {
|
|
586
|
+
if (this.elements.branchSubNameTextfield.checkValidity()) {
|
|
587
|
+
this.branchSubName = this.elements.branchSubNameTextfield.value
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/** Скрывает поле ввода доп. имени ветки при потере фокуса */
|
|
592
|
+
onblurBranchSubName() {
|
|
593
|
+
if (this.elements.branchSubNameTextfield.checkValidity()) {
|
|
594
|
+
this.elements.branchSubName.classList.toggle('hide')
|
|
595
|
+
this.elements.branchSubNameTextfield.classList.toggle('hide')
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/** Копирование ссылки на задачу */
|
|
600
|
+
copyLink() {
|
|
601
|
+
this.data.copyLink()
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/** Копирование имени ветки */
|
|
605
|
+
async copyBranchName() {
|
|
606
|
+
const valid = this.elements.branchSubNameTextfield.checkValidity() &&
|
|
607
|
+
this.elements.branchVersionTextfield.checkValidity()
|
|
608
|
+
|
|
609
|
+
if (valid) {
|
|
610
|
+
await this.data.copyBranchName()
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/** Копирование описания для git commit */
|
|
615
|
+
async copyDescription() {
|
|
616
|
+
const valid = this.elements.branchSubNameTextfield.checkValidity() &&
|
|
617
|
+
this.elements.branchVersionTextfield.checkValidity()
|
|
618
|
+
|
|
619
|
+
if (valid) {
|
|
620
|
+
await this.data.copyDescription()
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/** Восстановление из истории последнего сохраненного состояния карточки */
|
|
625
|
+
async restoreFromHistory() {
|
|
626
|
+
await this.data.restoreFromHistory()
|
|
627
|
+
this.version = this.data.version
|
|
628
|
+
this.branchSubName = this.data.branchSubName
|
|
629
|
+
this.description = this.data.description
|
|
50
630
|
}
|
|
51
631
|
|
|
52
632
|
}
|
|
@@ -59,35 +639,185 @@ class GitBranchCardList extends oom.extends(HTMLElement) {
|
|
|
59
639
|
static style = oom.style({
|
|
60
640
|
'display': 'contents',
|
|
61
641
|
'.empty': {
|
|
62
|
-
padding: '
|
|
642
|
+
padding: '50px',
|
|
63
643
|
textAlign: 'center'
|
|
644
|
+
},
|
|
645
|
+
'.content': {
|
|
646
|
+
flexGrow: '1',
|
|
647
|
+
overflowY: 'auto',
|
|
648
|
+
overflowX: 'hidden',
|
|
649
|
+
maxHeight: 'calc(var(--mdc-dialog-max-height) - 100px)',
|
|
650
|
+
background: 'var(--mdc-theme-background)'
|
|
651
|
+
},
|
|
652
|
+
'.hide': {
|
|
653
|
+
display: 'none'
|
|
654
|
+
},
|
|
655
|
+
'.nav-buttons': {
|
|
656
|
+
display: 'flex',
|
|
657
|
+
justifyContent: 'space-between',
|
|
658
|
+
alignItems: 'center',
|
|
659
|
+
padding: '4px 4px 0px',
|
|
660
|
+
height: '36px'
|
|
661
|
+
},
|
|
662
|
+
'.nav-buttons-space': {
|
|
663
|
+
width: '64px'
|
|
664
|
+
},
|
|
665
|
+
'.nav-buttons-page-label': {
|
|
666
|
+
userSelect: 'none'
|
|
64
667
|
}
|
|
65
668
|
})
|
|
66
669
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
670
|
+
tabs = oom
|
|
671
|
+
.mwcTabBar(oom
|
|
672
|
+
.mwcTab({ label: 'Открытые задачи' })
|
|
673
|
+
// .mwcTab({ label: 'Список задач' })
|
|
674
|
+
.mwcTab({ label: 'История задач' }))
|
|
675
|
+
|
|
676
|
+
openTaskList = oom.div({ class: 'content' }, oom.div({ class: 'empty' }, 'Загрузка ...'))
|
|
677
|
+
historyTaskList = oom.div({ class: 'content hide' })
|
|
72
678
|
|
|
73
|
-
|
|
74
|
-
|
|
679
|
+
// Параметры навигации по истории
|
|
680
|
+
historyListPage = 0
|
|
681
|
+
historyListLimit = 3
|
|
75
682
|
|
|
76
|
-
template =
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
683
|
+
template = async () => {
|
|
684
|
+
// if (this.openTaskList.length === 0) {
|
|
685
|
+
// this.tabs({ activeindex: '1' })
|
|
686
|
+
// }
|
|
687
|
+
oom(this, this.tabs, this.openTaskList, this.historyTaskList)
|
|
688
|
+
|
|
689
|
+
this.tabs.dom.addEventListener('MDCTabBar:activated', (/** @type {CustomEvent<import('@material/mwc-list/mwc-list-foundation').ActionDetail>} */event) => {
|
|
690
|
+
switch (event.detail.index) {
|
|
691
|
+
case 0:
|
|
692
|
+
this.historyTaskList({ innerHTML: '' })
|
|
693
|
+
this.historyTaskList.dom.classList.add('hide')
|
|
694
|
+
this.openTaskList.dom.classList.remove('hide')
|
|
695
|
+
break
|
|
696
|
+
case 1:
|
|
697
|
+
this.historyTaskList({ innerHTML: '' }, oom.div({ class: 'empty' }, 'Загрузка ...'))
|
|
698
|
+
this.openTaskList.dom.classList.add('hide')
|
|
699
|
+
this.historyTaskList.dom.classList.remove('hide')
|
|
700
|
+
this.historyListPage = 0
|
|
701
|
+
this.historyListLimit = 3
|
|
702
|
+
this.buildHistoryList().catch(console.error)
|
|
703
|
+
break
|
|
704
|
+
}
|
|
705
|
+
})
|
|
706
|
+
|
|
707
|
+
this.openTaskList({ innerHTML: '' }, await this.buildTaskList())
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/** @returns {Promise<HTMLElement|DocumentFragment>} Вернет готовый список задач с учетом аинхронной загрузки данных */
|
|
711
|
+
async buildTaskList() {
|
|
712
|
+
let taskTist = null
|
|
713
|
+
const openTaskList = (await getListOfOpenCards({
|
|
714
|
+
names: ['Ошибка', 'Задача']
|
|
715
|
+
})).map(card => new GitBranchCard(card))
|
|
716
|
+
|
|
717
|
+
await Promise.all(openTaskList.map(card => card.restoreFromHistory()))
|
|
718
|
+
|
|
719
|
+
if (openTaskList.length > 0) {
|
|
720
|
+
taskTist = oom()(...openTaskList)
|
|
721
|
+
} else {
|
|
722
|
+
taskTist = oom.div({ class: 'empty' }, 'Открытых задач не найдено')
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
return taskTist.dom
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/** Строит компонент списка истории задач */
|
|
729
|
+
async buildHistoryList() {
|
|
730
|
+
const offset = this.historyListPage * this.historyListLimit
|
|
731
|
+
const navButtons = oom.div({ class: 'nav-buttons' })
|
|
732
|
+
const gitBranchHistory = db.table('gitBranchHistory')
|
|
733
|
+
const historyData = await gitBranchHistory
|
|
734
|
+
.orderBy('useDate')
|
|
735
|
+
.reverse()
|
|
736
|
+
.offset(offset)
|
|
737
|
+
.limit(this.historyListLimit + 1)
|
|
738
|
+
.toArray()
|
|
739
|
+
|
|
740
|
+
if (historyData.length > 0) {
|
|
741
|
+
const totalCount = await gitBranchHistory.count()
|
|
742
|
+
const currentSize = offset + Math.min(this.historyListLimit, historyData.length)
|
|
743
|
+
|
|
744
|
+
if (this.historyListPage > 0) {
|
|
745
|
+
navButtons(oom.mwcButton({
|
|
746
|
+
innerHTML: octicons['arrow-left'].toSVG({ width: 24 }),
|
|
747
|
+
onclick: () => {
|
|
748
|
+
--this.historyListPage
|
|
749
|
+
this.buildHistoryList().catch(console.error)
|
|
750
|
+
}
|
|
751
|
+
}))
|
|
752
|
+
} else {
|
|
753
|
+
navButtons(oom.span({ class: 'nav-buttons-space' }))
|
|
754
|
+
}
|
|
755
|
+
navButtons(oom.span(`${offset + 1} - ${currentSize} / ${totalCount}`, {
|
|
756
|
+
class: 'nav-buttons-page-label'
|
|
757
|
+
}))
|
|
758
|
+
if (historyData.length > this.historyListLimit) {
|
|
759
|
+
historyData.pop()
|
|
760
|
+
navButtons(oom.mwcButton({
|
|
761
|
+
innerHTML: octicons['arrow-right'].toSVG({ width: 24 }),
|
|
762
|
+
onclick: () => {
|
|
763
|
+
++this.historyListPage
|
|
764
|
+
this.buildHistoryList().catch(console.error)
|
|
765
|
+
}
|
|
766
|
+
}))
|
|
767
|
+
} else {
|
|
768
|
+
navButtons(oom.span({ class: 'nav-buttons-space' }))
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
this.historyTaskList({ innerHTML: '' }, navButtons, ...historyData.map(card => new GitBranchCard(card)))
|
|
772
|
+
} else if (this.historyListPage > 0) {
|
|
773
|
+
--this.historyListPage
|
|
774
|
+
this.buildHistoryList().catch(console.error)
|
|
775
|
+
} else {
|
|
776
|
+
this.historyTaskList({ innerHTML: '' }, oom.div({ class: 'empty' }, 'Задач в истории не найдено'))
|
|
777
|
+
}
|
|
778
|
+
}
|
|
83
779
|
|
|
84
780
|
}
|
|
85
781
|
|
|
86
782
|
|
|
87
783
|
oom.define(GitBranchCard, GitBranchCardList)
|
|
88
784
|
|
|
89
|
-
keysMapping['alt-KeyB'] = () =>
|
|
785
|
+
keysMapping['alt-KeyB'] = () => PopupDialog.toggle({
|
|
90
786
|
key: 'git-branch-dialog',
|
|
91
787
|
title: 'Ветки для Git',
|
|
92
788
|
Element: GitBranchCardList
|
|
93
789
|
})
|
|
790
|
+
|
|
791
|
+
toolbar.addButton({
|
|
792
|
+
position: 'right',
|
|
793
|
+
title: 'Ветки для Git',
|
|
794
|
+
iconSVG: octicons['git-branch'].toSVG({ width: 24 }),
|
|
795
|
+
onclick: keysMapping['alt-KeyB']
|
|
796
|
+
})
|
|
797
|
+
|
|
798
|
+
toolbar.addButton({
|
|
799
|
+
position: 'top',
|
|
800
|
+
filter: { names: ['Ошибка', 'Задача'] },
|
|
801
|
+
title: 'Скопировать имя ветки для Git',
|
|
802
|
+
iconSVG: octicons['git-branch'].toSVG({ width: 18 }),
|
|
803
|
+
onclick: card => {
|
|
804
|
+
const gitCard = new GitBranchCardData(card.data)
|
|
805
|
+
|
|
806
|
+
gitCard.restoreFromHistory()
|
|
807
|
+
.then(() => gitCard.copyBranchName())
|
|
808
|
+
.catch(console.error)
|
|
809
|
+
}
|
|
810
|
+
})
|
|
811
|
+
toolbar.addButton({
|
|
812
|
+
position: 'top',
|
|
813
|
+
filter: { names: ['Ошибка', 'Задача'] },
|
|
814
|
+
title: 'Скопировать описание для Git коммита',
|
|
815
|
+
iconSVG: octicons['git-commit'].toSVG({ width: 18 }),
|
|
816
|
+
onclick: card => {
|
|
817
|
+
const gitCard = new GitBranchCardData(card.data)
|
|
818
|
+
|
|
819
|
+
gitCard.restoreFromHistory()
|
|
820
|
+
.then(() => gitCard.copyDescription())
|
|
821
|
+
.catch(console.error)
|
|
822
|
+
}
|
|
823
|
+
})
|