|
1 | 1 | <template> |
2 | 2 |
|
3 | | - <KPageContainer class="page-container"> |
4 | | - <div |
5 | | - :class="{ 'table-header-mobile': isMobile() }" |
6 | | - :style="{ |
7 | | - marginTop: windowIsSmall ? '24px' : '32px', |
8 | | - }" |
9 | | - > |
10 | | - <div class="header-top"> |
11 | | - <h1 class="page-title">{{ $tr('pageTitle') }}</h1> |
12 | | - <KButton |
13 | | - v-if="!loading" |
14 | | - appearance="raised-button" |
15 | | - primary |
16 | | - :text="$tr('addChannelSetTitle')" |
17 | | - @click="newChannelSet" |
18 | | - /> |
19 | | - </div> |
20 | | - |
21 | | - <div class="header-bottom"> |
22 | | - <KButton |
23 | | - v-if="tableRows.length > 0" |
24 | | - appearance="basic-link" |
25 | | - :text="$tr('aboutChannelSetsLink')" |
26 | | - @click="infoDialog = true" |
27 | | - /> |
28 | | - </div> |
| 3 | + <KPageContainer |
| 4 | + class="page-container" |
| 5 | + :class="{ 'larger-window': !windowIsSmall }" |
| 6 | + > |
| 7 | + <div class="header"> |
| 8 | + <h1>{{ $tr('pageTitle') }}</h1> |
| 9 | + <KButton |
| 10 | + v-if="!loading" |
| 11 | + appearance="raised-button" |
| 12 | + primary |
| 13 | + class="new-collection-button" |
| 14 | + :text="$tr('addChannelSetTitle')" |
| 15 | + @click="newChannelSet" |
| 16 | + /> |
29 | 17 | </div> |
30 | | - |
| 18 | + <KButton |
| 19 | + v-if="tableRows.length > 0" |
| 20 | + appearance="basic-link" |
| 21 | + :text="$tr('aboutChannelSetsLink')" |
| 22 | + @click="infoDialog = true" |
| 23 | + /> |
| 24 | + |
| 25 | + <!-- Two wrapping divs needed to prevent brief loader shift after content displayed --> |
31 | 26 | <div v-if="show('loader', loading, 500)"> |
32 | | - <KCircularLoader /> |
| 27 | + <div class="loader"> |
| 28 | + <KCircularLoader /> |
| 29 | + </div> |
33 | 30 | </div> |
34 | 31 |
|
35 | | - <div v-else-if="tableRows.length === 0"> |
36 | | - <p class="mb-0"> |
| 32 | + <div |
| 33 | + v-else-if="tableRows.length === 0" |
| 34 | + class="no-channels" |
| 35 | + > |
| 36 | + <div> |
37 | 37 | {{ $tr('noChannelSetsFound') }} |
38 | 38 | <KButton |
39 | 39 | appearance="basic-link" |
40 | 40 | :text="$tr('aboutChannelSetsLink')" |
41 | 41 | @click="infoDialog = true" |
42 | 42 | /> |
43 | | - </p> |
| 43 | + </div> |
44 | 44 | </div> |
45 | 45 |
|
46 | 46 | <KTable |
47 | 47 | v-else |
| 48 | + class="table" |
48 | 49 | :stickyColumns="stickyColumns" |
49 | 50 | :caption="$tr('tableCaption')" |
50 | 51 | :headers="tableHeaders" |
|
70 | 71 | <StudioCopyToken |
71 | 72 | v-if="content" |
72 | 73 | :token="content" |
| 74 | + :style="copyTokenStyle" |
| 75 | + :showLabel="false" |
| 76 | + :showCopyButton="showCopyTokenButton" |
73 | 77 | /> |
74 | 78 | <em |
75 | 79 | v-else |
|
90 | 94 | class="actions-cell" |
91 | 95 | > |
92 | 96 | <KButton |
93 | | - v-if="!isSmallScreen()" |
| 97 | + v-if="windowBreakpoint > 2" |
94 | 98 | :text="$tr('options')" |
95 | 99 | appearance="flat-button" |
96 | 100 | :hasDropdown="true" |
|
156 | 160 | import { mapActions, mapGetters } from 'vuex'; |
157 | 161 | import useKShow from 'kolibri-design-system/lib/composables/useKShow'; |
158 | 162 | import useKResponsiveWindow from 'kolibri-design-system/lib/composables/useKResponsiveWindow'; |
| 163 | + import useClipboard from '../../../shared/composables/useClipboard'; |
159 | 164 | import { RouteNames } from '../../constants'; |
160 | | - import StudioCopyToken from '../../../settings/pages/Account/StudioCopyToken'; |
| 165 | + import StudioCopyToken from '../../../shared/views/StudioCopyToken'; |
161 | 166 |
|
162 | 167 | export default { |
163 | 168 | name: 'StudioCollectionsTable', |
|
166 | 171 | }, |
167 | 172 | setup() { |
168 | 173 | const { show } = useKShow(); |
169 | | - const { windowBreakpoint, windowIsSmall } = useKResponsiveWindow(); |
| 174 | + const { windowIsSmall, windowBreakpoint } = useKResponsiveWindow(); |
| 175 | + const { copyToClipboard } = useClipboard(); |
170 | 176 |
|
171 | 177 | return { |
172 | 178 | show, |
173 | | - windowBreakpoint, |
174 | 179 | windowIsSmall, |
| 180 | + windowBreakpoint, |
| 181 | + copyToClipboard, |
175 | 182 | }; |
176 | 183 | }, |
177 | 184 | data() { |
|
184 | 191 | }, |
185 | 192 | computed: { |
186 | 193 | ...mapGetters('channelSet', ['channelSets', 'getChannelSet']), |
187 | | -
|
| 194 | + showCopyTokenButton() { |
| 195 | + return this.windowBreakpoint > 2; |
| 196 | + }, |
| 197 | + tokenInputWidth() { |
| 198 | + return this.showCopyTokenButton ? '170px' : '130px'; |
| 199 | + }, |
| 200 | + copyTokenStyle() { |
| 201 | + return { |
| 202 | + position: 'relative', |
| 203 | + top: '-6px', |
| 204 | + minWidth: this.tokenInputWidth, |
| 205 | + }; |
| 206 | + }, |
188 | 207 | tableHeaders() { |
189 | 208 | return [ |
190 | 209 | { |
191 | 210 | label: this.$tr('title'), |
192 | 211 | dataType: 'string', |
193 | 212 | minWidth: '200px', |
194 | | - width: '55%', |
| 213 | + width: '40%', |
195 | 214 | columnId: 'name', |
196 | 215 | }, |
197 | 216 | { |
198 | 217 | label: this.$tr('token'), |
199 | 218 | dataType: 'string', |
200 | | - minWidth: '200px', |
201 | | - width: '20%', |
| 219 | + width: this.tokenInputWidth, |
202 | 220 | columnId: 'tokens', |
203 | 221 | }, |
204 | 222 | { |
205 | 223 | label: this.$tr('channelNumber'), |
206 | 224 | dataType: 'number', |
207 | | - minWidth: '100px', |
208 | | - width: '15%', |
| 225 | + minWidth: '200px', |
| 226 | + width: '20%', |
209 | 227 | columnId: 'channel_count', |
210 | 228 | }, |
211 | 229 | { |
212 | 230 | label: '', |
213 | 231 | dataType: 'undefined', |
214 | | - width: '10%', |
215 | 232 | columnId: 'actions', |
216 | 233 | }, |
217 | 234 | ]; |
|
240 | 257 | }, |
241 | 258 |
|
242 | 259 | dropdownOptions() { |
243 | | - return [ |
| 260 | + const options = [ |
244 | 261 | { |
245 | 262 | label: this.$tr('edit'), |
246 | 263 | value: 'edit', |
|
252 | 269 | icon: 'trash', |
253 | 270 | }, |
254 | 271 | ]; |
| 272 | + if (!this.showCopyTokenButton) { |
| 273 | + options.unshift({ |
| 274 | + label: this.$tr('copyToken'), |
| 275 | + value: 'copy-token', |
| 276 | + icon: 'copy', |
| 277 | + }); |
| 278 | + } |
| 279 | + return options; |
255 | 280 | }, |
256 | 281 | }, |
257 | 282 | mounted() { |
|
261 | 286 | }, |
262 | 287 | methods: { |
263 | 288 | ...mapActions('channelSet', ['loadChannelSetList', 'deleteChannelSet']), |
264 | | -
|
265 | | - isMobile() { |
266 | | - return this.windowBreakpoint <= 0; |
267 | | - }, |
268 | | -
|
269 | | - isSmallScreen() { |
270 | | - return this.windowBreakpoint <= 2; |
271 | | - }, |
272 | | -
|
273 | 289 | handleOptionSelect(option, collectionId) { |
274 | 290 | if (option.value === 'edit') { |
275 | 291 | this.$router.push({ |
|
282 | 298 | this.channelSets.find(c => c.id === collectionId) || |
283 | 299 | null; |
284 | 300 | if (this.collectionToDelete) this.deleteDialog = true; |
| 301 | + } else if (option.value === 'copy-token') { |
| 302 | + const collection = |
| 303 | + this.getChannelSet(collectionId) || |
| 304 | + this.channelSets.find(c => c.id === collectionId) || |
| 305 | + null; |
| 306 | + if (collection && collection.secret_token) { |
| 307 | + this.handleCopyToken(collection.secret_token); |
| 308 | + } |
285 | 309 | } |
286 | 310 | }, |
287 | 311 |
|
| 312 | + handleCopyToken(value) { |
| 313 | + this.copyToClipboard(value, { |
| 314 | + successMessage: this.$tr('copiedTokenId'), |
| 315 | + errorMessage: this.$tr('copyFailed'), |
| 316 | + }); |
| 317 | + }, |
| 318 | +
|
288 | 319 | confirmDelete() { |
289 | 320 | if (this.collectionToDelete) { |
290 | 321 | this.deleteChannelSet(this.collectionToDelete) |
|
335 | 366 | saving: 'Saving', |
336 | 367 | collectionDeleted: 'Collection deleted', |
337 | 368 | deleteError: 'Error deleting collection', |
| 369 | + copyToken: 'Copy token', |
| 370 | + copiedTokenId: 'Token copied', |
| 371 | + copyFailed: 'Copy failed', |
338 | 372 | }, |
339 | 373 | }; |
340 | 374 |
|
|
346 | 380 | .page-container { |
347 | 381 | width: 100%; |
348 | 382 | max-width: 1440px; |
| 383 | + min-height: 400px; // TOOD have a look at Kolibri's user table |
349 | 384 | margin: 0 auto; |
350 | 385 | } |
351 | 386 |
|
352 | | - .header-top { |
| 387 | + .header { |
353 | 388 | display: flex; |
| 389 | + flex-direction: column-reverse; |
| 390 | + margin-top: 24px; |
| 391 | +
|
| 392 | + h1 { |
| 393 | + margin-top: 8px; |
| 394 | + } |
| 395 | +
|
| 396 | + .new-collection-button { |
| 397 | + align-self: flex-end; |
| 398 | + } |
| 399 | + } |
| 400 | +
|
| 401 | + .larger-window .header { |
| 402 | + flex-direction: row; |
354 | 403 | align-items: center; |
355 | 404 | justify-content: space-between; |
356 | | - margin-bottom: 16px; |
357 | | - } |
358 | 405 |
|
359 | | - .collection-name { |
360 | | - display: inline-block; |
361 | | - font-size: 16px; |
362 | | - font-weight: 500; |
363 | | - border-radius: 2px; |
| 406 | + h1 { |
| 407 | + margin-top: 0; |
| 408 | + } |
364 | 409 | } |
365 | 410 |
|
366 | | - .header-bottom { |
367 | | - display: flex; |
368 | | - align-items: center; |
369 | | - margin-bottom: 8px; |
| 411 | + .loader { |
| 412 | + margin-top: 64px; |
370 | 413 | } |
371 | 414 |
|
372 | | - .page-title { |
373 | | - margin: 0; |
| 415 | + .no-channels { |
| 416 | + margin-top: 24px; |
374 | 417 | } |
375 | 418 |
|
376 | | - .actions-cell { |
377 | | - display: flex; |
378 | | - justify-content: flex-end; |
| 419 | + .larger-window .no-channels { |
| 420 | + max-width: 800px; |
| 421 | + margin: 64px auto 0; |
| 422 | + text-align: center; |
379 | 423 | } |
380 | 424 |
|
381 | | - .table-header-mobile { |
382 | | - .header-top { |
383 | | - flex-direction: column; |
384 | | - gap: 12px; |
385 | | - text-align: center; |
386 | | - } |
| 425 | + .table { |
| 426 | + margin-top: 32px; |
| 427 | + } |
387 | 428 |
|
388 | | - .header-bottom { |
389 | | - justify-content: center; |
390 | | - } |
| 429 | + .collection-name { |
| 430 | + display: inline-block; |
| 431 | + font-size: 16px; |
| 432 | + font-weight: 500; |
| 433 | + border-radius: 2px; |
391 | 434 | } |
392 | 435 |
|
393 | | - .page-container .k-table-wrapper { |
394 | | - overflow: hidden; |
| 436 | + .actions-cell { |
| 437 | + display: flex; |
| 438 | + justify-content: flex-end; |
395 | 439 | } |
396 | 440 |
|
397 | 441 | </style> |
0 commit comments