Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"nextcloud/coding-standard": "^1.0",
"nextcloud/ocp": "dev-stable28",
"phan/phan": "^5",
"php-cs-fixer/shim": "3.95.1",
"php-cs-fixer/shim": "3.94.2",
"psalm/phar": "^5.26",
"squizlabs/php_codesniffer": "^4",
"staabm/annotate-pull-request-from-checkstyle": "^1.1.0"
Expand Down
38 changes: 19 additions & 19 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 41 additions & 0 deletions playwright/e2e/category-actions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,26 @@ async function waitForNewNoteRoute(page: Page, previousNoteId: number | null): P
return noteId
}

async function createNoteViaApi(page: Page, category: string, title: string): Promise<number> {
return page.evaluate(async ({ category, title }) => {
const requestToken = (window as unknown as { OC: { requestToken: string } }).OC.requestToken
const response = await fetch('/index.php/apps/notes/notes', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
requesttoken: requestToken,
},
body: JSON.stringify({ category, title, content: '' }),
})
if (!response.ok) {
throw new Error(`Failed to create note: ${response.status} ${await response.text()}`)
}

const note = await response.json() as { id: number }
return note.id
}, { category, title })
}

async function ensureNotesView(page: Page): Promise<void> {
if (await notesSearchField(page).isVisible()) {
return
Expand Down Expand Up @@ -154,4 +174,25 @@ test.describe('Category actions', () => {
await expect(navigationRow(page, 'All notes')).toHaveClass(/active/)
await expect(page).not.toHaveURL(deletedNoteUrl)
})

test('keeps all notes selected when opening a categorized note', async ({ page }, testInfo: TestInfo) => {
const category = uniqueCategoryName('all-notes', testInfo)
const title = `${category} note`
const noteId = await createNoteViaApi(page, category, title)

await page.goto('/index.php/apps/notes/')
await expect(contentNewNoteButton(page)).toBeVisible()
await expect(navigationRow(page, category)).toBeVisible()

await navigationRow(page, 'All notes').click()
await expect(navigationRow(page, 'All notes')).toHaveClass(/active/)

const noteLink = page.locator(`a[href$="/note/${noteId}"]`).first()
await expect(noteLink).toBeVisible()
await noteLink.click()

await expect(page).toHaveURL(new RegExp(`/note/${noteId}(\\?.*)?$`))
await expect(navigationRow(page, 'All notes')).toHaveClass(/active/)
await expect(navigationRow(page, category)).not.toHaveClass(/active/)
})
})
8 changes: 8 additions & 0 deletions src/Util.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ export const categoryLabel = (category) => {
return category === '' ? t('notes', 'Uncategorized') : category.replace(/\//g, ' / ')
}

export const rootCategory = (category) => {
if (!category) {
return ''
}
const separator = category.indexOf('/')
return separator === -1 ? category : category.substring(0, separator)
}

export const routeIsNewNote = ($route) => {
return {}.hasOwnProperty.call($route.query, 'new')
}
Expand Down
20 changes: 17 additions & 3 deletions src/components/CategoriesList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -458,15 +458,29 @@ export default {
</script>
<style lang="scss" scoped>
.app-navigation-entry-wrapper.active:deep(.app-navigation-entry) {
background-color: var(--color-primary-element-light) !important;
background-color: var(--color-primary-element) !important;
}

.app-navigation-entry-wrapper.active:deep(.app-navigation-entry:hover),
.app-navigation-entry-wrapper.active:deep(.app-navigation-entry:focus-within) {
background-color: var(--color-primary-element-hover) !important;
}

.app-navigation-entry-wrapper.drop-over:deep(.app-navigation-entry) {
background-color: var(--color-primary-element-light) !important;
outline: 2px dashed var(--color-primary-element);
background-color: var(--color-primary-element) !important;
outline: 2px dashed var(--color-primary-element-text);
outline-offset: -2px;
}

.app-navigation-entry-wrapper.active:deep(.app-navigation-entry-link),
.app-navigation-entry-wrapper.active:deep(.app-navigation-entry-button),
.app-navigation-entry-wrapper.active:deep(.material-design-icon),
.app-navigation-entry-wrapper.drop-over:deep(.app-navigation-entry-link),
.app-navigation-entry-wrapper.drop-over:deep(.app-navigation-entry-button),
.app-navigation-entry-wrapper.drop-over:deep(.material-design-icon) {
color: var(--color-primary-element-text) !important;
}

.app-navigation-entry-wrapper.category-no-actions:deep(.app-navigation-entry__counter-wrapper) {
margin-inline-end: calc(var(--default-grid-baseline) * 2 + var(--default-clickable-area));
}
Expand Down
18 changes: 17 additions & 1 deletion src/components/NotesList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
-->

<template>
<ul>
<ul class="notes-list">
<NoteItem v-for="note in notes"
:key="note.id"
:note="note"
Expand Down Expand Up @@ -50,3 +50,19 @@ export default {
},
}
</script>

<style lang="scss" scoped>
.notes-list:deep(.list-item__wrapper) {
border-block-end: 1px solid var(--color-border);
box-sizing: border-box;
padding-block: 0;
}

.notes-list:deep(.list-item__wrapper:first-of-type) {
padding-block-start: 0;
}

.notes-list:deep(.list-item__wrapper:last-of-type) {
padding-block-end: 0;
}
Comment on lines +70 to +72
</style>
67 changes: 65 additions & 2 deletions src/components/NotesView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ import NcAppContentList from '@nextcloud/vue/components/NcAppContentList'
import NcAppContentDetails from '@nextcloud/vue/components/NcAppContentDetails'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcTextField from '@nextcloud/vue/components/NcTextField'
import { categoryLabel } from '../Util.js'
import { categoryLabel, rootCategory } from '../Util.js'
import NotesList from './NotesList.vue'
import NotesCaption from './NotesCaption.vue'
import store from '../store.js'
Expand Down Expand Up @@ -128,6 +128,15 @@ export default {
return store.getters.getSelectedCategory()
},

note() {
const noteId = Number.parseInt(this.noteId, 10)
return Number.isFinite(noteId) ? store.getters.getNote(noteId) : null
},

noteCategory() {
return this.note?.category ?? null
},

filteredNotes() {
return store.getters.getFilteredNotes()
},
Expand Down Expand Up @@ -164,16 +173,70 @@ export default {
},

watch: {
category() { this.showFirstNotesOnly = true },
category() {
this.showFirstNotesOnly = true
this.hideVisibleNoteOutsideSelectedCategory()
},
noteId() {
this.showNote = true
this.updateVisibleNoteSelection()
},
noteCategory() {
this.updateVisibleNoteSelection()
},
showNote() {
this.updateVisibleNoteSelection()
},
searchText(value) { store.commit('updateSearchText', value) },
},

created() {
this.updateTimeslots()
this.updateVisibleNoteSelection()
setInterval(this.updateTimeslots, 1000 * 60)
},

destroyed() {
this.clearVisibleNoteSelection()
},

methods: {
clearVisibleNoteSelection() {
if (store.getters.getSelectedNote() !== null) {
store.commit('setSelectedNote', null)
}
},

updateVisibleNoteSelection() {
const noteId = Number.parseInt(this.noteId, 10)
if (!this.showNote || !Number.isFinite(noteId)) {
this.clearVisibleNoteSelection()
return
}

if (store.getters.getSelectedNote() !== noteId) {
store.commit('setSelectedNote', noteId)
}

if (this.note && store.getters.getSelectedCategory() !== null) {
const category = rootCategory(this.note.category)
if (store.getters.getSelectedCategory() !== category) {
store.commit('setSelectedCategory', category)
}
}
},

hideVisibleNoteOutsideSelectedCategory() {
if (!this.showNote || !this.note) {
return
}

const selectedCategory = store.getters.getSelectedCategory()
if (selectedCategory !== null && selectedCategory !== rootCategory(this.note.category)) {
this.showNote = false
}
},

updateTimeslots() {
const now = new Date()
// define the time groups we want to allow
Expand Down
You are viewing a condensed version of this merge commit. You can view the full changes here.