saby-customizer 0.0.0-pre.19 → 0.0.0-pre.23

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.
@@ -1,5 +1,5 @@
1
1
  import { oom } from '@notml/core'
2
- import { keysMapping, rightSidebar, PopupDialog, getListOfOpenCards, snackbar, context } from 'saby-customizer/lib.js'
2
+ import { keysMapping, toolbar, PopupDialog, getListOfOpenCards, snackbar, context, db } from 'saby-customizer/lib.js'
3
3
  import { octicons } from 'saby-customizer/octicons.js'
4
4
 
5
5
 
@@ -78,7 +78,8 @@ class GitBranchCard extends oom.extends(HTMLElement) {
78
78
  fontSize: '14px',
79
79
  whiteSpace: 'nowrap',
80
80
  overflow: 'hidden',
81
- textOverflow: 'ellipsis'
81
+ textOverflow: 'ellipsis',
82
+ flexGrow: '1'
82
83
  },
83
84
  '.description-textarea': {
84
85
  width: '100%'
@@ -104,130 +105,198 @@ class GitBranchCard extends oom.extends(HTMLElement) {
104
105
  return String(Math.min(Math.max(1, rows), 5))
105
106
  }
106
107
 
107
- url = this.options.data.url
108
- version = this.options.data.version
109
- milestones = this.options.data.milestones
110
- branchType = this.options.data.name === 'Ошибка' ? 'bugfix' : 'feature'
111
-
112
- cardTitle = oom.span(this.getTitle(), { title: this.getTitle() }).dom
113
-
114
- copyLinkButton = oom.mwcIconButton({
115
- title: 'Скопировать ссылку',
116
- class: 'icon_18',
117
- innerHTML: octicons.link.toSVG({ width: 18 }),
118
- onclick: () => this.copyLink()
119
- }).dom
120
-
121
- descriptionEdit = oom.mwcIconButton({
122
- title: 'Редактировать описание для git commit',
123
- class: 'icon_18',
124
- innerHTML: octicons.pencil.toSVG({ width: 18 }),
125
- onclick: () => this.editDescription()
126
- }).dom
127
-
128
- description = oom.span({
129
- class: 'description',
130
- title: this.options.data.description,
131
- onclick: () => this.editDescription()
132
- }, this.options.data.description).dom
133
-
134
- /** @type {HTMLTextAreaElement} */// @ts-ignore
135
- descriptionTextarea = oom.mwcTextarea({
136
- class: 'description-textarea hide',
137
- rows: GitBranchCard.maxRows(this.options.data.description),
138
- label: 'Описание для git commit',
139
- value: this.options.data.description,
140
- oninput: () => {
141
- this.descriptionTextarea.setAttribute('rows', GitBranchCard.maxRows(this.descriptionTextarea.value))
142
- }
143
- }).dom
108
+ /**
109
+ * @typedef GitCardData
110
+ * @property {string} [branchSubName] Имя ветки указанное пользователем
111
+ */
112
+ /** @type {import('saby-customizer/lib.js').CardData & GitCardData} Данные о задаче */
113
+ data = {
114
+ id: this.options.data.id,
115
+ number: this.options.data.number,
116
+ branchSubName: this.options.data.branchSubName || this.options.data.number,
117
+ date: this.options.data.date,
118
+ name: this.options.data.name,
119
+ uuid: this.options.data.uuid,
120
+ url: this.options.data.url,
121
+ author: this.options.data.author,
122
+ milestones: this.options.data.milestones,
123
+ version: this.options.data.version,
124
+ description: this.options.data.description
125
+ }
144
126
 
145
- versions = this.milestones.reduce((mwcMenu, item) => {
146
- mwcMenu(oom.mwcListItem(item))
127
+ elements = {
128
+ /** @type {HTMLSpanElement} */
129
+ cardTitle: oom.span(this.branchTitle, { title: this.branchTitle }).dom,
130
+ /** @type {import('@material/mwc-icon-button').IconButton} */// @ts-ignore
131
+ copyLinkButton: oom.mwcIconButton({
132
+ title: 'Скопировать ссылку',
133
+ class: 'icon_18',
134
+ innerHTML: octicons.link.toSVG({ width: 18 }),
135
+ onclick: () => this.copyLink()
136
+ }).dom,
137
+ /** @type {import('@material/mwc-icon-button').IconButton} */// @ts-ignore
138
+ descriptionEdit: oom.mwcIconButton({
139
+ title: 'Редактировать описание для git commit',
140
+ class: 'icon_18',
141
+ innerHTML: octicons.pencil.toSVG({ width: 18 }),
142
+ onclick: () => this.editDescription()
143
+ }).dom,
144
+ /** @type {HTMLSpanElement} */
145
+ description: oom.span({
146
+ class: 'description',
147
+ title: this.data.description,
148
+ onclick: () => this.editDescription()
149
+ }, this.data.description).dom,
150
+ /** @type {import('@material/mwc-textarea').TextArea} */// @ts-ignore
151
+ descriptionTextarea: oom.mwcTextarea({
152
+ class: 'description-textarea hide',
153
+ rows: GitBranchCard.maxRows(this.data.description),
154
+ label: 'Описание для git commit',
155
+ value: this.data.description,
156
+ oninput: () => this.oninputDescription()
157
+ }).dom,
158
+ /** @type {import('@material/mwc-menu').Menu} */// @ts-ignore
159
+ versions: this.data.milestones.reduce((mwcMenu, item) => {
160
+ return mwcMenu(oom.mwcListItem(item))
161
+ }, oom.mwcMenu({ fixed: true, activatable: true })).dom,
162
+ /** @type {HTMLDivElement} */// @ts-ignore
163
+ branchButton: oom.div({
164
+ class: 'version-button',
165
+ onclick: () => { this.elements.versions.open = true }
166
+ }, this.data.version).dom,
167
+ /** @type {HTMLSpanElement} */
168
+ branchNamePart: oom.span({
169
+ class: 'branch-part'
170
+ }, `/${this.branchType}/***/`).dom,
171
+ /** @type {HTMLSpanElement} */
172
+ branchSubName: oom.span({
173
+ title: this.data.branchSubName,
174
+ class: 'sub-name-button',
175
+ onclick: () => this.editBranchSubName()
176
+ }, this.data.branchSubName).dom,
177
+ /** @type {import('@material/mwc-textfield').TextField} */// @ts-ignore
178
+ branchSubNameTextfield: oom.mwcTextfield({
179
+ class: 'branch-sub-name hide',
180
+ value: this.data.branchSubName,
181
+ placeholder: this.data.branchSubName,
182
+ pattern: '^\\w+[\\w()-]*$',
183
+ validationmessage: 'Латинские буквы, цифры и _()-',
184
+ oninput: () => this.oninputBranchSubName(),
185
+ onblur: () => this.onblurBranchSubName()
186
+ }).dom,
187
+ /** @type {import('@material/mwc-icon-button').IconButton} */// @ts-ignore
188
+ copyBranchButton: oom.mwcIconButton({
189
+ title: 'Скопировать имя ветки',
190
+ class: 'primary-action',
191
+ innerHTML: octicons['git-branch'].toSVG({ width: 24 }),
192
+ onclick: () => this.copyBranchName().catch(console.error)
193
+ }).dom,
194
+ /** @type {import('@material/mwc-icon-button').IconButton} */// @ts-ignore
195
+ copyDescriptionButton: oom.mwcIconButton({
196
+ title: 'Скопировать описание',
197
+ innerHTML: octicons.copy.toSVG({ width: 24 }),
198
+ onclick: () => this.copyDescription().catch(console.error)
199
+ }).dom
200
+ }
147
201
 
148
- return mwcMenu
149
- }, oom.mwcMenu({ fixed: true, activatable: true })).dom
202
+ /** @returns {string} Заголовок для описания задачи */
203
+ get branchTitle() {
204
+ const { name } = this.data
205
+ const docNumber = ' № ' + this.data.number
206
+ const version = ' веха ' + this.version
207
+ const date = ' от ' + this.data.date
208
+ const author = ' ' + this.data.author
150
209
 
151
- branchButton = oom.div({
152
- class: 'version-button',
153
- onclick: () => {
154
- this.versions.open = true
155
- }
156
- }, this.version).dom
157
-
158
- branchNamePart = oom.span({
159
- class: 'branch-part'
160
- }, `/${this.branchType}/***/`).dom
161
-
162
- branchSubName = oom.span({
163
- title: this.options.data.number,
164
- class: 'sub-name-button',
165
- onclick: () => {
166
- this.branchSubName.classList.toggle('hide')
167
- this.branchSubNameTextfield.classList.toggle('hide')
168
- this.branchSubNameTextfield.focus()
169
- this.branchSubNameTextfield.select()
210
+ return name + docNumber + version + date + author
211
+ }
212
+
213
+ /** @returns {string} Версия задачи (веха), выбранная пользователем */
214
+ get version() {
215
+ return this.data.version
216
+ }
217
+
218
+ /**
219
+ * Обновление выбранной версии и обновление карточки задачи
220
+ *
221
+ * @param {string} value Версия
222
+ */
223
+ set version(value) {
224
+ if (this.data.milestones && this.data.milestones.includes(value)) {
225
+ this.data.version = value
226
+ this.elements.branchButton.textContent = this.data.version
227
+ this.elements.cardTitle.textContent = this.branchTitle
170
228
  }
171
- }, this.options.data.number).dom
172
-
173
- /** @type {import('@material/mwc-textfield').TextField} */// @ts-ignore
174
- branchSubNameTextfield = oom.mwcTextfield({
175
- class: 'branch-sub-name hide',
176
- value: this.options.data.number,
177
- placeholder: this.options.data.number,
178
- pattern: '^\\w+$',
179
- validationmessage: 'Латинские буквы и цифры',
180
- onblur: (/** @type {{target:import('@material/mwc-textfield').TextField}} */{ target }) => {
181
- if (target.checkValidity()) {
182
- this.branchSubName.textContent = target.value || this.options.data.number
183
- this.branchSubName.title = this.branchSubName.textContent
184
- this.branchSubName.classList.toggle('hide')
185
- this.branchSubNameTextfield.classList.toggle('hide')
186
- }
229
+ }
230
+
231
+ /** @returns {string} Часть имени ветки, зависящая от регламента задачи */
232
+ get branchType() {
233
+ return this.data.name === 'Ошибка' ? 'bugfix' : 'feature'
234
+ }
235
+
236
+ /** @returns {string} Часть имени ветки, определяемая пользователем */
237
+ get branchSubName() {
238
+ return this.data.branchSubName
239
+ }
240
+
241
+ /**
242
+ * Обновление доп. имени ветки и обновление карточки задачи
243
+ *
244
+ * @param {string} value Доп. имя ветки
245
+ */
246
+ set branchSubName(value) {
247
+ this.data.branchSubName = value || this.data.number
248
+ oom(this.elements.branchSubName, { innerHTML: '', title: this.data.branchSubName }, this.data.branchSubName)
249
+ if (this.elements.branchSubNameTextfield.value !== this.data.branchSubName) {
250
+ this.elements.branchSubNameTextfield.value = this.data.branchSubName
187
251
  }
188
- }).dom
252
+ }
189
253
 
190
- copyBranchButton = oom.mwcIconButton({
191
- title: 'Скопировать имя ветки',
192
- class: 'primary-action',
193
- innerHTML: octicons['git-branch'].toSVG({ width: 24 }),
194
- onclick: () => this.copyBranchName().catch(console.error)
195
- }).dom
254
+ /** @returns {string} Краткое описание задачи */
255
+ get description() {
256
+ return this.data.description
257
+ }
196
258
 
197
- copyDescriptionButton = oom.mwcIconButton({
198
- title: 'Скопировать описание',
199
- innerHTML: octicons.copy.toSVG({ width: 24 }),
200
- onclick: () => this.copyDescription()
201
- }).dom
259
+ /**
260
+ * Обновление краткого описания и карточки задачи
261
+ *
262
+ * @param {string} value Доп. имя ветки
263
+ */
264
+ set description(value) {
265
+ this.data.description = value || ''
266
+ this.elements.description.title = this.data.description
267
+ this.elements.description.textContent = this.data.description
268
+ if (this.elements.descriptionTextarea.value !== this.data.description) {
269
+ this.elements.descriptionTextarea.value = this.data.description
270
+ }
271
+ oom(this.elements.descriptionTextarea, { rows: GitBranchCard.maxRows(this.data.description) })
272
+ }
202
273
 
203
274
  template = () => {
204
- this.versions.anchor = this.branchButton
205
- this.versions.addEventListener('selected', (event) => {
206
- this.version = this.milestones[event.detail.index]
207
- this.cardTitle.textContent = this.getTitle()
208
- this.branchButton.textContent = this.version
275
+ this.elements.versions.anchor = this.elements.branchButton
276
+ this.elements.versions.addEventListener('selected', (/** @type {CustomEvent<import('@material/mwc-list/mwc-list-foundation').ActionDetail>} */event) => {
277
+ this.version = this.data.milestones[event.detail.index]
209
278
  })
210
279
 
211
280
  this.updateBranchNamePart().catch(console.error)
212
281
 
213
282
  return oom.div({ class: 'mdc-card' }, oom
214
- .div({ class: 'title' }, this.cardTitle)
283
+ .div({ class: 'title' }, this.elements.cardTitle)
215
284
  .div(oom
216
- .a({ class: 'link' }, this.url, {
285
+ .a({ class: 'link' }, this.data.url, {
217
286
  target: '_blank',
218
- href: this.url
219
- }), this.copyLinkButton)
287
+ href: this.data.url
288
+ }), this.elements.copyLinkButton)
220
289
  .div({
221
290
  class: 'description-line'
222
- }, this.descriptionEdit, this.description, this.descriptionTextarea)
291
+ }, this.elements.descriptionEdit, this.elements.description, this.elements.descriptionTextarea)
223
292
  .div({ class: 'branch-line' }, oom
224
293
  .div({ class: 'branch' },
225
- this.branchButton,
226
- this.versions,
227
- this.branchNamePart,
228
- this.branchSubName,
229
- this.branchSubNameTextfield)
230
- .div({ class: 'actions' }, this.copyBranchButton, this.copyDescriptionButton)
294
+ this.elements.branchButton,
295
+ this.elements.versions,
296
+ this.elements.branchNamePart,
297
+ this.elements.branchSubName,
298
+ this.elements.branchSubNameTextfield)
299
+ .div({ class: 'actions' }, this.elements.copyBranchButton, this.elements.copyDescriptionButton)
231
300
  )
232
301
  )
233
302
  }
@@ -236,64 +305,124 @@ class GitBranchCard extends oom.extends(HTMLElement) {
236
305
  async updateBranchNamePart() {
237
306
  const userLogin = await context.userLogin
238
307
 
239
- this.branchNamePart.textContent = `/${this.branchType}/${userLogin}/`
308
+ this.elements.branchNamePart.textContent = `/${this.branchType}/${userLogin}/`
240
309
  }
241
310
 
242
- /** Запускает редактирование описания для коммита */
311
+ /** Открывает форму редактирования редактирование описания для коммита */
243
312
  editDescription() {
244
- this.descriptionEdit.classList.toggle('hide')
245
- this.description.classList.toggle('hide')
246
- this.descriptionTextarea.classList.toggle('hide')
247
- this.descriptionTextarea.focus()
313
+ this.elements.descriptionEdit.classList.toggle('hide')
314
+ this.elements.description.classList.toggle('hide')
315
+ this.elements.descriptionTextarea.classList.toggle('hide')
316
+ this.elements.descriptionTextarea.focus()
248
317
  }
249
318
 
250
- /**
251
- * @returns {string} Заголовок
252
- */
253
- getTitle() {
254
- const { name } = this.options.data
255
- const docNumber = ' № ' + this.options.data.number
256
- const version = ' веха ' + this.version
257
- const date = ' от ' + this.options.data.date
258
- const author = ' ' + this.options.data.author
319
+ /** Обработка события при вводе текста в описание для расчета отображаемого кол-ва строк */
320
+ oninputDescription() {
321
+ this.description = this.elements.descriptionTextarea.value
322
+ }
259
323
 
260
- return name + docNumber + version + date + author
324
+ /** Открывает форму редактирования доп. имени ветки */
325
+ editBranchSubName() {
326
+ this.elements.branchSubName.classList.toggle('hide')
327
+ this.elements.branchSubNameTextfield.classList.toggle('hide')
328
+ this.elements.branchSubNameTextfield.focus()
329
+ this.elements.branchSubNameTextfield.select()
330
+ }
331
+
332
+ /** Сохранение данных о доп. имени ветки при вводе */
333
+ oninputBranchSubName() {
334
+ if (this.elements.branchSubNameTextfield.checkValidity()) {
335
+ this.branchSubName = this.elements.branchSubNameTextfield.value
336
+ }
337
+ }
338
+
339
+ /** Скрывает поле ввода доп. имени ветки при потере фокуса */
340
+ onblurBranchSubName() {
341
+ if (this.elements.branchSubNameTextfield.checkValidity()) {
342
+ this.elements.branchSubName.classList.toggle('hide')
343
+ this.elements.branchSubNameTextfield.classList.toggle('hide')
344
+ }
261
345
  }
262
346
 
263
347
  /**
348
+ * Получение имени ветки с учетом выбора вехи и доп. имени ветки
349
+ *
264
350
  * @returns {Promise<string>} Имя ветки
265
351
  */
266
352
  async getBranchName() {
267
- const branchSubName = this.branchSubNameTextfield.value || this.options.data.number
268
353
  const userLogin = await context.userLogin
269
354
 
270
- return `${this.version}/${this.branchType}/${userLogin}/${branchSubName}`
355
+ return `${this.version}/${this.branchType}/${userLogin}/${this.branchSubName}`
271
356
  }
272
357
 
273
358
  /** Копирование ссылки на задачу */
274
359
  copyLink() {
275
- navigator.clipboard.writeText(this.url)
276
- snackbar.show(`Скопирована ссылка: ${this.url}`)
360
+ navigator.clipboard.writeText(this.data.url)
361
+ snackbar.show(`Скопирована ссылка: ${this.data.url}`)
277
362
  }
278
363
 
279
364
  /** Копирование имени ветки */
280
365
  async copyBranchName() {
281
- if (this.branchSubNameTextfield.checkValidity()) {
366
+ if (this.elements.branchSubNameTextfield.checkValidity()) {
282
367
  const branchName = await this.getBranchName()
283
368
 
284
369
  navigator.clipboard.writeText(branchName)
285
370
  snackbar.show(`Скопировано имя ветки: ${branchName}`)
371
+
372
+ await this.saveToHistory()
286
373
  }
287
374
  }
288
375
 
289
376
  /** Копирование описания для git commit */
290
- copyDescription() {
291
- const description = this.getTitle() + '\n' +
292
- this.url + '\n' +
293
- this.descriptionTextarea.value
377
+ async copyDescription() {
378
+ const description = this.branchTitle + '\n' +
379
+ this.data.url + '\n' +
380
+ this.description
294
381
 
295
382
  navigator.clipboard.writeText(description)
296
383
  snackbar.show(`Скопировано описание для git commit:\n${description}`)
384
+
385
+ await this.saveToHistory()
386
+ }
387
+
388
+ /** Сохраняет данные в историю по карточкам для которых копировали имя ветки или описание */
389
+ async saveToHistory() {
390
+ const branchName = await this.getBranchName()
391
+ const gitBranchHistory = db.table('gitBranchHistory')
392
+ const historyOldData = await gitBranchHistory.get({
393
+ id: this.data.id,
394
+ branch: branchName
395
+ })
396
+ const historyData = {
397
+ id: this.data.id,
398
+ branch: branchName,
399
+ version: this.version,
400
+ useDate: new Date(),
401
+ data: this.data
402
+ }
403
+
404
+ if (historyOldData) {
405
+ await gitBranchHistory.update(historyOldData.pk, historyData)
406
+ } else {
407
+ await gitBranchHistory.add(historyData)
408
+ }
409
+ }
410
+
411
+ /** Восстановление из истории последнего сохраненного состояния карточки */
412
+ async restoreFromHistory() {
413
+ const gitBranchHistory = db.table('gitBranchHistory')
414
+ const historyData = await gitBranchHistory
415
+ .where({ id: this.options.data.id })
416
+ .reverse()
417
+ .sortBy('useDate')
418
+
419
+ if (historyData && historyData.length > 0) {
420
+ const [{ data: { version, branchSubName, description } }] = historyData
421
+
422
+ this.version = version
423
+ this.branchSubName = branchSubName
424
+ this.description = description
425
+ }
297
426
  }
298
427
 
299
428
  }
@@ -321,22 +450,35 @@ class GitBranchCardList extends oom.extends(HTMLElement) {
321
450
  // .mwcTab({ label: 'Список задач' })
322
451
  .mwcTab({ label: 'История задач' }))
323
452
 
324
- openTaskList = getListOfOpenCards({
325
- names: ['Ошибка', 'Задача'],
326
- hasVersion: true
327
- })
328
- .map(card => new GitBranchCard(card))
453
+ list = oom.div({ class: 'content' })
329
454
 
330
- openTaskListElement = (this.openTaskList.length > 0 && oom()(...this.openTaskList)) || oom
331
- .div({ class: 'empty' }, 'Открытых задач с вехой не найдено')
455
+ template = async () => {
456
+ // if (this.openTaskList.length === 0) {
457
+ // this.tabs({ activeindex: '1' })
458
+ // }
459
+ oom(this, this.tabs, this.list)
460
+ oom(this.list, oom.div({ class: 'empty' }, 'Загрузка ...'))
332
461
 
333
- template = () => {
334
- if (this.openTaskList.length === 0) {
335
- this.tabs({ activeindex: '1' })
462
+ this.list({ innerHTML: '' }, await this.buildTaskList())
463
+ }
464
+
465
+ /** @returns {Promise<HTMLElement|DocumentFragment>} Вернет готовый список задач с учетом аинхронной загрузки данных */
466
+ async buildTaskList() {
467
+ let taskTist = null
468
+ const openTaskList = (await getListOfOpenCards({
469
+ names: ['Ошибка', 'Задача'],
470
+ hasVersion: true
471
+ })).map(card => new GitBranchCard(card))
472
+
473
+ await Promise.all(openTaskList.map(card => card.restoreFromHistory()))
474
+
475
+ if (openTaskList.length > 0) {
476
+ taskTist = oom()(...openTaskList)
477
+ } else {
478
+ taskTist = oom.div({ class: 'empty' }, 'Открытых задач с вехой не найдено')
336
479
  }
337
- oom(this, this.tabs, oom.div({
338
- class: 'content'
339
- }, this.openTaskListElement))
480
+
481
+ return taskTist.dom
340
482
  }
341
483
 
342
484
  }
@@ -350,7 +492,7 @@ keysMapping['alt-KeyB'] = () => PopupDialog.toggle({
350
492
  Element: GitBranchCardList
351
493
  })
352
494
 
353
- rightSidebar.addButton({
495
+ toolbar.addButton({
354
496
  title: 'Ветки для Git',
355
497
  iconSVG: octicons['git-branch'].toSVG({ width: 24 }),
356
498
  onclick: keysMapping['alt-KeyB']
package/lib/database.js CHANGED
@@ -3,7 +3,10 @@ import { Dexie } from 'dexie'
3
3
  const db = new Dexie('saby-customizer-database')
4
4
 
5
5
 
6
- db.version(1).stores({ settings: '&key' })
6
+ db.version(2).stores({
7
+ settings: '&key',
8
+ gitBranchHistory: '++pk, &[id+branch], version, useDate'
9
+ })
7
10
 
8
11
 
9
12
  export { db }
@@ -1,2 +1,3 @@
1
1
  // Собрать стату по использованию фич кастомайзера
2
2
  // https://online.sbis.ru/news/4a005fd5-c99b-4e8d-a78b-eeb67b78d892
3
+ // https://git.sbis.ru/contragents/online/-/blob/rc-22.1200/client/ContractorCommon/_statisticCollection/Helper.ts
@@ -68,12 +68,22 @@ function parseRichEditorJSON(json) {
68
68
 
69
69
  /**
70
70
  * @typedef CardData Данные карточки документа
71
+ * @property {string} id Идентификатор документа
71
72
  * @property {string} number Номер документа
73
+ * @property {string} date Дата создания документа
74
+ * @property {string} name Название регламента Задача/Ошибка и т.д.
75
+ * @property {string} uuid UUID документа (для открытия ссылки)
76
+ * @property {string} url Ссылка на документ в отдельной вкладке
77
+ * @property {string} author Автор документа
78
+ * @property {string[]} milestones Список доступных вех (версий)
79
+ * @property {string} version Ближайшая версия
80
+ * @property {string} description Краткий текст описания задачи
72
81
  */
73
82
  /**
74
83
  * @typedef OpenCardsFilter Фильтры для выборки документов
75
84
  * @property {Array<string>} [names] Фильтр по названию документа
76
85
  * @property {boolean} [hasVersion] Документ включен хотя бы в 1 веху
86
+ * @property {boolean} [duplicates] Показать/скрыть из ответа документы которые открыты дважды
77
87
  */
78
88
  /**
79
89
  * Собирает из верстки страницы список открытых в данный момент карточек документов ЭДО
@@ -84,6 +94,7 @@ function parseRichEditorJSON(json) {
84
94
  export function getListOfOpenCards(filter = {}) {
85
95
  const cardNodes = document.querySelectorAll('.edo3-Dialog')
86
96
  const cards = []
97
+ const exists = []
87
98
 
88
99
  for (const cardNode of Array.from(cardNodes)) {
89
100
  // @ts-ignore
@@ -95,17 +106,24 @@ export function getListOfOpenCards(filter = {}) {
95
106
  const { element } = control
96
107
  const record = control?.options?.record
97
108
  const data = record && {
109
+ id: record.get('@Документ'),
98
110
  number: record.get('Номер'),
99
111
  date: getStrDate(record.get('Дата')),
100
112
  name: record.get('РП.Документ').get('Регламент').get('Название'),
101
113
  uuid: record.get('РП.Документ').get('ИдентификаторПереписки'),
114
+ url: '',
102
115
  author: record.get('ЛицоСоздал.Название') || record.get('Сотрудник.Название'),
103
116
  milestones: [],
104
- version: 'dev'
117
+ version: 'dev',
118
+ description: ''
105
119
  }
106
120
 
107
- if (data) {
108
- const milestonesRS = record.get('РП.ВехаДокумента')
121
+ if (data && (filter.duplicates || !exists.includes(data.id))) {
122
+ const milestonesRS = record.get('РП.ВехаДокумента') || []
123
+
124
+ if (!filter.duplicates) {
125
+ exists.push(data.id)
126
+ }
109
127
 
110
128
  data.name = replaceDocTypeName[data.name] || data.name
111
129
  if (filter.names) {