diff --git a/packages/web-app-files/src/components/AppBar/AppBar.vue b/packages/web-app-files/src/components/AppBar/AppBar.vue index 1e145988b87..9c8c3f5012d 100644 --- a/packages/web-app-files/src/components/AppBar/AppBar.vue +++ b/packages/web-app-files/src/components/AppBar/AppBar.vue @@ -125,7 +125,7 @@ <size-info v-if="hasBulkActions && selectedFiles.length > 0" class="oc-mr oc-visible@l" /> <batch-actions v-if="hasBulkActions" /> </div> - <view-options /> + <view-options v-if="!hideViewOptions" /> </div> </div> </div> @@ -244,18 +244,32 @@ export default { hasBulkActions() { return this.$route.meta.hasBulkActions === true }, + hideViewOptions() { + return this.$route.meta.hideViewOptions === true + }, pageTitle() { const title = this.$route.meta.title return this.$gettext(title) }, breadcrumbs() { - if (!(this.isPublicLocation || this.isPersonalLocation)) { + const isProjectSpaces = + isLocationSpacesActive(this.$router, 'files-spaces-projects') || + isLocationSpacesActive(this.$router, 'files-spaces-project') + + if (!(this.isPublicLocation || this.isPersonalLocation || isProjectSpaces)) { return [] } const { params: routeParams, path: routePath } = this.$route - const { item: requestedItemPath = '' } = routeParams + + let requestedItemPath = '' + if (isProjectSpaces) { + requestedItemPath = routeParams.spaceId || '' + } else { + requestedItemPath = routeParams.item || '' + } + const basePaths = '/' + decodeURIComponent(routePath) @@ -275,10 +289,17 @@ export default { if (i === rawItems.length - 1) { this.isPublicLocation && acc.shift() - acc.length && - (acc[0].text = this.isPersonalLocation - ? this.$gettext('All files') - : this.$gettext('Public link')) + + if (acc.length) { + if (this.isPersonalLocation) { + acc[0].text = this.$gettext('All files') + } else if (isProjectSpaces) { + acc[0].text = this.$gettext('Spaces') + } else { + acc[0].text = this.$gettext('Public link') + } + } + acc.length && delete acc[acc.length - 1].to } else { delete acc[i].onClick diff --git a/packages/web-app-files/src/router/spaces.ts b/packages/web-app-files/src/router/spaces.ts index ba7cc24d99e..980a1936f62 100644 --- a/packages/web-app-files/src/router/spaces.ts +++ b/packages/web-app-files/src/router/spaces.ts @@ -39,7 +39,7 @@ export const buildRoutes = (components: RouteComponents): RouteConfig[] => [ meta: { hideFilelistActions: true, hasBulkActions: true, - hideAppBar: true, + hideViewOptions: true, title: $gettext('Spaces') } }, @@ -50,7 +50,6 @@ export const buildRoutes = (components: RouteComponents): RouteConfig[] => [ meta: { hideFilelistActions: true, hasBulkActions: true, - hideAppBar: true, title: $gettext('Space') } }, diff --git a/packages/web-app-files/src/views/spaces/Project.vue b/packages/web-app-files/src/views/spaces/Project.vue index b9bee270d10..07af32a703f 100644 --- a/packages/web-app-files/src/views/spaces/Project.vue +++ b/packages/web-app-files/src/views/spaces/Project.vue @@ -4,7 +4,7 @@ <template v-else> <not-found-message v-if="!space.id" class="files-not-found oc-height-1-1" /> <div v-else class="oc-grid oc-grid-match oc-child-width-1-3@s"> - <div class="oc-mt-s"> + <div> <img class="space-overview-image" alt="" @@ -14,7 +14,7 @@ <div> <h3 class="oc-mb-s">{{ space.name }}</h3> <span v-if="space.description">{{ space.description }}</span> - <div v-if="markdownContent"> + <div> <div ref="markdownContainer" class="markdown-container" v-html="markdownContent"></div> <div v-if="showMarkdownCollapse" class="markdown-collapse oc-text-center oc-mt-s"> <oc-button appearance="raw" @click="toggleCollapseMarkdown"> @@ -25,15 +25,10 @@ </div> </div> </div> - <no-content-message - v-if="isEmpty" - id="files-personal-empty" - class="files-empty" - icon="folder" - > + <no-content-message v-if="isEmpty" id="files-spaces-empty" class="files-empty" icon="folder"> <template #message> <p class="oc-text-muted"> - <span v-translate>No resource found</span> + <span v-translate>No resources found</span> </p> </template> </no-content-message> @@ -48,10 +43,12 @@ import ListLoader from '../../components/FilesList/ListLoader.vue' import { ref } from '@vue/composition-api' import { client } from 'web-client' import { useTask } from 'vue-concurrency' -import { useStore, useRouter } from '../../composables' +import { useStore, useRouter } from 'web-pkg/src/composables' import marked from 'marked' import { arrayBuffToB64 } from '../../helpers/commonUtil' import axios from 'axios' +import MixinAccessibleBreadcrumb from '../../mixins/accessibleBreadcrumb' +import { bus } from 'web-pkg/src/instance' export default { components: { @@ -59,6 +56,7 @@ export default { ListLoader, NotFoundMessage }, + mixins: [MixinAccessibleBreadcrumb], setup() { const router = useRouter() const store = useStore() @@ -85,7 +83,16 @@ export default { Authorization: `Bearer ${ref.getToken}` } }) + + if (ref.markdownResizeObserver) { + ref.markdownResizeObserver.unobserve(ref.$refs.markdownContainer) + } + markdownContent.value = marked.parse(response.data) + + if (markdownContent.value) { + ref.markdownResizeObserver.observe(ref.$refs.markdownContainer) + } }) const loadImageTask = useTask(function* (signal, ref) { const imageEntry = space.value?.special?.find((el) => el?.specialFolder?.name === 'image') @@ -104,7 +111,11 @@ export default { imageContent.value = arrayBuffToB64(response.data) }) - loadSpaceTask.perform() + const loadResourcesTask = useTask(function* (signal, ref) { + yield loadSpaceTask.perform(ref) + loadReadmeTask.perform(ref) + loadImageTask.perform(ref) + }) return { space, @@ -112,7 +123,8 @@ export default { loadImageTask, loadReadmeTask, markdownContent, - imageContent + imageContent, + loadResourcesTask } }, data: function () { @@ -120,7 +132,7 @@ export default { markdownCollapsed: true, markdownContainerCollapsedClass: 'collapsed', showMarkdownCollapse: false, - markdownResizeObserver: null, + markdownResizeObserver: new ResizeObserver(this.onMarkdownResize), isEmpty: true } }, @@ -135,15 +147,16 @@ export default { } }, async mounted() { - await this.loadSpaceTask.last - await this.loadReadmeTask.perform(this) - await this.loadImageTask.perform(this) + await this.loadResourcesTask.perform(this) + document.title = `${this.space.name} - ${this.$route.meta.title}` + this.$route.params.name = this.space.name - if (this.markdownContent) { - this.markdownResizeObserver = new ResizeObserver(this.onMarkdownResize) - this.markdownResizeObserver.observe(this.$refs.markdownContainer) - } + const loadSpaceEventToken = bus.subscribe('app.files.list.load', (path) => { + this.loadResourcesTask.perform(this) + }) + + this.$on('beforeDestroy', () => bus.unsubscribe('app.files.list.load', loadSpaceEventToken)) }, beforeDestroy() { this.markdownResizeObserver.unobserve(this.$refs.markdownContainer) @@ -154,6 +167,10 @@ export default { return this.$refs.markdownContainer.classList.toggle(this.markdownContainerCollapsedClass) }, onMarkdownResize() { + if (!this.$refs.markdownContainer) { + return + } + this.$refs.markdownContainer.classList.remove(this.markdownContainerCollapsedClass) const markdownContainerHeight = this.$refs.markdownContainer.offsetHeight @@ -174,7 +191,7 @@ export default { <style lang="scss"> .space-overview { &-image { - border-radius: 5px; + border-radius: 10px; max-height: 250px; } diff --git a/packages/web-app-files/src/views/spaces/Projects.vue b/packages/web-app-files/src/views/spaces/Projects.vue index aedb2e13e40..75271598dec 100644 --- a/packages/web-app-files/src/views/spaces/Projects.vue +++ b/packages/web-app-files/src/views/spaces/Projects.vue @@ -1,6 +1,6 @@ <template> <div class="oc-p-s"> - <h2 v-text="$gettext('Spaces')" /> + <h2 class="oc-mt-rm" 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')" /> @@ -31,7 +31,7 @@ <div v-for="space in spaces" :key="space.id" 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"> - <router-link v-if="!loadImagesTask.isRunning" :to="getSpaceProjectRoute(space.id)"> + <router-link v-if="!loadImagesTask.isRunning" :to="getSpaceProjectRoute(space)"> <img v-if="imageContentObject[space.id]" class="space-image" @@ -43,7 +43,7 @@ </span> <span class="oc-card-body"> <router-link - :to="getSpaceProjectRoute(space.id)" + :to="getSpaceProjectRoute(space)" class="oc-card-title" v-text="space.name" /> @@ -66,6 +66,8 @@ import { useTask } from 'vue-concurrency' import { createLocationSpaces } from '../../router' import axios from 'axios' import { arrayBuffToB64 } from '../../helpers/commonUtil' +import { bus } from 'web-pkg/src/instance' +import { mapMutations } from 'vuex' export default { components: { @@ -85,8 +87,6 @@ export default { .sort((a, b) => a.name.localeCompare(b.name)) }) - loadSpacesTask.perform() - const loadImageTask = useTask(function* (signal, { spaceId, webDavUrl, token }) { const response = yield axios.get(webDavUrl, { headers: { @@ -103,7 +103,7 @@ export default { const imageEntry = space?.special?.find((el) => el?.specialFolder?.name === 'image') if (!imageEntry) { - return + continue } yield loadImageTask.perform({ @@ -114,21 +114,36 @@ export default { } }) + const loadResourcesTask = useTask(function* (signal, ref) { + ref.SET_CURRENT_FOLDER(null) + + yield ref.loadSpacesTask.perform(ref) + yield ref.loadImagesTask.perform(ref) + }) + return { spaces, loadSpacesTask, loadImagesTask, + loadResourcesTask, imageContentObject } }, - async mounted() { - await this.loadSpacesTask.last - await this.loadImagesTask.perform(this) + mounted() { + this.loadResourcesTask.perform(this) + + const loadSpacesEventToken = bus.subscribe('app.files.list.load', (path) => { + this.loadResourcesTask.perform(this) + }) + + this.$on('beforeDestroy', () => bus.unsubscribe('app.files.list.load', loadSpacesEventToken)) }, methods: { - getSpaceProjectRoute(spaceId) { + ...mapMutations('Files', ['SET_CURRENT_FOLDER']), + + getSpaceProjectRoute({ id, name }) { return createLocationSpaces('files-spaces-project', { - params: { spaceId } + params: { spaceId: id, name } }) } } @@ -149,11 +164,18 @@ export default { display: inline-block; width: 100%; background-color: var(--oc-color-background-muted); - max-height: 150px; + height: 200px; + } + .oc-card-media-top a { + display: flex; + justify-content: center; + align-items: center; + height: 100%; } .space-image { - max-width: 100%; - height: auto; + width: 100%; + height: 200px; + object-fit: cover; } } </style>