From d1b0bff8d81fda57b9f010cf94a8a76f9ff8a56c Mon Sep 17 00:00:00 2001 From: Luka Trovic Date: Tue, 29 Nov 2022 10:37:55 +0100 Subject: [PATCH] feat: update rich workspace visibility Signed-off-by: Luka Trovic --- cypress/e2e/workspace.spec.js | 54 ++++++++++++++++++-------------- cypress/support/commands.js | 28 ++++++++++++----- src/helpers/files.js | 44 ++++++++++++++++++++++---- src/views/RichWorkspace.vue | 59 +++++++---------------------------- 4 files changed, 100 insertions(+), 85 deletions(-) diff --git a/cypress/e2e/workspace.spec.js b/cypress/e2e/workspace.spec.js index b69c3a7f3a6..f145ccb1a25 100644 --- a/cypress/e2e/workspace.spec.js +++ b/cypress/e2e/workspace.spec.js @@ -62,27 +62,33 @@ describe('Workspace', function() { cy.get('a[href*="/apps/files/recent"]') .click() cy.get('#rich-workspace .ProseMirror') - .should('not.exist') + .should('not.visible') }) it('adds a Readme.md', function() { + const url = '**/remote.php/dav/files/**' + cy.intercept({ method: 'PUT', url }) + .as('addDescription') + cy.visit(`apps/files?dir=/${encodeURIComponent(currentFolder)}`) cy.get('.files-fileList').should('not.contain', 'Readme.md') - cy.openWorkspace() - .type('Hello') - .should('contain', 'Hello') + + cy.get('.files-controls').within(() => { + cy.get('.button.new').click() + cy.get('.newFileMenu a.menuitem[data-action="rich-workspace-init"]').click() + cy.wait('@addDescription') + }) + openSidebar('Readme.md') - cy.log('Regression test for #2215') - cy.get('#rich-workspace .ProseMirror') + cy.get('#rich-workspace .text-editor .text-editor__wrapper') .should('be.visible') - .should('contain', 'Hello') }) it('formats text', function() { cy.visit(`apps/files?dir=/${encodeURIComponent(currentFolder)}`) cy.openWorkspace() - .type('Format me') - .type('{selectall}') + .type('Format me', { force: true }) + .type('{selectall}', { force: true }) ;[ ['bold', 'strong'], ['italic', 'em'], @@ -104,8 +110,8 @@ describe('Workspace', function() { it('creates headings via submenu', function() { cy.visit(`apps/files?dir=/${encodeURIComponent(currentFolder)}`) cy.openWorkspace() - .type('Heading') - .type('{selectall}') + .type('Heading', { force: true }) + .type('{selectall}', { force: true }) ;['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].forEach((heading) => { const actionName = `headings-${heading}` @@ -123,11 +129,12 @@ describe('Workspace', function() { }) }) + it('creates lists', function() { cy.visit(`apps/files?dir=/${encodeURIComponent(currentFolder)}`) cy.openWorkspace() - .type('List me') - .type('{selectall}') + .type('List me', { force: true }) + .type('{selectall}', { force: true }) ;[ ['unordered-list', 'ul'], ['ordered-list', 'ol'], @@ -157,14 +164,14 @@ describe('Workspace', function() { it('emoji picker', () => { cy.visit(`apps/files?dir=/${encodeURIComponent(currentFolder)}`) cy.openWorkspace() - .type('# Let\'s smile together{enter}## ') + .type('# Let\'s smile together{enter}## ', {force: true}) cy.getMenuEntry('emoji-picker') .click() cy.get('#emoji-mart-list button[aria-label="😀, grinning"]') .first() - .click() + .click({force: true}) cy.getEditor() .find('h2') @@ -179,8 +186,8 @@ describe('Workspace', function() { cy.visit(`apps/files?dir=/${encodeURIComponent(currentFolder)}`) cy.openWorkspace() - .type('link me') - .type('{selectall}') + .type('link me', { force: true }) + .type('{selectall}', { force: true }) cy.getSubmenuEntry('insert-link', 'insert-link-file') .click() @@ -215,7 +222,7 @@ describe('Workspace', function() { beforeEach(function() { cy.visit(`apps/files?dir=/${encodeURIComponent(currentFolder)}`) - cy.openWorkspace().type('Callout') + cy.openWorkspace().type('Callout', {force: true}) }) // eslint-disable-next-line cypress/no-async-tests it('create callout', () => { @@ -286,7 +293,6 @@ describe('Workspace', function() { cy.uploadFile('test.md', 'text/markdown', `${Cypress.currentTest.title}/Anleitung.md`) cy.visit(`apps/files?dir=/${encodeURIComponent(currentFolder)}`) cy.get('.files-fileList').should('contain', 'Anleitung.md') - cy.get('.empty-workspace').should('contain', 'Ajoutez des notes, listes ou liens') }) }) @@ -294,10 +300,10 @@ describe('Workspace', function() { const checkContent = () => { const txt = Cypress.currentTest.title - cy.getEditor().find('[data-text-el="editor-content-wrapper"]').click() + cy.getEditor().find('[data-text-el="editor-content-wrapper"]').click({force: true}) cy.getContent() - .type(txt) + .type(txt, {force: true}) .should('contain', txt) } @@ -306,17 +312,17 @@ describe('Workspace', function() { }) it('click', () => { - cy.get('#rich-workspace .empty-workspace').click() + cy.openWorkspace().click({force: true}) checkContent() }) it('enter', () => { - cy.get('#rich-workspace .empty-workspace').type('{enter}') + cy.openWorkspace().type('{enter}', {force: true}) checkContent() }) it('spacebar', () => { - cy.get('#rich-workspace .empty-workspace') + cy.openWorkspace() .trigger('keyup', { keyCode: 32, which: 32, diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 35b30601fc1..1d833a02dc7 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -268,9 +268,9 @@ Cypress.Commands.add('getFile', fileName => { }) Cypress.Commands.add('deleteFile', fileName => { - cy.get(`.files-fileList tr[data-file="${fileName}"] a.name .action-menu`).click() - cy.get(`.files-fileList tr[data-file="${fileName}"] a.name + .popovermenu .action-delete`).click() - cy.get(`.files-fileList tr[data-file="${fileName}"]`).should('not.exist') + cy.get(`.files-fileList tr[data-file="${ fileName }"] a.name .action-menu`).click() + cy.get(`.files-fileList tr[data-file="${ fileName }"] a.name + .popovermenu .action-delete`).click() + cy.get(`.files-fileList tr[data-file="${ fileName }"]`).should('not.exist') }) Cypress.Commands.add('getModal', () => { @@ -301,7 +301,7 @@ Cypress.Commands.add('getMenuEntry', (name) => { Cypress.Commands.add('getSubmenuEntry', { prevSubject: 'optional' }, (subject, parent, name) => { return (subject ? cy.wrap(subject) : cy.getMenu()) .getActionEntry(parent) - .click() + .click({force: true}) .then(() => cy.getActionSubEntry(name)) }) @@ -311,7 +311,7 @@ Cypress.Commands.add('getActionEntry', { prevSubject: 'optional' }, (subject, na }) Cypress.Commands.add('getActionSubEntry', (name) => { - return cy.get('.action-item__popper .open').getActionEntry(name) + return cy.get('div[data-text-el="menubar"]').getActionEntry(name) }) Cypress.Commands.add('getContent', { prevSubject: 'optional' }, (subject) => { @@ -337,8 +337,9 @@ Cypress.Commands.add('clearContent', () => { }) Cypress.Commands.add('openWorkspace', () => { - cy.get('#rich-workspace .empty-workspace').click() - cy.getEditor().find('[data-text-el="editor-content-wrapper"]').click() + cy.createDescription() + cy.get('#rich-workspace .editor__content').click({force: true}) + cy.getEditor().find('[data-text-el="editor-content-wrapper"]').click({force: true}) return cy.getContent() }) @@ -363,6 +364,19 @@ Cypress.Commands.add('showHiddenFiles', () => { cy.get('.modal-container__close').click() }) +Cypress.Commands.add('createDescription', () => { + const url = '**/remote.php/dav/files/**' + cy.intercept({ method: 'PUT', url }) + .as('addDescription') + + cy.get('.files-fileList').should('not.contain', 'Readme.md') + cy.get('.files-controls').within(() => { + cy.get('.button.new').click() + cy.get('.newFileMenu a.menuitem[data-action="rich-workspace-init"]').click() + }) + cy.wait('@addDescription') +}) + Cypress.on( 'uncaught:exception', err => !err.message.includes('ResizeObserver loop limit exceeded'), diff --git a/src/helpers/files.js b/src/helpers/files.js index b95f06bcf4b..a4a65ac0bc9 100644 --- a/src/helpers/files.js +++ b/src/helpers/files.js @@ -21,7 +21,7 @@ */ import { loadState } from '@nextcloud/initial-state' -import { subscribe } from '@nextcloud/event-bus' +import { emit, subscribe } from '@nextcloud/event-bus' import { openMimetypes } from './mime.js' import { getSharingToken } from './token.js' import RichWorkspace from '../views/RichWorkspace.vue' @@ -139,6 +139,40 @@ const registerFileActionFallback = () => { } +const newRichWorkspaceFileMenuPlugin = { + attach(menu) { + const fileList = menu.fileList + const descriptionFile = t('text', 'Readme') + '.' + loadState('text', 'default_file_extension') + // only attach to main file list, public view is not supported yet + if (fileList.id !== 'files' && fileList.id !== 'files.public') { + return + } + + // register the new menu entry + menu.addMenuEntry({ + id: 'rich-workspace-init', + displayName: t('text', 'Add description'), + templateName: descriptionFile, + iconClass: 'icon-rename', + fileType: 'file', + useInput: false, + actionHandler() { + return window.FileList + .createFile(descriptionFile, { scrollTo: false, animate: false }) + .then(() => emit('Text::showRichWorkspace')) + }, + shouldShow() { + if (fileList.findFile(descriptionFile)) return false + return true + }, + }) + }, +} + +const addMenuRichWorkspace = () => { + OC.Plugins.register('OCA.Files.NewFileMenu', newRichWorkspaceFileMenuPlugin) +} + const FilesWorkspacePlugin = { el: null, @@ -146,7 +180,6 @@ const FilesWorkspacePlugin = { if (fileList.id !== 'files' && fileList.id !== 'files.public') { return } - this.el = document.createElement('div') fileList.registerHeader({ id: 'workspace', @@ -160,9 +193,10 @@ const FilesWorkspacePlugin = { if (fileList.id !== 'files' && fileList.id !== 'files.public') { return } - + addMenuRichWorkspace() import('vue').then((module) => { const Vue = module.default + const descriptionFile = t('text', 'Readme') + '.' + loadState('text', 'default_file_extension') this.el.id = 'files-workspace-wrapper' Vue.prototype.t = window.t Vue.prototype.n = window.n @@ -170,17 +204,15 @@ const FilesWorkspacePlugin = { const View = Vue.extend(RichWorkspace) const vm = new View({ propsData: { - path: fileList.getCurrentDirectory(), + path: fileList.getCurrentDirectory() }, store, }).$mount(this.el) - subscribe('files:navigation:changed', () => { // Expose if the default file list is active to the component // to only render the workspace if the file list is actually visible vm.active = OCA.Files.App.getCurrentFileList() === fileList }) - fileList.$el.on('urlChanged', data => { vm.path = data.dir.toString() }) diff --git a/src/views/RichWorkspace.vue b/src/views/RichWorkspace.vue index c0a86d1e9a4..d2b8d8adfc8 100644 --- a/src/views/RichWorkspace.vue +++ b/src/views/RichWorkspace.vue @@ -21,18 +21,7 @@ -->