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

Implement spaces list #6199

Merged
merged 18 commits into from
Jan 13, 2022
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
6 changes: 6 additions & 0 deletions changelog/unreleased/enhancement-spaces-list
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Implement spaces list

We added a new route that lists all available spaces of type "project".

https://github.com/owncloud/web/pull/6199
https://github.com/owncloud/web/issues/6104
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"packages/web-app-markdown-editor",
"packages/web-app-media-viewer",
"packages/web-app-search",
"packages/web-client",
"packages/web-pkg",
"packages/web-runtime"
],
Expand Down
5 changes: 4 additions & 1 deletion packages/web-app-files/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
class="files-list-wrapper oc-width-expand"
@dragover="$_ocApp_dragOver"
>
<app-bar id="files-app-bar" />
<app-bar v-if="!hideAppBar" id="files-app-bar" />
<progress-bar v-show="$_uploadProgressVisible" id="files-upload-progress" class="oc-p-s" />
<router-view id="files-view" />
</div>
Expand Down Expand Up @@ -55,6 +55,9 @@ export default {
},
showSidebar() {
return !this.sidebarClosed
},
hideAppBar() {
return this.$route.meta.hideAppBar === true
}
},
watch: {
Expand Down
16 changes: 15 additions & 1 deletion packages/web-app-files/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Personal from './views/Personal.vue'
import SharedWithMe from './views/SharedWithMe.vue'
import SharedWithOthers from './views/SharedWithOthers.vue'
import SharedViaLink from './views/SharedViaLink.vue'
import SpaceProjects from './views/spaces/Projects.vue'
import Trashbin from './views/Trashbin.vue'
import translations from '../l10n/translations.json'
import quickActions from './quickActions'
Expand Down Expand Up @@ -39,7 +40,7 @@ const navItems = [
iconMaterial: appInfo.icon,
fillType: 'fill',
route: {
path: `/${appInfo.id}/spaces/`
path: `/${appInfo.id}/spaces/personal/home`
}
},
{
Expand Down Expand Up @@ -77,6 +78,16 @@ const navItems = [
path: `/${appInfo.id}/shares/via-link`
}
},
{
JammingBen marked this conversation as resolved.
Show resolved Hide resolved
name: $gettext('Spaces'),
iconMaterial: 'layout-grid',
route: {
path: `/${appInfo.id}/spaces/projects`
},
enabled(capabilities) {
return capabilities.spaces && capabilities.spaces.enabled === true
kulmann marked this conversation as resolved.
Show resolved Hide resolved
}
},
{
name: $gettext('Deleted files'),
iconMaterial: 'delete-bin-5',
Expand Down Expand Up @@ -105,6 +116,9 @@ export default {
SharedViaLink,
SharedWithMe,
SharedWithOthers,
Spaces: {
Projects: SpaceProjects
},
Trashbin
}),
navItems,
Expand Down
29 changes: 17 additions & 12 deletions packages/web-app-files/src/router/router.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import Vue, { ComponentOptions } from 'vue'

/**
* we need to inject the vue files into the route builders,
* this is because we also import the provided helpers from other js|ts files
* like mixins, rollup seems to have a problem to import files which contain vue file imports
* into js files which then again get imported by other vue files...
*/
export interface RouteComponents {
App: any
Favorites: any
FilesDrop: any
LocationPicker: any
PrivateLink: any
PublicFiles: any
Personal: any
PublicLink: any
SharedWithMe: any
SharedWithOthers: any
SharedViaLink: any
Trashbin: any
App: ComponentOptions<Vue>
Favorites: ComponentOptions<Vue>
FilesDrop: ComponentOptions<Vue>
LocationPicker: ComponentOptions<Vue>
PrivateLink: ComponentOptions<Vue>
PublicFiles: ComponentOptions<Vue>
Personal: ComponentOptions<Vue>
PublicLink: ComponentOptions<Vue>
SharedWithMe: ComponentOptions<Vue>
SharedWithOthers: ComponentOptions<Vue>
SharedViaLink: ComponentOptions<Vue>
Spaces: {
Projects: ComponentOptions<Vue>
}
Trashbin: ComponentOptions<Vue>
}
36 changes: 23 additions & 13 deletions packages/web-app-files/src/router/spaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,48 @@ import { Location, RouteConfig } from 'vue-router'
import { RouteComponents } from './router'
import { createLocation, isLocationActiveDirector, $gettext } from './utils'

type shareTypes = 'files-spaces-personal-home'
type spaceTypes = 'files-spaces-personal-home' | 'files-spaces-projects'

export const createLocationSpaces = (name: shareTypes, location = {}): Location =>
export const createLocationSpaces = (name: spaceTypes, location = {}): Location =>
createLocation(
name,
{
params: {
storage: 'home',
namespace: 'personal'
...(name === 'files-spaces-personal-home' && { storage: 'home' })
}
},
location
)
export const isLocationSpacesActive = isLocationActiveDirector<shareTypes>(
createLocationSpaces('files-spaces-personal-home')

const locationSpacesProjects = createLocationSpaces('files-spaces-projects')
const locationSpacesPersonalHome = createLocationSpaces('files-spaces-personal-home')

export const isLocationSpacesActive = isLocationActiveDirector<spaceTypes>(
locationSpacesProjects,
locationSpacesPersonalHome
)

export const buildRoutes = (components: RouteComponents): RouteConfig[] => [
{
path: '/spaces',
redirect: (to) => createLocationSpaces('files-spaces-personal-home', to)
},
{
path: '/spaces/:namespace',
components: {
app: components.App
},
redirect: (to) => createLocationSpaces('files-spaces-personal-home', to),
children: [
{
name: createLocationSpaces('files-spaces-personal-home').name,
path: ':storage/:item*',
path: 'projects',
name: locationSpacesProjects.name,
component: components.Spaces?.Projects,
meta: {
hideFilelistActions: true,
hasBulkActions: true,
hideAppBar: true,
title: $gettext('Spaces')
}
},
{
path: 'personal/:storage/:item*',
name: locationSpacesPersonalHome.name,
component: components.Personal,
meta: {
hasBulkActions: true,
Expand Down
98 changes: 98 additions & 0 deletions packages/web-app-files/src/views/spaces/Projects.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<template>
<div class="oc-p-s">
<h2 v-text="$gettext('Spaces')" />
<span v-text="$gettext('Access all project related files in one place.')" />
<a href="#" v-text="$gettext('Learn more about spaces.')" />
<h3 v-text="$gettext('Your spaces')" />
<hr class="oc-mb-s" />
<list-loader v-if="loadSpacesTask.isRunning" />
<template v-else>
<no-content-message
v-if="!spaces.length"
id="files-spaces-empty"
class="files-empty"
icon="layout-grid"
>
<template #message>
<span v-translate>You don't have access to any spaces</span>
</template>
</no-content-message>
<div v-else class="spaces-list">
<div
class="
oc-grid
oc-grid-match
oc-grid-column-small
oc-grid-row-large
oc-text-center
oc-child-width-1-3@s
"
>
<a v-for="space in spaces" :key="space.id" href="#" class="oc-mb-m">
<span class="spaces-list-card oc-border oc-card oc-card-default">
<span class="oc-card-media-top oc-border-b">
<img v-if="space.image" :src="space.image" alt="" />
<oc-icon v-else name="layout-grid" size="xxlarge" class="oc-px-m oc-py-m" />
</span>
<span class="oc-card-body">
<span class="oc-card-title" v-text="space.name" />
</span>
</span>
</a>
</div>
</div>
</template>
</div>
</template>

<script>
import NoContentMessage from '../../components/FilesList/NoContentMessage.vue'
import ListLoader from '../../components/FilesList/ListLoader.vue'
import { client } from 'web-client'
import { ref } from '@vue/composition-api'
import { useStore } from '../../composables'
import { useTask } from 'vue-concurrency'

export default {
components: {
NoContentMessage,
ListLoader
},
setup() {
const store = useStore()
const spaces = ref([])
const { graph } = client(store.getters.configuration.server, store.getters.getToken)

const loadSpacesTask = useTask(function* () {
const response = yield graph.drives.listMyDrives()
spaces.value = (response.data?.value || []).filter((drive) => drive.driveType === 'project')
})

loadSpacesTask.perform()

return {
spaces,
loadSpacesTask
}
}
}
</script>

<style lang="scss">
#files-spaces-empty {
height: 50vh;
}

.spaces-list {
&-card {
box-shadow: none !important;
}

.oc-card-media-top {
display: inline-block;
width: 100%;
background-color: var(--oc-color-background-muted);
max-height: 150px;
}
}
</style>
63 changes: 63 additions & 0 deletions packages/web-app-files/tests/unit/views/spaces/Projects.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { mount } from '@vue/test-utils'
import { localVue } from '../views.setup'
import { createStore } from 'vuex-extensions'
import mockAxios from 'jest-mock-axios'
import SpaceProjects from '../../../../src/views/spaces/Projects.vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'

localVue.use(VueRouter)

const selectors = {
sharesNoContentMessage: '#files-spaces-empty',
spacesList: '.spaces-list'
}

beforeEach(mockAxios.reset)

describe('Spaces component', () => {
it('should show a "no content" message', async () => {
mockAxios.request.mockImplementationOnce(() => {
return Promise.resolve({
data: {
value: []
}
})
})

const wrapper = getMountedWrapper()
await wrapper.vm.loadSpacesTask.last

expect(wrapper.find(selectors.sharesNoContentMessage).exists()).toBeTruthy()
})

it('should only list drives of type "project"', async () => {
mockAxios.request.mockImplementationOnce(() => {
return Promise.resolve({
data: {
value: [{ driveType: 'project' }, { driveType: 'personal' }]
}
})
})

const wrapper = getMountedWrapper()
await wrapper.vm.loadSpacesTask.last

expect(wrapper.vm.spaces.length).toEqual(1)
JammingBen marked this conversation as resolved.
Show resolved Hide resolved
expect(wrapper).toMatchSnapshot()
})
})

function getMountedWrapper() {
return mount(SpaceProjects, {
localVue,
router: new VueRouter(),
store: createStore(Vuex.Store, {
getters: {
configuration: () => ({
server: 'https://example.com/'
})
}
})
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Spaces component should only list drives of type "project" 1`] = `
<div class="oc-p-s">
<h2>Spaces</h2> <span>Access all project related files in one place.</span> <a href="#">Learn more about spaces.</a>
<h3>Your spaces</h3>
<hr class="oc-mb-s">
<div class="spaces-list">
<div class="
oc-grid
oc-grid-match
oc-grid-column-small
oc-grid-row-large
oc-text-center
oc-child-width-1-3@s
"><a href="#" class="oc-mb-m"><span class="spaces-list-card oc-border oc-card oc-card-default"><span class="oc-card-media-top oc-border-b"><span class="oc-px-m oc-py-m oc-icon oc-icon-xxl oc-icon-passive"><!----></span></span> <span class="oc-card-body"><span class="oc-card-title"></span></span>
</span></a>
</div>
</div>
</div>
`;
11 changes: 11 additions & 0 deletions packages/web-client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "web-client",
"private": true,
"version": "0.0.0",
"description": "ownCloud web client",
"license": "AGPL-3.0",
"main": "src/index.ts",
"scripts": {
"generate-openapi": "rm -rf src/generated && docker run --rm -v \"${PWD}/src:/local\" openapitools/openapi-generator-cli generate -i https://github.com/raw/owncloud/libre-graph-api/main/api/openapi-spec/v0.0.yaml -g typescript-axios -o /local/generated"
Copy link
Member

Choose a reason for hiding this comment

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

}
}
4 changes: 4 additions & 0 deletions packages/web-client/src/generated/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
wwwroot/*.js
node_modules
typings
dist
1 change: 1 addition & 0 deletions packages/web-client/src/generated/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm
Loading