Skip to content

Commit

Permalink
Merge pull request #43589 from nextcloud/feat/reminder-status
Browse files Browse the repository at this point in the history
feat(files_reminders): Add reminder status indicator
  • Loading branch information
Pytal authored Mar 9, 2024
2 parents ef319ab + cb68d4b commit 6cf51f9
Show file tree
Hide file tree
Showing 18 changed files with 269 additions and 111 deletions.
2 changes: 1 addition & 1 deletion apps/files/src/components/FileEntry/FileEntryActions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
:key="action.id"
:class="`files-list__row-action-${action.id}`"
class="files-list__row-action--submenu"
:close-after-click="false /* never close submenu, just go back */"
close-after-click
:data-cy-files-list-row-action="action.id"
:title="action.title?.([source], currentView)"
@click="onActionClick(action)">
Expand Down
10 changes: 0 additions & 10 deletions apps/files_reminders/appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ Set file reminders.
<author>Christopher Ng</author>
<namespace>FilesReminders</namespace>

<types>
<dav />
</types>

<category>files</category>

<bugs>https://github.com/nextcloud/server/issues</bugs>
Expand All @@ -33,10 +29,4 @@ Set file reminders.
<commands>
<command>OCA\FilesReminders\Command\ListCommand</command>
</commands>

<sabre>
<plugins>
<plugin>OCA\FilesReminders\Dav\PropFindPlugin</plugin>
</plugins>
</sabre>
</info>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
'OCA\\FilesReminders\\Exception\\UserNotFoundException' => $baseDir . '/../lib/Exception/UserNotFoundException.php',
'OCA\\FilesReminders\\Listener\\LoadAdditionalScriptsListener' => $baseDir . '/../lib/Listener/LoadAdditionalScriptsListener.php',
'OCA\\FilesReminders\\Listener\\NodeDeletedListener' => $baseDir . '/../lib/Listener/NodeDeletedListener.php',
'OCA\\FilesReminders\\Listener\\SabrePluginAddListener' => $baseDir . '/../lib/Listener/SabrePluginAddListener.php',
'OCA\\FilesReminders\\Listener\\UserDeletedListener' => $baseDir . '/../lib/Listener/UserDeletedListener.php',
'OCA\\FilesReminders\\Migration\\Version10000Date20230725162149' => $baseDir . '/../lib/Migration/Version10000Date20230725162149.php',
'OCA\\FilesReminders\\Model\\RichReminder' => $baseDir . '/../lib/Model/RichReminder.php',
Expand Down
1 change: 1 addition & 0 deletions apps/files_reminders/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class ComposerStaticInitFilesReminders
'OCA\\FilesReminders\\Exception\\UserNotFoundException' => __DIR__ . '/..' . '/../lib/Exception/UserNotFoundException.php',
'OCA\\FilesReminders\\Listener\\LoadAdditionalScriptsListener' => __DIR__ . '/..' . '/../lib/Listener/LoadAdditionalScriptsListener.php',
'OCA\\FilesReminders\\Listener\\NodeDeletedListener' => __DIR__ . '/..' . '/../lib/Listener/NodeDeletedListener.php',
'OCA\\FilesReminders\\Listener\\SabrePluginAddListener' => __DIR__ . '/..' . '/../lib/Listener/SabrePluginAddListener.php',
'OCA\\FilesReminders\\Listener\\UserDeletedListener' => __DIR__ . '/..' . '/../lib/Listener/UserDeletedListener.php',
'OCA\\FilesReminders\\Migration\\Version10000Date20230725162149' => __DIR__ . '/..' . '/../lib/Migration/Version10000Date20230725162149.php',
'OCA\\FilesReminders\\Model\\RichReminder' => __DIR__ . '/..' . '/../lib/Model/RichReminder.php',
Expand Down
4 changes: 4 additions & 0 deletions apps/files_reminders/lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@

namespace OCA\FilesReminders\AppInfo;

use OCA\DAV\Events\SabrePluginAddEvent;
use OCA\Files\Event\LoadAdditionalScriptsEvent;
use OCA\FilesReminders\Listener\LoadAdditionalScriptsListener;
use OCA\FilesReminders\Listener\NodeDeletedListener;
use OCA\FilesReminders\Listener\SabrePluginAddListener;
use OCA\FilesReminders\Listener\UserDeletedListener;
use OCA\FilesReminders\Notification\Notifier;
use OCP\AppFramework\App;
Expand All @@ -51,6 +53,8 @@ public function boot(IBootContext $context): void {
public function register(IRegistrationContext $context): void {
$context->registerNotifierService(Notifier::class);

$context->registerEventListener(SabrePluginAddEvent::class, SabrePluginAddListener::class);

$context->registerEventListener(NodeDeletedEvent::class, NodeDeletedListener::class);
$context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class);

Expand Down
51 changes: 51 additions & 0 deletions apps/files_reminders/lib/Listener/SabrePluginAddListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

/**
* @copyright 2024 Christopher Ng <chrng8@gmail.com>
*
* @author Christopher Ng <chrng8@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* 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/>.
*
*/

namespace OCA\FilesReminders\Listener;

use OCA\DAV\Events\SabrePluginAddEvent;
use OCA\FilesReminders\Dav\PropFindPlugin;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use Psr\Container\ContainerInterface;

/** @template-implements IEventListener<SabrePluginAddEvent> */
class SabrePluginAddListener implements IEventListener {
public function __construct(
private ContainerInterface $container,
) {
}

public function handle(Event $event): void {
if (!($event instanceof SabrePluginAddEvent)) {
return;
}

$server = $event->getServer();
$plugin = $this->container->get(PropFindPlugin::class);
$server->addPlugin($plugin);
}
}
4 changes: 2 additions & 2 deletions apps/files_reminders/src/actions/clearReminderAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ import { getVerboseDateString } from '../shared/utils.ts'
export const action = new FileAction({
id: 'clear-reminder',

displayName: () => t('files', 'Clear reminder'),
displayName: () => t('files_reminders', 'Clear reminder'),

title: (nodes: Node[]) => {
const node = nodes.at(0)!
const dueDate = new Date(node.attributes['reminder-due-date'])
return `${t('files', 'Clear reminder')}${getVerboseDateString(dueDate)}`
return `${t('files_reminders', 'Clear reminder')}${getVerboseDateString(dueDate)}`
},

iconSvgInline: () => AlarmOffSvg,
Expand Down
62 changes: 62 additions & 0 deletions apps/files_reminders/src/actions/reminderStatusAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* @copyright 2024 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 { FileAction, type Node } from '@nextcloud/files'
import { translate as t } from '@nextcloud/l10n'

import AlarmSvg from '@mdi/svg/svg/alarm.svg?raw'

import { pickCustomDate } from '../services/customPicker.ts'
import { getVerboseDateString } from '../shared/utils.ts'

export const action = new FileAction({
id: 'reminder-status',

inline: () => true,

displayName: () => '',

title: (nodes: Node[]) => {
const node = nodes.at(0)!
const dueDate = new Date(node.attributes['reminder-due-date'])
return `${t('files_reminders', 'Reminder set')}${getVerboseDateString(dueDate)}`
},

iconSvgInline: () => AlarmSvg,

enabled: (nodes: Node[]) => {
// Only allow on a single node
if (nodes.length !== 1) {
return false
}
const node = nodes.at(0)!
const dueDate = node.attributes['reminder-due-date']
return Boolean(dueDate)
},

async exec(node: Node) {
pickCustomDate(node)
return null
},

order: -15,
})
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { pickCustomDate } from '../services/customPicker'

export const action = new FileAction({
id: 'set-reminder-custom',
displayName: () => t('files', 'Set custom reminder'),
displayName: () => t('files_reminders', 'Set custom reminder'),
title: () => t('files_reminders', 'Set reminder at custom date & time'),
iconSvgInline: () => CalendarClockSvg,

Expand Down
2 changes: 1 addition & 1 deletion apps/files_reminders/src/actions/setReminderMenuAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const SET_REMINDER_MENU_ID = 'set-reminder-menu'

export const action = new FileAction({
id: SET_REMINDER_MENU_ID,
displayName: () => t('files', 'Set reminder'),
displayName: () => t('files_reminders', 'Set reminder'),
iconSvgInline: () => AlarmSvg,

enabled: () => true,
Expand Down
100 changes: 55 additions & 45 deletions apps/files_reminders/src/components/SetCustomReminderModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@
-->

<template>
<NcModal v-if="opened"
<NcDialog v-if="opened"
:name="name"
:out-transition="true"
size="small"
@close="onClose">
<form class="custom-reminder-modal" @submit.prevent="setCustom">
<h2 class="custom-reminder-modal__title">
{{ title }}
</h2>

close-on-click-outside
@closing="onClose">
<form id="set-custom-reminder-form"
class="custom-reminder-modal"
@submit.prevent="setCustom">
<NcDateTimePickerNative id="set-custom-reminder"
v-model="customDueDate"
:label="label"
Expand All @@ -46,21 +46,27 @@
<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 #actions>
<!-- Cancel pick -->
<NcButton type="tertiary" @click="onClose">
{{ t('files_reminders', 'Cancel') }}
</NcButton>

<!-- Clear reminder -->
<NcButton v-if="hasDueDate" @click="clear">
{{ t('files_reminders', 'Clear reminder') }}
</NcButton>

<!-- Set reminder -->
<NcButton :disabled="!isValid"
type="primary"
form="set-custom-reminder-form"
native-type="submit">
{{ t('files_reminders', 'Set reminder') }}
</NcButton>
</template>
</NcDialog>
</template>

<script lang="ts">
Expand All @@ -73,12 +79,12 @@ import { translate as t } from '@nextcloud/l10n'
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 NcDialog from '@nextcloud/vue/dist/Components/NcDialog.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'
import { clearReminder, setReminder } from '../services/reminderService.ts'

export default Vue.extend({
name: 'SetCustomReminderModal',
Expand All @@ -87,17 +93,18 @@ export default Vue.extend({
NcButton,
NcDateTime,
NcDateTimePickerNative,
NcModal,
NcDialog,
NcNoteCard,
},

data() {
return {
node: undefined as Node | undefined,
hasDueDate: false,
opened: false,
isValid: true,

customDueDate: getInitialCustomDueDate() as '' | Date,
customDueDate: null as null | Date,
nowDate: new Date(),
}
},
Expand All @@ -111,7 +118,7 @@ export default Vue.extend({
return this.node.basename
},

title() {
name() {
return t('files_reminders', 'Set reminder for "{fileName}"', { fileName: this.fileName })
},

Expand All @@ -133,18 +140,23 @@ export default Vue.extend({
* and reset the state.
* @param node The node to set a reminder for
*/
async open(node: Node): Promise<void> {
open(node: Node): void {
const dueDate = node.attributes['reminder-due-date'] ? new Date(node.attributes['reminder-due-date']) : null

this.node = node
this.hasDueDate = Boolean(dueDate)
this.isValid = true
this.opened = true
this.customDueDate = getInitialCustomDueDate()
this.customDueDate = dueDate ?? 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()
if (!this.hasDueDate) {
input.showPicker()
}
}, 300)
},

Expand All @@ -167,6 +179,19 @@ export default Vue.extend({
}
},

async clear(): Promise<void> {
try {
await clearReminder(this.fileId)
Vue.set(this.node.attributes, 'reminder-due-date', '')
emit('files:node:updated', this.node)
showSuccess(t('files_reminders', 'Reminder cleared for "{fileName}"', { fileName: this.fileName }))
this.onClose()
} catch (error) {
logger.error('Failed to clear reminder', { error })
showError(t('files_reminders', 'Failed to clear reminder'))
}
},

onClose(): void {
this.opened = false
this.$emit('close')
Expand All @@ -182,21 +207,6 @@ export default Vue.extend({

<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;
}
}
margin: 0 12px;
}
</style>
Loading

0 comments on commit 6cf51f9

Please sign in to comment.