aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files_reminders
diff options
context:
space:
mode:
authorJohn Molakvoæ <skjnldsv@protonmail.com>2023-10-25 09:43:58 +0200
committerJohn Molakvoæ <skjnldsv@protonmail.com>2023-11-08 08:39:01 +0100
commitcf6c921376effdf7e3682388237f675bb1520945 (patch)
treeded738bfb4bd0fe6cf3765f26b9ee24a8564d6d1 /apps/files_reminders
parent72ffd4999a82c242a7f82afd750372a8d49e517e (diff)
downloadnextcloud-server-cf6c921376effdf7e3682388237f675bb1520945.tar.gz
nextcloud-server-cf6c921376effdf7e3682388237f675bb1520945.zip
chore(files_reminders): upgrade to 28 APIs
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
Diffstat (limited to 'apps/files_reminders')
-rw-r--r--apps/files_reminders/lib/Listener/LoadAdditionalScriptsListener.php2
-rw-r--r--apps/files_reminders/src/actions/setReminderCustomAction.ts45
-rw-r--r--apps/files_reminders/src/actions/setReminderMenuAction.ts40
-rw-r--r--apps/files_reminders/src/actions/setReminderSuggestionActions.scss38
-rw-r--r--apps/files_reminders/src/actions/setReminderSuggestionActions.ts106
-rw-r--r--apps/files_reminders/src/components/SetCustomReminderModal.vue199
-rw-r--r--apps/files_reminders/src/components/SetReminderActions.vue272
-rw-r--r--apps/files_reminders/src/init.ts29
-rw-r--r--apps/files_reminders/src/main.ts102
-rw-r--r--apps/files_reminders/src/services/customPicker.ts48
10 files changed, 506 insertions, 375 deletions
diff --git a/apps/files_reminders/lib/Listener/LoadAdditionalScriptsListener.php b/apps/files_reminders/lib/Listener/LoadAdditionalScriptsListener.php
index 1e7f63d8e0d..bc3aa42ff6c 100644
--- a/apps/files_reminders/lib/Listener/LoadAdditionalScriptsListener.php
+++ b/apps/files_reminders/lib/Listener/LoadAdditionalScriptsListener.php
@@ -47,6 +47,6 @@ class LoadAdditionalScriptsListener implements IEventListener {
return;
}
- Util::addScript(Application::APP_ID, 'main');
+ Util::addInitScript(Application::APP_ID, 'init');
}
}
diff --git a/apps/files_reminders/src/actions/setReminderCustomAction.ts b/apps/files_reminders/src/actions/setReminderCustomAction.ts
new file mode 100644
index 00000000000..efcf70dc311
--- /dev/null
+++ b/apps/files_reminders/src/actions/setReminderCustomAction.ts
@@ -0,0 +1,45 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+import { FileAction, Node } from '@nextcloud/files'
+import { translate as t } from '@nextcloud/l10n'
+import CalendarClockSvg from '@mdi/svg/svg/calendar-clock.svg?raw'
+
+import { SET_REMINDER_MENU_ID } from './setReminderMenuAction'
+import { pickCustomDate } from '../services/customPicker'
+
+export const action = new FileAction({
+ id: 'set-reminder-custom',
+ displayName: () => t('files', 'Set custom reminder'),
+ title: () => t('files_reminders', 'Set reminder at custom date & time'),
+ iconSvgInline: () => CalendarClockSvg,
+
+ enabled: () => true,
+ parent: SET_REMINDER_MENU_ID,
+
+ async exec(file: Node) {
+ pickCustomDate(file)
+ return null
+ },
+
+ // After presets
+ order: 22,
+})
diff --git a/apps/files_reminders/src/actions/setReminderMenuAction.ts b/apps/files_reminders/src/actions/setReminderMenuAction.ts
new file mode 100644
index 00000000000..11810413db1
--- /dev/null
+++ b/apps/files_reminders/src/actions/setReminderMenuAction.ts
@@ -0,0 +1,40 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+import { FileAction } from '@nextcloud/files'
+import { translate as t } from '@nextcloud/l10n'
+import AlarmSvg from '@mdi/svg/svg/alarm.svg?raw'
+
+export const SET_REMINDER_MENU_ID = 'set-reminder-menu'
+
+export const action = new FileAction({
+ id: SET_REMINDER_MENU_ID,
+ displayName: () => t('files', 'Set reminder'),
+ iconSvgInline: () => AlarmSvg,
+
+ enabled: () => true,
+
+ async exec() {
+ return null
+ },
+
+ order: 20,
+})
diff --git a/apps/files_reminders/src/actions/setReminderSuggestionActions.scss b/apps/files_reminders/src/actions/setReminderSuggestionActions.scss
new file mode 100644
index 00000000000..16964e9ae2f
--- /dev/null
+++ b/apps/files_reminders/src/actions/setReminderSuggestionActions.scss
@@ -0,0 +1,38 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+ // TODO: remove when/if the actions API supports a separator
+ // This the last preset action, so we need to add a separator
+.files-list__row-action-set-reminder-3 {
+ margin-bottom: 13px;
+
+ &::after {
+ content: "";
+ margin: 3px 10px 3px 15px;
+ border-bottom: 1px solid var(--color-border-dark);
+ cursor: default;
+ display: flex;
+ height: 0;
+ position: absolute;
+ left: 0;
+ right: 0;
+ }
+}
diff --git a/apps/files_reminders/src/actions/setReminderSuggestionActions.ts b/apps/files_reminders/src/actions/setReminderSuggestionActions.ts
new file mode 100644
index 00000000000..453bab4c5c1
--- /dev/null
+++ b/apps/files_reminders/src/actions/setReminderSuggestionActions.ts
@@ -0,0 +1,106 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+import type { Node } from '@nextcloud/files'
+
+import { FileAction } from '@nextcloud/files'
+import { showError, showSuccess } from '@nextcloud/dialogs'
+import { translate as t } from '@nextcloud/l10n'
+
+import { DateTimePreset, getDateString, getDateTime, getVerboseDateString } from '../shared/utils'
+import { logger } from '../shared/logger'
+import { SET_REMINDER_MENU_ID } from './setReminderMenuAction'
+import { setReminder } from '../services/reminderService'
+import './setReminderSuggestionActions.scss'
+
+interface ReminderOption {
+ dateTimePreset: DateTimePreset
+ label: string
+ ariaLabel: string
+ dateString?: string
+ action?: () => Promise<void>
+}
+
+const laterToday: ReminderOption = {
+ dateTimePreset: DateTimePreset.LaterToday,
+ label: t('files_reminders', 'Later today'),
+ ariaLabel: t('files_reminders', 'Set reminder for later today'),
+}
+
+const tomorrow: ReminderOption = {
+ dateTimePreset: DateTimePreset.Tomorrow,
+ label: t('files_reminders', 'Tomorrow'),
+ ariaLabel: t('files_reminders', 'Set reminder for tomorrow'),
+}
+
+const thisWeekend: ReminderOption = {
+ dateTimePreset: DateTimePreset.ThisWeekend,
+ label: t('files_reminders', 'This weekend'),
+ ariaLabel: t('files_reminders', 'Set reminder for this weekend'),
+}
+
+const nextWeek: ReminderOption = {
+ dateTimePreset: DateTimePreset.NextWeek,
+ label: t('files_reminders', 'Next week'),
+ ariaLabel: t('files_reminders', 'Set reminder for next week'),
+}
+
+// Generate the default preset actions
+export const actions = [laterToday, tomorrow, thisWeekend, nextWeek].map((option): FileAction|null => {
+ const dateTime = getDateTime(option.dateTimePreset)
+ if (!dateTime) {
+ return null
+ }
+
+ return new FileAction({
+ id: `set-reminder-${option.dateTimePreset}`,
+ displayName: () => `${option.label} - ${getDateString(dateTime)}`,
+ title: () => `${option.ariaLabel} – ${getVerboseDateString(dateTime)}`,
+
+ // Empty svg to hide the icon
+ iconSvgInline: () => '<svg></svg>',
+
+ enabled: () => true,
+ parent: SET_REMINDER_MENU_ID,
+
+ async exec(node: Node) {
+ // Can't really happen, but just in case™
+ if (!node.fileid) {
+ logger.error('Failed to set reminder, missing file id')
+ showError(t('files_reminders', 'Failed to set reminder'))
+ return null
+ }
+
+ // Set the reminder
+ try {
+ await setReminder(node.fileid, dateTime)
+ showSuccess(t('files_reminders', 'Reminder set for "{fileName}"', { fileName: node.basename }))
+ } catch (error) {
+ logger.error('Failed to set reminder', { error })
+ showError(t('files_reminders', 'Failed to set reminder'))
+ }
+ // Silent success as we display our own notification
+ return null
+ },
+
+ order: 21,
+ })
+}).filter(Boolean) as FileAction[]
diff --git a/apps/files_reminders/src/components/SetCustomReminderModal.vue b/apps/files_reminders/src/components/SetCustomReminderModal.vue
new file mode 100644
index 00000000000..c4023d1c39b
--- /dev/null
+++ b/apps/files_reminders/src/components/SetCustomReminderModal.vue
@@ -0,0 +1,199 @@
+<!--
+ - @copyright 2023 Christopher Ng <chrng8@gmail.com>
+ -
+ - @author Christopher Ng <chrng8@gmail.com>
+ -
+ - @license AGPL-3.0-or-later
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -
+-->
+
+<template>
+ <NcModal v-if="opened"
+ :out-transition="true"
+ size="small"
+ @close="onClose">
+ <form class="custom-reminder-modal" @submit.prevent="setCustom">
+ <h2 class="custom-reminder-modal__title">
+ {{ title }}
+ </h2>
+
+ <NcDateTimePickerNative id="set-custom-reminder"
+ v-model="customDueDate"
+ :label="label"
+ :min="nowDate"
+ :required="true"
+ type="datetime-local"
+ @input="onInput" />
+
+ <NcNoteCard v-if="isValid" type="info">
+ {{ t('files_reminders', 'We will remind you of this file') }}
+ <NcDateTime :timestamp="customDueDate" />
+ </NcNoteCard>
+
+ <NcNoteCard v-else type="error">
+ {{ t('files_reminders', 'Please choose a valid date & time') }}
+ </NcNoteCard>
+
+ <!-- Buttons -->
+ <div class="custom-reminder-modal__buttons">
+ <!-- Cancel pick -->
+ <NcButton @click="onClose">
+ {{ t('files_reminders', 'Cancel') }}
+ </NcButton>
+
+ <!-- Set reminder -->
+ <NcButton :disabled="!isValid" native-type="submit" type="primary">
+ {{ t('files_reminders', 'Set reminder') }}
+ </NcButton>
+ </div>
+ </form>
+ </NcModal>
+</template>
+
+<script lang="ts">
+import type { Node } from '@nextcloud/files'
+import { showError, showSuccess } from '@nextcloud/dialogs'
+import { translate as t } from '@nextcloud/l10n'
+import Vue from 'vue'
+
+import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
+import NcDateTime from '@nextcloud/vue/dist/Components/NcDateTime.js'
+import NcDateTimePickerNative from '@nextcloud/vue/dist/Components/NcDateTimePickerNative.js'
+import NcModal from '@nextcloud/vue/dist/Components/NcModal.js'
+import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
+
+import { getDateString, getInitialCustomDueDate } from '../shared/utils.ts'
+import { logger } from '../shared/logger.ts'
+import { setReminder } from '../services/reminderService.ts'
+
+export default Vue.extend({
+ name: 'SetCustomReminderModal',
+
+ components: {
+ NcButton,
+ NcDateTime,
+ NcDateTimePickerNative,
+ NcModal,
+ NcNoteCard,
+ },
+
+ data() {
+ return {
+ node: undefined as Node | undefined,
+ opened: false,
+ isValid: true,
+
+ customDueDate: getInitialCustomDueDate() as '' | Date,
+ nowDate: new Date(),
+ }
+ },
+
+ computed: {
+ fileId(): number {
+ return this.node.fileid
+ },
+
+ fileName(): string {
+ return this.node.basename
+ },
+
+ title() {
+ return t('files_reminders', 'Set reminder for "{fileName}"', { fileName: this.fileName })
+ },
+
+ label(): string {
+ return t('files_reminders', 'Set reminder at custom date & time')
+ },
+
+ clearAriaLabel(): string {
+ return t('files_reminders', 'Clear reminder')
+ },
+ },
+
+ methods: {
+ t,
+ getDateString,
+
+ /**
+ * Open the modal to set a custom reminder
+ * and reset the state.
+ * @param node The node to set a reminder for
+ */
+ async open(node: Node): Promise<void> {
+ this.node = node
+ this.isValid = true
+ this.opened = true
+ this.customDueDate = getInitialCustomDueDate()
+ this.nowDate = new Date()
+
+ // Focus the input and show the picker after the animation
+ setTimeout(() => {
+ const input = document.getElementById('set-custom-reminder') as HTMLInputElement
+ input.focus()
+ input.showPicker()
+ }, 300)
+ },
+
+ async setCustom(): Promise<void> {
+ // Handle input cleared
+ if (this.customDueDate === '') {
+ showError(t('files_reminders', 'Please choose a valid date & time'))
+ return
+ }
+
+ try {
+ await setReminder(this.fileId, this.customDueDate)
+ showSuccess(t('files_reminders', 'Reminder set for "{fileName}"', { fileName: this.fileName }))
+ this.onClose()
+ } catch (error) {
+ logger.error('Failed to set reminder', { error })
+ showError(t('files_reminders', 'Failed to set reminder'))
+ }
+ },
+
+ onClose(): void {
+ this.opened = false
+ this.$emit('close')
+ },
+
+ onInput(): void {
+ const input = document.getElementById('set-custom-reminder') as HTMLInputElement
+ this.isValid = input.checkValidity()
+ },
+ },
+})
+</script>
+
+<style lang="scss" scoped>
+.custom-reminder-modal {
+ margin: 30px;
+
+ &__title {
+ font-size: 16px;
+ line-height: 2em;
+ }
+
+ &__buttons {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 30px;
+
+ button {
+ margin-left: 10px;
+ }
+ }
+}
+</style>
diff --git a/apps/files_reminders/src/components/SetReminderActions.vue b/apps/files_reminders/src/components/SetReminderActions.vue
deleted file mode 100644
index bf0b417a355..00000000000
--- a/apps/files_reminders/src/components/SetReminderActions.vue
+++ /dev/null
@@ -1,272 +0,0 @@
-<!--
- - @copyright 2023 Christopher Ng <chrng8@gmail.com>
- -
- - @author Christopher Ng <chrng8@gmail.com>
- -
- - @license AGPL-3.0-or-later
- -
- - This program is free software: you can redistribute it and/or modify
- - it under the terms of the GNU Affero General Public License as
- - published by the Free Software Foundation, either version 3 of the
- - License, or (at your option) any later version.
- -
- - This program is distributed in the hope that it will be useful,
- - but WITHOUT ANY WARRANTY; without even the implied warranty of
- - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- - GNU Affero General Public License for more details.
- -
- - You should have received a copy of the GNU Affero General Public License
- - along with this program. If not, see <http://www.gnu.org/licenses/>.
- -
--->
-
-<template>
- <NcActions class="actions-secondary-vue"
- :open.sync="open">
- <NcActionButton @click="$emit('back')">
- <template #icon>
- <ArrowLeft :size="20" />
- </template>
- {{ t('files_reminders', 'Back') }}
- </NcActionButton>
-
- <NcActionButton v-if="Boolean(dueDate)"
- :aria-label="clearAriaLabel"
- @click="clear">
- <template #icon>
- <CloseCircleOutline :size="20" />
- </template>
- {{ t('files_reminders', 'Clear reminder') }} – {{ getDateString(dueDate) }}
- </NcActionButton>
-
- <NcActionSeparator />
-
- <NcActionButton v-for="({ label, ariaLabel, dateString, action }) in options"
- :key="label"
- :aria-label="ariaLabel"
- @click="action">
- {{ label }} – {{ dateString }}
- </NcActionButton>
-
- <NcActionSeparator />
-
- <NcActionInput type="datetime-local"
- is-native-picker
- :min="now"
- v-model="customDueDate">
- <template #icon>
- <CalendarClock :size="20" />
- </template>
- </NcActionInput>
-
- <NcActionButton :aria-label="customAriaLabel"
- @click="setCustom">
- <template #icon>
- <Check :size="20" />
- </template>
- {{ t('files_reminders', 'Set custom reminder') }}
- </NcActionButton>
- </NcActions>
-</template>
-
-<script lang="ts">
-import Vue, { type PropType } from 'vue'
-import { translate as t } from '@nextcloud/l10n'
-import { showError, showSuccess } from '@nextcloud/dialogs'
-
-import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
-import NcActionInput from '@nextcloud/vue/dist/Components/NcActionInput.js'
-import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
-import NcActionSeparator from '@nextcloud/vue/dist/Components/NcActionSeparator.js'
-
-import ArrowLeft from 'vue-material-design-icons/ArrowLeft.vue'
-import CalendarClock from 'vue-material-design-icons/CalendarClock.vue'
-import Check from 'vue-material-design-icons/Check.vue'
-import CloseCircleOutline from 'vue-material-design-icons/CloseCircleOutline.vue'
-
-import { clearReminder, setReminder } from '../services/reminderService.ts'
-import {
- DateTimePreset,
- getDateString,
- getDateTime,
- getInitialCustomDueDate,
- getVerboseDateString,
-} from '../shared/utils.ts'
-import { logger } from '../shared/logger.ts'
-
-import type { FileAttributes } from '../shared/types.ts'
-
-interface ReminderOption {
- dateTimePreset: DateTimePreset
- label: string
- ariaLabel: string
- dateString?: string
- action?: () => Promise<void>
-}
-
-const laterToday: ReminderOption = {
- dateTimePreset: DateTimePreset.LaterToday,
- label: t('files_reminders', 'Later today'),
- ariaLabel: t('files_reminders', 'Set reminder for later today'),
-}
-
-const tomorrow: ReminderOption = {
- dateTimePreset: DateTimePreset.Tomorrow,
- label: t('files_reminders', 'Tomorrow'),
- ariaLabel: t('files_reminders', 'Set reminder for tomorrow'),
-}
-
-const thisWeekend: ReminderOption = {
- dateTimePreset: DateTimePreset.ThisWeekend,
- label: t('files_reminders', 'This weekend'),
- ariaLabel: t('files_reminders', 'Set reminder for this weekend'),
-}
-
-const nextWeek: ReminderOption = {
- dateTimePreset: DateTimePreset.NextWeek,
- label: t('files_reminders', 'Next week'),
- ariaLabel: t('files_reminders', 'Set reminder for next week'),
-}
-
-export default Vue.extend({
- name: 'SetReminderActions',
-
- components: {
- ArrowLeft,
- CalendarClock,
- Check,
- CloseCircleOutline,
- NcActionButton,
- NcActionInput,
- NcActions,
- NcActionSeparator,
- },
-
- props: {
- file: {
- type: Object as PropType<FileAttributes>,
- required: true,
- },
-
- dueDate: {
- type: Date as PropType<null | Date>,
- default: null,
- },
- },
-
- data() {
- return {
- open: true,
- now: new Date(),
- customDueDate: getInitialCustomDueDate() as '' | Date,
- }
- },
-
- watch: {
- open(isOpen) {
- if (!isOpen) {
- this.$emit('close')
- }
- },
- },
-
- computed: {
- fileId(): number {
- return this.file.id
- },
-
- fileName(): string {
- return this.file.name
- },
-
- clearAriaLabel(): string {
- return `${t('files_reminders', 'Clear reminder')} – ${getVerboseDateString(this.dueDate as Date)}`
- },
-
- customAriaLabel(): null | string {
- if (this.customDueDate === '') {
- return null
- }
- return `${t('files_reminders', 'Set reminder at custom date & time')} – ${getVerboseDateString(this.customDueDate)}`
- },
-
- options(): ReminderOption[] {
- const computeOption = (option: ReminderOption): null | ReminderOption => {
- const dateTime = getDateTime(option.dateTimePreset)
- if (!dateTime) {
- return null
- }
- return {
- ...option,
- ariaLabel: `${option.ariaLabel} – ${getVerboseDateString(dateTime)}`,
- dateString: getDateString(dateTime),
- action: () => this.set(dateTime),
- }
- }
-
- const options = [
- laterToday,
- tomorrow,
- thisWeekend,
- nextWeek,
- ]
- return options
- .map(computeOption)
- .filter(Boolean) as ReminderOption[]
- },
- },
-
- methods: {
- t,
- getDateString,
-
- async set(dueDate: Date): Promise<void> {
- try {
- await setReminder(this.fileId, dueDate)
- showSuccess(t('files_reminders', 'Reminder set for "{fileName}"', { fileName: this.fileName }))
- this.open = false
- } catch (error) {
- logger.error('Failed to set reminder', { error })
- showError(t('files_reminders', 'Failed to set reminder'))
- }
- },
-
- async setCustom(): Promise<void> {
- // Handle input cleared
- if (this.customDueDate === '') {
- showError(t('files_reminders', 'Please choose a valid date & time'))
- return
- }
-
- try {
- await setReminder(this.fileId, this.customDueDate)
- showSuccess(t('files_reminders', 'Reminder set for "{fileName}"', { fileName: this.fileName }))
- this.open = false
- } catch (error) {
- logger.error('Failed to set reminder', { error })
- showError(t('files_reminders', 'Failed to set reminder'))
- }
- },
-
- async clear(): Promise<void> {
- try {
- await clearReminder(this.fileId)
- showSuccess(t('files_reminders', 'Reminder cleared'))
- this.open = false
- } catch (error) {
- logger.error('Failed to clear reminder', { error })
- showError(t('files_reminders', 'Failed to clear reminder'))
- }
- },
- },
-})
-</script>
-
-<style lang="scss" scoped>
-.actions-secondary-vue {
- display: block !important;
- float: right !important;
- padding: 5px 0 0 4px !important;
- pointer-events: none !important; // prevent activation of file row
-}
-</style>
diff --git a/apps/files_reminders/src/init.ts b/apps/files_reminders/src/init.ts
new file mode 100644
index 00000000000..59f5d23ebe3
--- /dev/null
+++ b/apps/files_reminders/src/init.ts
@@ -0,0 +1,29 @@
+/**
+ * @copyright 2023 Christopher Ng <chrng8@gmail.com>
+ *
+ * @author Christopher Ng <chrng8@gmail.com>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+import { registerFileAction } from '@nextcloud/files'
+import { action as menuAction } from './actions/setReminderMenuAction'
+import { actions as suggestionActions } from './actions/setReminderSuggestionActions'
+import { action as customAction } from './actions/setReminderCustomAction'
+
+registerFileAction(menuAction)
+registerFileAction(customAction)
+suggestionActions.forEach((action) => registerFileAction(action))
diff --git a/apps/files_reminders/src/main.ts b/apps/files_reminders/src/main.ts
deleted file mode 100644
index b03f0b12ba6..00000000000
--- a/apps/files_reminders/src/main.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * @copyright 2023 Christopher Ng <chrng8@gmail.com>
- *
- * @author Christopher Ng <chrng8@gmail.com>
- *
- * @license AGPL-3.0-or-later
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-import Vue, { type ComponentInstance } from 'vue'
-import { subscribe } from '@nextcloud/event-bus'
-import { showError } from '@nextcloud/dialogs'
-import { translate as t } from '@nextcloud/l10n'
-
-import SetReminderActionsComponent from './components/SetReminderActions.vue'
-
-import { getReminder } from './services/reminderService.js'
-import { logger } from './shared/logger.js'
-
-import type { FileAttributes } from './shared/types.js'
-
-interface FileContext {
- [key: string]: any
- $file: JQuery<HTMLTableRowElement>
- fileInfoModel: {
- [key: string]: any
- attributes: FileAttributes
- }
-}
-
-interface EventPayload {
- el: HTMLDivElement
- context: FileContext
-}
-
-const handleOpen = async (payload: EventPayload) => {
- const fileId = payload.context.fileInfoModel.attributes.id
- const menuEl = payload.context.$file[0].querySelector('.fileactions .action-menu') as HTMLLinkElement
- const linkEl = payload.el.querySelector('.action-setreminder-container .action-setreminder') as HTMLLinkElement
-
- let dueDate: null | Date = null
- let error: null | any = null
- try {
- dueDate = (await getReminder(fileId)).dueDate
- } catch (e) {
- error = e
- logger.error(`Failed to load reminder for file with id: ${fileId}`, { error })
- }
-
- linkEl.addEventListener('click', (_event) => {
- if (error) {
- showError(t('files_reminders', 'Failed to load reminder'))
- throw Error()
- }
-
- const mountPoint = document.createElement('div')
- const SetReminderActions = Vue.extend(SetReminderActionsComponent)
-
- const origDisplay = menuEl.style.display
- menuEl.style.display = 'none'
- menuEl.insertAdjacentElement('afterend', mountPoint)
-
- const propsData = {
- file: payload.context.fileInfoModel.attributes,
- dueDate,
- }
- const actions = (new SetReminderActions({ propsData }) as ComponentInstance)
- .$mount(mountPoint)
-
- const cleanUp = () => {
- actions.$destroy() // destroy popper
- actions.$el.remove() // remove action menu button
- menuEl.style.display = origDisplay
- }
-
- actions.$once('back', () => {
- cleanUp()
- menuEl.click() // reopen original actions menu
- })
-
- actions.$once('close', () => {
- cleanUp()
- })
- }, {
- once: true,
- })
-}
-
-subscribe('files:action-menu:opened', handleOpen)
diff --git a/apps/files_reminders/src/services/customPicker.ts b/apps/files_reminders/src/services/customPicker.ts
new file mode 100644
index 00000000000..3a15cd514f8
--- /dev/null
+++ b/apps/files_reminders/src/services/customPicker.ts
@@ -0,0 +1,48 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+import type { Node } from '@nextcloud/files'
+import Vue from 'vue'
+
+import SetCustomReminderModal from '../components/SetCustomReminderModal.vue'
+
+const View = Vue.extend(SetCustomReminderModal)
+const mount = document.createElement('div')
+mount.id = 'set-custom-reminder-modal'
+document.body.appendChild(mount)
+
+// Create a new Vue instance and mount it to our modal container
+const CustomReminderModal = new View({
+ name: 'SetCustomReminderModal',
+ el: mount,
+})
+
+export const pickCustomDate = async (node: Node): Promise<void> => {
+ console.debug('CustomReminderModal', mount, CustomReminderModal)
+
+ CustomReminderModal.open(node)
+
+ // Wait for the modal to close
+ return new Promise((resolve) => {
+ CustomReminderModal.$on('close', resolve)
+ })
+}