From 3ab97ca2b2f0df46c6cda204d2eea7561e7c0393 Mon Sep 17 00:00:00 2001 From: Rijk van Zanten Date: Fri, 20 Mar 2020 17:05:55 -0400 Subject: [PATCH] Collections module additions (#201) * Render add new link, only render delete on isnew is false * Add header actions buttons based on state * Add header buttons and breadcrumbs * Style tweaks * Add navigation guard for single collections * Add delete button logic * Add ability to delete items on browse * Add select mode to tabular layout * Add saving / deleting logic to detail view * remove tests (temporarily) * Remove empty tests temporarily * Add pagination to tabular layout if collection is large * Add server sort * wip table tweaks * show shadow only on scroll, fix padding on top of private view. * Update table * fix header hiding the scrollbar * Fix rAF leak * Make pagination sticky * fix double scroll bug * add selfScroll prop to private view * Last try * Lower the default limit * Fix tests for table / private / public view * finish header * remove unnessesary code * Fix debug overflow + icon alignment * Fix breadcrumbs * Fix item fetching * browse view now collapses on scroll * Add drawer-button component * Fix styling of drawer-button drawer-detail * Revert "browse view now collapses on scroll" This reverts commit a8534484d496deef01e399574126f7ba877e098c. * Final commit for the night * Add scroll solution for header overflow * Render table header over shadow * Add useScrollDistance compositoin * Add readme for scroll distance * Restructure header bar using sticky + margin / add shadow * Tweak box shadow to not show up at top on scroll up * Fix tests Co-authored-by: Nitwel --- src/api.test.ts | 7 +- src/components/register.ts | 10 + src/components/v-button/v-button.vue | 5 + src/components/v-card/index.ts | 6 +- src/components/v-card/v-card-title.vue | 1 - src/components/v-dialog/readme.md | 4 +- src/components/v-dialog/v-dialog.vue | 10 +- src/components/v-form/v-form.vue | 26 ++- src/components/v-table/readme.md | 25 ++- src/components/v-table/table-header/index.ts | 4 + src/components/v-table/table-header/readme.md | 0 .../table-header.test.ts} | 87 +------- .../table-header.vue} | 62 +++--- src/components/v-table/table-row/index.ts | 4 + src/components/v-table/table-row/readme.md | 0 .../table-row.test.ts} | 10 +- .../table-row.vue} | 44 ++-- src/components/v-table/v-table.story.ts | 34 +-- src/components/v-table/v-table.test.ts | 20 +- src/components/v-table/v-table.vue | 108 +++++++--- .../use-element-size/use-element-size.ts | 17 +- src/compositions/use-scroll-distance/index.ts | 4 + .../use-scroll-distance/readme.md | 38 ++++ .../use-scroll-distance.story.ts | 29 +++ .../use-scroll-distance.test.ts | 83 ++++++++ .../use-scroll-distance.ts | 37 ++++ src/layouts/tabular/tabular.vue | 137 +++++++++++-- src/layouts/types.ts | 5 + .../compositions/use-navigation.ts | 7 +- src/modules/collections/index.ts | 3 + .../collections/routes/browse/browse.test.ts | 21 -- .../collections/routes/browse/browse.vue | 193 ++++++++++++++++-- .../collections/routes/detail/detail.test.ts | 21 -- .../collections/routes/detail/detail.vue | 179 +++++++++++++++- .../routes/overview/overview.test.ts | 50 ----- .../collections/routes/overview/overview.vue | 4 + src/stores/collections/collections.ts | 7 + src/stores/fields/fields.ts | 9 + src/styles/_variables.scss | 1 + .../drawer-button/drawer-button.story.ts | 31 +++ .../drawer-button/drawer-button.test.ts | 21 ++ .../drawer-button/drawer-button.vue | 75 +++++++ .../private/components/drawer-button/index.ts | 4 + .../components/drawer-button/readme.md | 28 +++ .../drawer-detail/drawer-detail.vue | 17 +- .../header-bar-actions/header-bar-actions.vue | 4 +- .../components/header-bar/header-bar.test.ts | 9 + .../components/header-bar/header-bar.vue | 46 +++-- src/views/private/private-view.vue | 75 ++----- src/views/public/public-view.test.ts | 16 +- src/views/public/public-view.vue | 6 +- 51 files changed, 1213 insertions(+), 431 deletions(-) create mode 100644 src/components/v-table/table-header/index.ts create mode 100644 src/components/v-table/table-header/readme.md rename src/components/v-table/{_table-header.test.ts => table-header/table-header.test.ts} (82%) rename src/components/v-table/{_table-header.vue => table-header/table-header.vue} (87%) create mode 100644 src/components/v-table/table-row/index.ts create mode 100644 src/components/v-table/table-row/readme.md rename src/components/v-table/{_table-row.test.ts => table-row/table-row.test.ts} (88%) rename src/components/v-table/{_table-row.vue => table-row/table-row.vue} (73%) create mode 100644 src/compositions/use-scroll-distance/index.ts create mode 100644 src/compositions/use-scroll-distance/readme.md create mode 100644 src/compositions/use-scroll-distance/use-scroll-distance.story.ts create mode 100644 src/compositions/use-scroll-distance/use-scroll-distance.test.ts create mode 100644 src/compositions/use-scroll-distance/use-scroll-distance.ts delete mode 100644 src/modules/collections/routes/browse/browse.test.ts delete mode 100644 src/modules/collections/routes/detail/detail.test.ts delete mode 100644 src/modules/collections/routes/overview/overview.test.ts create mode 100644 src/views/private/components/drawer-button/drawer-button.story.ts create mode 100644 src/views/private/components/drawer-button/drawer-button.test.ts create mode 100644 src/views/private/components/drawer-button/drawer-button.vue create mode 100644 src/views/private/components/drawer-button/index.ts create mode 100644 src/views/private/components/drawer-button/readme.md diff --git a/src/api.test.ts b/src/api.test.ts index 6ab5d0b304..445a4f6252 100644 --- a/src/api.test.ts +++ b/src/api.test.ts @@ -22,14 +22,11 @@ const defaultError: Error = { }; describe('API', () => { - beforeAll(() => { - globalThis.window = Object.create(window); - Vue.use(VueCompositionAPI); - }); - beforeEach(() => { jest.spyOn(auth, 'logout'); jest.spyOn(auth, 'checkAuth'); + Vue.use(VueCompositionAPI); + window = Object.create(window); }); it('Calculates the correct API root URL based on window', () => { diff --git a/src/components/register.ts b/src/components/register.ts index 1863d08e34..906f9c37ba 100644 --- a/src/components/register.ts +++ b/src/components/register.ts @@ -2,8 +2,11 @@ import Vue from 'vue'; import VAvatar from './v-avatar/'; import VButton from './v-button/'; +import VBreadcrumb from './v-breadcrumb'; +import VCard, { VCardActions, VCardTitle, VCardSubtitle, VCardText } from './v-card'; import VCheckbox from './v-checkbox/'; import VChip from './v-chip/'; +import VDialog from './v-dialog'; import VForm from './v-form'; import VHover from './v-hover/'; import VIcon from './v-icon/'; @@ -30,8 +33,15 @@ import VTabs, { VTab, VTabsItems, VTabItem } from './v-tabs/'; Vue.component('v-avatar', VAvatar); Vue.component('v-button', VButton); +Vue.component('v-breadcrumb', VBreadcrumb); +Vue.component('v-card', VCard); +Vue.component('v-card-title', VCardTitle); +Vue.component('v-card-subtitle', VCardSubtitle); +Vue.component('v-card-text', VCardText); +Vue.component('v-card-actions', VCardActions); Vue.component('v-checkbox', VCheckbox); Vue.component('v-chip', VChip); +Vue.component('v-dialog', VDialog); Vue.component('v-form', VForm); Vue.component('v-hover', VHover); Vue.component('v-icon', VIcon); diff --git a/src/components/v-button/v-button.vue b/src/components/v-button/v-button.vue index 073a7e411a..4d70bff959 100644 --- a/src/components/v-button/v-button.vue +++ b/src/components/v-button/v-button.vue @@ -2,6 +2,7 @@ .v-dialog { + --v-dialog-z-index: 100; + + display: contents; + .container { position: fixed; top: 0; left: 0; + z-index: var(--v-dialog-z-index); display: flex; align-items: center; justify-content: center; @@ -75,15 +80,16 @@ export default defineComponent({ .v-sheet { --v-sheet-padding: 24px; + --v-sheet-max-width: 560px; } .v-overlay { - --v-overlay-z-index: 100; + --v-overlay-z-index: 1; } .content { position: relative; - z-index: 105; + z-index: 2; max-height: 90%; transform: translateY(50px); opacity: 0; diff --git a/src/components/v-form/v-form.vue b/src/components/v-form/v-form.vue index 1cc42888ef..1a75215ee1 100644 --- a/src/components/v-form/v-form.vue +++ b/src/components/v-form/v-form.vue @@ -2,7 +2,11 @@
- +
@@ -10,8 +14,10 @@ diff --git a/src/components/v-table/readme.md b/src/components/v-table/readme.md index 01f99c9863..90cfe4cf85 100644 --- a/src/components/v-table/readme.md +++ b/src/components/v-table/readme.md @@ -111,16 +111,21 @@ export default defineComponent({ ``` ## Props -| Prop | Description | Default | -|----------------|---------------------------------------------------------------------|---------| -| `headers`* | What columns to show in the table. Supports the `.sync` modifier | -- | -| `items`* | The individual items to render as rows | -- | -| `item-key` | Primary key of the item. Used for keys / selections | `id` | -| `sort-by` | What column / order to sort by. Supports the `.sync` modifier | -- | -| `show-select` | Show checkboxes | `false` | -| `show-resize` | Show resize handlers | `false` | -| `selection` | What items are selected. Can be used with `v-model` as well | `[]` | -| `fixed-header` | Make the header fixed | `false` | +| Prop | Description | Default | +|--------------------|------------------------------------------------------------------------------------------------|--------------| +| `headers`* | What columns to show in the table. Supports the `.sync` modifier | -- | +| `items`* | The individual items to render as rows | -- | +| `item-key` | Primary key of the item. Used for keys / selections | `id` | +| `sort` | What column / order to sort by. Supports the `.sync` modifier. `{ by: string, desc: boolean }` | -- | +| `show-select` | Show checkboxes | `false` | +| `show-resize` | Show resize handlers | `false` | +| `show-manual-sort` | Show manual sort drag handles | `false` | +| `selection` | What items are selected. Can be used with `v-model` as well | `[]` | +| `fixed-header` | Make the header fixed | `false` | +| `loading` | Show progress indicator | `false` | +| `loadingText` | What text to show when table is loading with no items | `Loading...` | +| `server-sort` | Handle sorting on the parent level. | `false` | +| `row-height` | Height of the individual rows in px | `48` | ## Events | Event | Description | Value | diff --git a/src/components/v-table/table-header/index.ts b/src/components/v-table/table-header/index.ts new file mode 100644 index 0000000000..0e97f0c2df --- /dev/null +++ b/src/components/v-table/table-header/index.ts @@ -0,0 +1,4 @@ +import TableHeader from './table-header.vue'; + +export { TableHeader }; +export default TableHeader; diff --git a/src/components/v-table/table-header/readme.md b/src/components/v-table/table-header/readme.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/components/v-table/_table-header.test.ts b/src/components/v-table/table-header/table-header.test.ts similarity index 82% rename from src/components/v-table/_table-header.test.ts rename to src/components/v-table/table-header/table-header.test.ts index e00e820b72..44f5dd8702 100644 --- a/src/components/v-table/_table-header.test.ts +++ b/src/components/v-table/table-header/table-header.test.ts @@ -4,13 +4,13 @@ import { mount, createLocalVue, Wrapper } from '@vue/test-utils'; const localVue = createLocalVue(); localVue.use(VueCompositionAPI); -import VCheckbox from '../v-checkbox/'; -import VIcon from '../v-icon/'; +import VCheckbox from '@/components/v-checkbox'; +import VIcon from '@/components/v-icon'; localVue.component('v-checkbox', VCheckbox); localVue.component('v-icon', VIcon); -import TableHeader from './_table-header.vue'; +import TableHeader from './table-header.vue'; describe('Table / Header', () => { let component: Wrapper; @@ -185,27 +185,6 @@ describe('Table / Header', () => { expect(component.find('th:nth-child(3)').classes()).toContain('align-right'); }); - it('Generates the correct inline styles for column widths', async () => { - component.setProps({ - headers: [], - sortDesc: false - }); - - await component.vm.$nextTick(); - - const styles = (component.vm as any).getStyleForHeader({ - text: 'Col2', - value: 'col2', - align: 'center', - sortable: true, - width: 150 - }); - - expect(styles).toEqual({ - width: '150px' - }); - }); - it('Renders the provided element in the nested scoped slot for the header', async () => { const component = mount(TableHeader, { localVue, @@ -230,7 +209,7 @@ describe('Table / Header', () => { } }); - expect(component.find('.v-table_table-header th:nth-child(2) .content > *').html()).toEqual( + expect(component.find('.table-header th:nth-child(2) .content > span > *').html()).toEqual( '

Column 2

' ); }); @@ -355,62 +334,4 @@ describe('Table / Header', () => { expect(component.emitted('update:headers')).toBe(undefined); }); - - it('Calculates the right width CSS property based on header', async () => { - component.setProps({ - headers: [ - { - text: 'Col1', - value: 'col1', - align: 'left', - sortable: true - }, - { - text: 'Col2', - value: 'col2', - align: 'left', - sortable: true, - width: 175 - }, - { - text: 'Col3', - value: 'col3', - align: 'left', - sortable: true, - width: 250 - } - ] - }); - - await component.vm.$nextTick(); - - const { getStyleForHeader } = component.vm as any; - - expect( - getStyleForHeader( - { - width: null - }, - 0 - ) - ).toEqual(null); - - expect( - getStyleForHeader( - { - width: 175 - }, - 1 - ) - ).toEqual({ width: '175px' }); - - expect( - getStyleForHeader( - { - width: 175 - }, - 2 - ) - ).toEqual({ width: 'auto' }); - }); }); diff --git a/src/components/v-table/_table-header.vue b/src/components/v-table/table-header/table-header.vue similarity index 87% rename from src/components/v-table/_table-header.vue rename to src/components/v-table/table-header/table-header.vue index cf433533c1..39e83f7170 100644 --- a/src/components/v-table/_table-header.vue +++ b/src/components/v-table/table-header/table-header.vue @@ -1,9 +1,10 @@ + + diff --git a/src/modules/collections/routes/detail/detail.test.ts b/src/modules/collections/routes/detail/detail.test.ts deleted file mode 100644 index d359ba287c..0000000000 --- a/src/modules/collections/routes/detail/detail.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { createLocalVue, shallowMount } from '@vue/test-utils'; -import VueCompositionAPI from '@vue/composition-api'; -import CollectionsDetail from './detail.vue'; -import PrivateView from '@/views/private'; - -const localVue = createLocalVue(); -localVue.use(VueCompositionAPI); -localVue.component('private-view', PrivateView); - -describe('Modules / Collections / Detail', () => { - it('Renders', () => { - const component = shallowMount(CollectionsDetail, { - localVue, - propsData: { - collection: 'my-test', - primaryKey: 'id' - } - }); - expect(component.isVueInstance()).toBe(true); - }); -}); diff --git a/src/modules/collections/routes/detail/detail.vue b/src/modules/collections/routes/detail/detail.vue index a9c0665622..e9be02aa06 100644 --- a/src/modules/collections/routes/detail/detail.vue +++ b/src/modules/collections/routes/detail/detail.vue @@ -1,7 +1,50 @@