Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add viewMode toggle for condensed resource table #7976

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions changelog/unreleased/enhancement-condensed-files-view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Enhancement: Add switch to enable condensed resource table

We've added a switch to have a more condensed resource table.
The change gets saved to the route and persisted across resource navigation.

https://github.com/owncloud/web/pull/7976
https://github.com/owncloud/web/issues/6380
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Enhancement: Add condensed menu icon
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kulmann not sure if the changelog in the design system still gets updated individually or if there's only one in the repo root from now on?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to maintain a separate changelog, because we want to be able to release independently with non aligned version numbers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good, that's what I assumed (and hence the changelog entry^^)


We added a new menu icon for the switch between condensed and regular resource table.

https://github.com/owncloud/web/pull/7976
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 26 additions & 3 deletions packages/web-app-files/src/components/AppBar/ViewOptions.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
<template>
<div>
<div class="oc-flex oc-flex-middle">
<div data-testid="viewmode-switch-buttons" class="oc-button-group oc-visible@s oc-mr-s">
<oc-button
:appearance="viewModeCurrent === ViewModeConstants.condensedTable ? 'filled' : 'outline'"
@click="setViewMode(ViewModeConstants.condensedTable)"
>
<oc-icon name="menu-line-condensed" fill-type="none" size="small" />
</oc-button>
<oc-button
:appearance="viewModeCurrent === ViewModeConstants.default ? 'filled' : 'outline'"
@click="setViewMode(ViewModeConstants.default)"
>
<oc-icon name="menu-line" fill-type="none" size="small" />
</oc-button>
</div>
<oc-button
id="files-view-options-btn"
key="files-view-options-btn"
Expand Down Expand Up @@ -50,16 +64,22 @@
<script>
import { mapMutations, mapState } from 'vuex'
import { useRouteQueryPersisted } from 'web-pkg/src/composables'
import { PaginationConstants } from '../../composables'
import { PaginationConstants, ViewModeConstants } from '../../composables'

export default {
setup() {
const perPageQuery = useRouteQueryPersisted({
name: PaginationConstants.perPageQueryName,
defaultValue: PaginationConstants.perPageDefault
})
const viewModeQuery = useRouteQueryPersisted({
name: ViewModeConstants.queryName,
defaultValue: ViewModeConstants.default
})

return {
ViewModeConstants,
viewModeCurrent: viewModeQuery,
itemsPerPage: perPageQuery
}
},
Expand Down Expand Up @@ -90,7 +110,10 @@ export default {
}
},
methods: {
...mapMutations('Files', ['SET_HIDDEN_FILES_VISIBILITY', 'SET_FILE_EXTENSIONS_VISIBILITY'])
...mapMutations('Files', ['SET_HIDDEN_FILES_VISIBILITY', 'SET_FILE_EXTENSIONS_VISIBILITY']),
setViewMode(mode) {
this.viewModeCurrent = mode
}
}
}
</script>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<template>
<oc-table
:class="hoverableQuickActions && 'hoverable-quick-actions'"
:class="[
hoverableQuickActions && 'hoverable-quick-actions',
{ condensed: viewMode === ViewModeConstants.condensedTable }
]"
:data="resources"
:fields="fields"
:highlighted="selectedIds"
Expand Down Expand Up @@ -181,6 +184,8 @@ import {
useCapabilityProjectSpacesEnabled,
useCapabilityShareJailEnabled
} from 'web-pkg/src/composables'
import { ViewModeConstants } from 'web-app-files/src/composables/viewMode'

import Rename from '../../mixins/actions/rename'
import { defineComponent, PropType } from 'vue'
import { Resource } from 'web-client'
Expand Down Expand Up @@ -318,6 +323,10 @@ export default defineComponent({
required: false,
default: false
},
viewMode: {
type: String,
default: ViewModeConstants.default
},
/**
* Enable hover effect
*/
Expand Down Expand Up @@ -367,6 +376,7 @@ export default defineComponent({
},
setup() {
return {
ViewModeConstants,
hasShareJail: useCapabilityShareJailEnabled(),
hasProjectSpaces: useCapabilityProjectSpacesEnabled()
}
Expand Down Expand Up @@ -833,6 +843,9 @@ export default defineComponent({
})
</script>
<style lang="scss">
.oc-table.condensed > tbody > tr {
height: 0 !important;
}
.resource-table {
&-resource-cut {
opacity: 0.6;
Expand Down
1 change: 1 addition & 0 deletions packages/web-app-files/src/composables/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './resourcesViewDefaults'
export * from './router'
export * from './selection'
export * from './sort'
export * from './viewMode'

declare module 'vue/types/vue' {
interface Vue {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@ import { usePagination, useFileListHeaderPosition, SortField } from '../'
import { useSort, SortDir } from '../sort/'
import { useSideBar } from '../sideBar'

import { useMutationSubscription, useRouteQuery, useStore } from 'web-pkg/src/composables'
import {
queryItemAsString,
useMutationSubscription,
useRouteQuery,
useStore
} from 'web-pkg/src/composables'
import { determineSortFields } from '../../helpers/ui/resourceTable'
import { Task } from 'vue-concurrency'
import { Resource } from 'web-client'
import { useSelectedResources, SelectedResourcesResult } from '../selection'
import { ReadOnlyRef } from 'web-pkg'
import { ScrollToResult, useScrollTo } from '../scrollTo'
import { useViewMode, ViewModeConstants } from '../viewMode'

interface ResourcesViewDefaultsOptions<T, U extends any[]> {
loadResourcesTask?: Task<T, U>
Expand All @@ -30,6 +36,7 @@ type ResourcesViewDefaultsResult<T, TT, TU extends any[]> = {
handleSort({ sortBy, sortDir }: { sortBy: string; sortDir: SortDir }): void
sortBy: ReadOnlyRef<string>
sortDir: ReadOnlyRef<SortDir>
viewMode: ReadOnlyRef<string>

selectedResources: Ref<Resource[]>
selectedResourcesIds: Ref<(string | number)[]>
Expand Down Expand Up @@ -61,6 +68,10 @@ export const useResourcesViewDefaults = <T, TT, TU extends any[]>(
fields
})

const currentViewModeQuery = useRouteQuery('view-mode', ViewModeConstants.default)
const currentViewMode = computed((): string => queryItemAsString(currentViewModeQuery.value))
const viewMode = useViewMode(currentViewMode)

const paginationPageQuery = useRouteQuery('page', '1')
const paginationPage = computed((): number => parseInt(String(paginationPageQuery.value)))
const { items: paginatedResources, total: paginationPages } = usePagination({
Expand All @@ -80,6 +91,7 @@ export const useResourcesViewDefaults = <T, TT, TU extends any[]>(
areResourcesLoading,
storeItems,
fields,
viewMode,
paginatedResources,
paginationPages,
paginationPage,
Expand Down
5 changes: 5 additions & 0 deletions packages/web-app-files/src/composables/viewMode/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export abstract class ViewModeConstants {
static readonly default: string = 'resource-table'
static readonly queryName: string = 'view-mode'
static readonly condensedTable: string = 'resource-table-condensed'
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a huge fan of this use class as enum pattern, I'd rather use typescript types for this nowadays

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've followed what I found in another composable basically, idk if refactoring my/the other solution independently is within the scope of this PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with both of you 😆 Would like to get rid of it, but also fine in a separate PR.

2 changes: 2 additions & 0 deletions packages/web-app-files/src/composables/viewMode/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './constants'
export * from './useViewMode'
15 changes: 15 additions & 0 deletions packages/web-app-files/src/composables/viewMode/useViewMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { computed, ComputedRef, unref } from 'vue'
import { queryItemAsString, useRouteQueryPersisted } from 'web-pkg/src/composables'
import { ViewModeConstants } from './constants'

export function useViewMode<T>(options: ComputedRef<string>): ComputedRef<string> {
if (options) {
return computed(() => unref(options))
}

const viewModeQuery = useRouteQueryPersisted({
name: ViewModeConstants.queryName,
defaultValue: ViewModeConstants.default
})
return computed(() => queryItemAsString(unref(viewModeQuery)))
}
1 change: 1 addition & 0 deletions packages/web-app-files/src/views/spaces/GenericSpace.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
v-model="selectedResourcesIds"
class="files-table"
:class="{ 'files-table-squashed': sideBarOpen }"
:view-mode="viewMode"
:are-thumbnails-displayed="displayThumbnails"
:resources="paginatedResources"
:target-route-callback="resourceTargetRouteCallback"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const useResourcesViewDefaultsMock = (
sideBarActivePanel: ref(''),
scrollToResource: jest.fn(),
scrollToResourceFromRoute: jest.fn(),
viewMode: ref('resource-table'),
...options
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { shallowMount, createLocalVue } from '@vue/test-utils'
import { mount, shallowMount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import VueRouter from 'vue-router'
import merge from 'lodash-es/merge'

import DesignSystem from '@ownclouders/design-system'

import Store from 'web-app-files/src/store'
import stubs from '@/tests/unit/stubs'
import OcPageSize from '@/tests/unit/stubs/OcPageSize'
Expand Down Expand Up @@ -95,4 +97,46 @@ describe('ViewOptions', () => {

expect(mockedStore.modules.Files.mutations.SET_HIDDEN_FILES_VISIBILITY).toHaveBeenCalled()
})

it('initially shows normal resource-table by default', () => {
const wrapper = shallowMount(ViewOptions, {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for future tests (not blocking this PR): we introduced a new way of handling mocks in unit tests. See for example

The functions creating the wrappers now return an object, containing mocks, storeOptions and the wrapper. That gives you the chance to manipulate mocks within the test code.

store,
router,
localVue,
stubs: stubs,
directives: { OcTooltip }
})
const viewModeSwitchButtons = wrapper.find('[data-testid="viewmode-switch-buttons"]')

expect(viewModeSwitchButtons).toMatchSnapshot()
})
it('toggles between normal and condensed resource-table upon clicking the respective buttons', async () => {
localVue.use(DesignSystem)

const wrapper = mount(ViewOptions, {
store,
router,
localVue,
stubs: {
...stubs,
'oc-button': false
},
directives: { OcTooltip }
})

const viewModeSwitchButtons = wrapper.find('[data-testid="viewmode-switch-buttons"]')
console.log(viewModeSwitchButtons.html())

await wrapper
.findAll('[data-testid="viewmode-switch-buttons"] > .oc-button')
.at(0)
.trigger('click')
expect(viewModeSwitchButtons).toMatchSnapshot()

await wrapper
.findAll('[data-testid="viewmode-switch-buttons"] > .oc-button')
.at(1)
.trigger('click')
expect(viewModeSwitchButtons).toMatchSnapshot()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ViewOptions initially shows normal resource-table by default 1`] = `
<div data-testid="viewmode-switch-buttons" class="oc-button-group oc-visible@s oc-mr-s">
<oc-button-stub appearance="outline">
<oc-icon-stub name="menu-line-condensed" fill-type="none" size="small"></oc-icon-stub>
</oc-button-stub>
<oc-button-stub appearance="filled">
<oc-icon-stub name="menu-line" fill-type="none" size="small"></oc-icon-stub>
</oc-button-stub>
</div>
`;

exports[`ViewOptions toggles between normal and condensed resource-table upon clicking the respective buttons 1`] = `
<div data-testid="viewmode-switch-buttons" class="oc-button-group oc-visible@s oc-mr-s"><button type="button" class="oc-button oc-rounded oc-button-m oc-button-justify-content-center oc-button-gap-m oc-button-passive oc-button-passive-filled">
<oc-icon-stub name="menu-line-condensed" filltype="none" accessiblelabel="" type="span" size="small" variation="passive" color=""></oc-icon-stub>
</button> <button type="button" class="oc-button oc-rounded oc-button-m oc-button-justify-content-center oc-button-gap-m oc-button-passive oc-button-passive-outline">
<oc-icon-stub name="menu-line" filltype="none" accessiblelabel="" type="span" size="small" variation="passive" color=""></oc-icon-stub>
</button></div>
`;

exports[`ViewOptions toggles between normal and condensed resource-table upon clicking the respective buttons 2`] = `
<div data-testid="viewmode-switch-buttons" class="oc-button-group oc-visible@s oc-mr-s"><button type="button" class="oc-button oc-rounded oc-button-m oc-button-justify-content-center oc-button-gap-m oc-button-passive oc-button-passive-outline">
<oc-icon-stub name="menu-line-condensed" filltype="none" accessiblelabel="" type="span" size="small" variation="passive" color=""></oc-icon-stub>
</button> <button type="button" class="oc-button oc-rounded oc-button-m oc-button-justify-content-center oc-button-gap-m oc-button-passive oc-button-passive-filled">
<oc-icon-stub name="menu-line" filltype="none" accessiblelabel="" type="span" size="small" variation="passive" color=""></oc-icon-stub>
</button></div>
`;