Skip to content

Commit c107174

Browse files
committed
chore(files_reminders): upgrade to 28 APIs
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
1 parent b08c973 commit c107174

14 files changed

Lines changed: 522 additions & 423 deletions

apps/files/src/components/FileEntry/FileEntryActions.vue

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,34 +51,34 @@
5151
}"
5252
:close-after-click="!isMenu(action.id)"
5353
:data-cy-files-list-row-action="action.id"
54+
:is-menu="isMenu(action.id)"
5455
:title="action.title?.([source], currentView)"
5556
@click="onActionClick(action)">
5657
<template #icon>
57-
<ChevronRightIcon v-if="isMenu(action.id)" />
58-
<NcLoadingIcon v-else-if="loading === action.id" :size="18" />
58+
<NcLoadingIcon v-if="loading === action.id" :size="18" />
5959
<NcIconSvgWrapper v-else :svg="action.iconSvgInline([source], currentView)" />
6060
</template>
6161
{{ actionDisplayName(action) }}
6262
</NcActionButton>
6363
</template>
6464

6565
<!-- Submenu actions list-->
66-
<template v-if="openedSubmenu && enabledSubmenuActions[openedSubmenu]">
66+
<template v-if="openedSubmenu && enabledSubmenuActions[openedSubmenu?.id]">
6767
<!-- Back to top-level button -->
68-
<NcActionButton class="files-list__row-action-back" @click="openedSubmenu = ''">
68+
<NcActionButton class="files-list__row-action-back" @click="openedSubmenu = null">
6969
<template #icon>
7070
<ArrowLeftIcon />
7171
</template>
72-
{{ t('files', 'Back') }}
72+
{{ actionDisplayName(openedSubmenu) }}
7373
</NcActionButton>
7474
<NcActionSeparator />
7575

7676
<!-- Submenu actions -->
77-
<NcActionButton v-for="action in enabledSubmenuActions[openedSubmenu]"
77+
<NcActionButton v-for="action in enabledSubmenuActions[openedSubmenu?.id]"
7878
:key="action.id"
7979
:class="`files-list__row-action-${action.id}`"
8080
class="files-list__row-action--submenu"
81-
:close-after-click="true"
81+
:close-after-click="false /* never close submenu, just go back */"
8282
:data-cy-files-list-row-action="action.id"
8383
:title="action.title?.([source], currentView)"
8484
@click="onActionClick(action)">
@@ -152,7 +152,7 @@ export default Vue.extend({
152152
153153
data() {
154154
return {
155-
openedSubmenu: '',
155+
openedSubmenu: null as FileAction | null,
156156
}
157157
},
158158
@@ -267,10 +267,10 @@ export default Vue.extend({
267267
return action.displayName([this.source], this.currentView)
268268
},
269269
270-
async onActionClick(action) {
270+
async onActionClick(action, isSubmenu = false) {
271271
// If the action is a submenu, we open it
272272
if (this.enabledSubmenuActions[action.id]) {
273-
this.openedSubmenu = action.id
273+
this.openedSubmenu = action
274274
return
275275
}
276276
@@ -299,6 +299,11 @@ export default Vue.extend({
299299
// Reset the loading marker
300300
this.$emit('update:loading', '')
301301
Vue.set(this.source, 'status', undefined)
302+
303+
// If that was a submenu, we just go back after the action
304+
if (isSubmenu) {
305+
this.openedSubmenu = null
306+
}
302307
}
303308
},
304309
execDefaultAction(event) {

apps/files/src/components/FileEntry/FileEntryPreview.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
alt=""
3838
class="files-list__row-icon-preview"
3939
:class="{'files-list__row-icon-preview--loaded': backgroundFailed === false}"
40+
loading="lazy"
4041
:src="previewUrl"
4142
@error="backgroundFailed = true"
4243
@load="backgroundFailed = false">

apps/files/src/init.ts

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -63,39 +63,3 @@ registerRecentView()
6363

6464
// Register preview service worker
6565
registerPreviewServiceWorker()
66-
67-
registerFileAction(new FileAction({
68-
id: 'menu',
69-
displayName: () => 'Menu',
70-
iconSvgInline: () => MenuIcon,
71-
exec: async () => true,
72-
}))
73-
74-
registerFileAction(new FileAction({
75-
id: 'submenu1',
76-
displayName: () => 'Submenu 1',
77-
iconSvgInline: () => MenuIcon,
78-
exec: async () => alert('Hello 1'),
79-
parent: 'menu',
80-
}))
81-
registerFileAction(new FileAction({
82-
id: 'submenu2',
83-
displayName: () => 'Submenu 2',
84-
iconSvgInline: () => MenuIcon,
85-
exec: async () => alert('Hello 2'),
86-
parent: 'menu',
87-
}))
88-
registerFileAction(new FileAction({
89-
id: 'submenu3',
90-
displayName: () => 'Submenu 3',
91-
iconSvgInline: () => MenuIcon,
92-
exec: async () => alert('Hello 3'),
93-
parent: 'menu',
94-
}))
95-
registerFileAction(new FileAction({
96-
id: 'submenu4',
97-
displayName: () => 'Submenu 4',
98-
iconSvgInline: () => MenuIcon,
99-
exec: async () => alert('Hello 4'),
100-
parent: 'menu',
101-
}))

apps/files/src/sidebar.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ if (!window.OCA.Files) {
3636
Object.assign(window.OCA.Files, { Sidebar: new Sidebar() })
3737
Object.assign(window.OCA.Files.Sidebar, { Tab })
3838

39-
console.debug('OCA.Files.Sidebar initialized')
40-
4139
window.addEventListener('DOMContentLoaded', function() {
4240
const contentElement = document.querySelector('body > .content')
4341
|| document.querySelector('body > #content')

apps/files_reminders/lib/Listener/LoadAdditionalScriptsListener.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,6 @@ public function handle(Event $event): void {
4747
return;
4848
}
4949

50-
Util::addScript(Application::APP_ID, 'main');
50+
Util::addInitScript(Application::APP_ID, 'init');
5151
}
5252
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
3+
*
4+
* @author John Molakvoæ <skjnldsv@protonmail.com>
5+
*
6+
* @license AGPL-3.0-or-later
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License as
10+
* published by the Free Software Foundation, either version 3 of the
11+
* License, or (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU Affero General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Affero General Public License
19+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
*
21+
*/
22+
import { FileAction, Node } from '@nextcloud/files'
23+
import { translate as t } from '@nextcloud/l10n'
24+
import CalendarClockSvg from '@mdi/svg/svg/calendar-clock.svg?raw'
25+
26+
import { SET_REMINDER_MENU_ID } from './setReminderMenuAction'
27+
import { pickCustomDate } from '../services/customPicker'
28+
29+
export const action = new FileAction({
30+
id: 'set-reminder-custom',
31+
displayName: () => t('files', 'Set custom reminder'),
32+
title: () => t('files_reminders', 'Set reminder at custom date & time'),
33+
iconSvgInline: () => CalendarClockSvg,
34+
35+
enabled: () => true,
36+
parent: SET_REMINDER_MENU_ID,
37+
38+
async exec(file: Node) {
39+
pickCustomDate(file)
40+
return null
41+
},
42+
43+
// After presets
44+
order: 22,
45+
})
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
3+
*
4+
* @author John Molakvoæ <skjnldsv@protonmail.com>
5+
*
6+
* @license AGPL-3.0-or-later
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License as
10+
* published by the Free Software Foundation, either version 3 of the
11+
* License, or (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU Affero General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Affero General Public License
19+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
*
21+
*/
22+
import { FileAction } from '@nextcloud/files'
23+
import { translate as t } from '@nextcloud/l10n'
24+
import AlarmSvg from '@mdi/svg/svg/alarm.svg?raw'
25+
26+
export const SET_REMINDER_MENU_ID = 'set-reminder-menu'
27+
28+
export const action = new FileAction({
29+
id: SET_REMINDER_MENU_ID,
30+
displayName: () => t('files', 'Set reminder'),
31+
iconSvgInline: () => AlarmSvg,
32+
33+
enabled: () => true,
34+
35+
async exec() {
36+
return null
37+
},
38+
39+
order: 20,
40+
})
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
3+
*
4+
* @author John Molakvoæ <skjnldsv@protonmail.com>
5+
*
6+
* @license AGPL-3.0-or-later
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License as
10+
* published by the Free Software Foundation, either version 3 of the
11+
* License, or (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU Affero General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Affero General Public License
19+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
*
21+
*/
22+
// TODO: remove when/if the actions API supports a separator
23+
// This the last preset action, so we need to add a separator
24+
.files-list__row-action-set-reminder-3 {
25+
margin-bottom: 13px;
26+
27+
&::after {
28+
content: "";
29+
margin: 3px 10px 3px 15px;
30+
border-bottom: 1px solid var(--color-border-dark);
31+
cursor: default;
32+
display: flex;
33+
height: 0;
34+
position: absolute;
35+
left: 0;
36+
right: 0;
37+
}
38+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/**
2+
* @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
3+
*
4+
* @author John Molakvoæ <skjnldsv@protonmail.com>
5+
*
6+
* @license AGPL-3.0-or-later
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License as
10+
* published by the Free Software Foundation, either version 3 of the
11+
* License, or (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU Affero General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Affero General Public License
19+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
*
21+
*/
22+
import type { Node } from '@nextcloud/files'
23+
24+
import { FileAction } from '@nextcloud/files'
25+
import { showError, showSuccess } from '@nextcloud/dialogs'
26+
import { translate as t } from '@nextcloud/l10n'
27+
28+
import { DateTimePreset, getDateString, getDateTime, getVerboseDateString } from '../shared/utils'
29+
import { logger } from '../shared/logger'
30+
import { SET_REMINDER_MENU_ID } from './setReminderMenuAction'
31+
import { setReminder } from '../services/reminderService'
32+
import './setReminderSuggestionActions.scss'
33+
34+
interface ReminderOption {
35+
dateTimePreset: DateTimePreset
36+
label: string
37+
ariaLabel: string
38+
dateString?: string
39+
action?: () => Promise<void>
40+
}
41+
42+
const laterToday: ReminderOption = {
43+
dateTimePreset: DateTimePreset.LaterToday,
44+
label: t('files_reminders', 'Later today'),
45+
ariaLabel: t('files_reminders', 'Set reminder for later today'),
46+
}
47+
48+
const tomorrow: ReminderOption = {
49+
dateTimePreset: DateTimePreset.Tomorrow,
50+
label: t('files_reminders', 'Tomorrow'),
51+
ariaLabel: t('files_reminders', 'Set reminder for tomorrow'),
52+
}
53+
54+
const thisWeekend: ReminderOption = {
55+
dateTimePreset: DateTimePreset.ThisWeekend,
56+
label: t('files_reminders', 'This weekend'),
57+
ariaLabel: t('files_reminders', 'Set reminder for this weekend'),
58+
}
59+
60+
const nextWeek: ReminderOption = {
61+
dateTimePreset: DateTimePreset.NextWeek,
62+
label: t('files_reminders', 'Next week'),
63+
ariaLabel: t('files_reminders', 'Set reminder for next week'),
64+
}
65+
66+
// Generate the default preset actions
67+
export const actions = [laterToday, tomorrow, thisWeekend, nextWeek].map((option): FileAction|null => {
68+
const dateTime = getDateTime(option.dateTimePreset)
69+
if (!dateTime) {
70+
return null
71+
}
72+
73+
return new FileAction({
74+
id: `set-reminder-${option.dateTimePreset}`,
75+
displayName: () => `${option.label} - ${getDateString(dateTime)}`,
76+
title: () => `${option.ariaLabel}${getVerboseDateString(dateTime)}`,
77+
78+
// Empty svg to hide the icon
79+
iconSvgInline: () => '<svg></svg>',
80+
81+
enabled: () => true,
82+
parent: SET_REMINDER_MENU_ID,
83+
84+
async exec(node: Node) {
85+
// Can't really happen, but just in case™
86+
if (!node.fileid) {
87+
logger.error('Failed to set reminder, missing file id')
88+
showError(t('files_reminders', 'Failed to set reminder'))
89+
return null
90+
}
91+
92+
// Set the reminder
93+
try {
94+
await setReminder(node.fileid, dateTime)
95+
showSuccess(t('files_reminders', 'Reminder set for "{fileName}"', { fileName: node.basename }))
96+
} catch (error) {
97+
logger.error('Failed to set reminder', { error })
98+
showError(t('files_reminders', 'Failed to set reminder'))
99+
}
100+
// Silent success as we display our own notification
101+
return null
102+
},
103+
104+
order: 21,
105+
})
106+
}).filter(Boolean) as FileAction[]

0 commit comments

Comments
 (0)