mirror of https://github.com/nextcloud/server
Cleanup updatenotification
- Port away from jquery inside vue - Use modern vue components when possible - Fix some readability isssues particularly on dark theme - Use IInitialState - Use php7.4 Signed-off-by: Carl Schwan <carl@carlschwan.eu> Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
This commit is contained in:
parent
204a700f85
commit
7bd83d9dcf
|
@ -794,10 +794,6 @@ span.version {
|
|||
display: none !important;
|
||||
}
|
||||
}
|
||||
#version.section {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 0;
|
||||
/* section divider lines, none needed for last one */
|
||||
|
@ -818,7 +814,6 @@ span.version {
|
|||
.followupsection {
|
||||
display: block;
|
||||
padding: 0 30px 30px 30px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.app-image {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -901,10 +901,6 @@ span.version {
|
|||
}
|
||||
}
|
||||
|
||||
#version.section {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 0;
|
||||
/* section divider lines, none needed for last one */
|
||||
|
@ -927,7 +923,6 @@ span.version {
|
|||
.followupsection {
|
||||
display: block;
|
||||
padding: 0 30px 30px 30px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.app-image {
|
||||
|
|
|
@ -33,6 +33,7 @@ use OC\User\Backend;
|
|||
use OCP\User\Backend\ICountUsersBackend;
|
||||
use OCA\UpdateNotification\UpdateChecker;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\AppFramework\Services\IInitialState;
|
||||
use OCP\IConfig;
|
||||
use OCP\IDateTimeFormatter;
|
||||
use OCP\IGroupManager;
|
||||
|
@ -44,22 +45,15 @@ use OCP\IUserManager;
|
|||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Admin implements ISettings {
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
/** @var UpdateChecker */
|
||||
private $updateChecker;
|
||||
/** @var IGroupManager */
|
||||
private $groupManager;
|
||||
/** @var IDateTimeFormatter */
|
||||
private $dateTimeFormatter;
|
||||
/** @var IFactory */
|
||||
private $l10nFactory;
|
||||
/** @var IRegistry */
|
||||
private $subscriptionRegistry;
|
||||
/** @var IUserManager */
|
||||
private $userManager;
|
||||
/** @var LoggerInterface */
|
||||
private $logger;
|
||||
private IConfig $config;
|
||||
private UpdateChecker $updateChecker;
|
||||
private IGroupManager $groupManager;
|
||||
private IDateTimeFormatter $dateTimeFormatter;
|
||||
private IFactory $l10nFactory;
|
||||
private IRegistry $subscriptionRegistry;
|
||||
private IUserManager $userManager;
|
||||
private LoggerInterface $logger;
|
||||
private IInitialState $initialState;
|
||||
|
||||
public function __construct(
|
||||
IConfig $config,
|
||||
|
@ -69,7 +63,8 @@ class Admin implements ISettings {
|
|||
IFactory $l10nFactory,
|
||||
IRegistry $subscriptionRegistry,
|
||||
IUserManager $userManager,
|
||||
LoggerInterface $logger
|
||||
LoggerInterface $logger,
|
||||
IInitialState $initialState
|
||||
) {
|
||||
$this->config = $config;
|
||||
$this->updateChecker = $updateChecker;
|
||||
|
@ -79,11 +74,9 @@ class Admin implements ISettings {
|
|||
$this->subscriptionRegistry = $subscriptionRegistry;
|
||||
$this->userManager = $userManager;
|
||||
$this->logger = $logger;
|
||||
$this->initialState = $initialState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TemplateResponse
|
||||
*/
|
||||
public function getForm(): TemplateResponse {
|
||||
$lastUpdateCheckTimestamp = $this->config->getAppValue('core', 'lastupdatedat');
|
||||
$lastUpdateCheck = $this->dateTimeFormatter->formatDateTime($lastUpdateCheckTimestamp);
|
||||
|
@ -131,12 +124,9 @@ class Admin implements ISettings {
|
|||
'notifyGroups' => $this->getSelectedGroups($notifyGroups),
|
||||
'hasValidSubscription' => $hasValidSubscription,
|
||||
];
|
||||
$this->initialState->provideInitialState('data', $params);
|
||||
|
||||
$params = [
|
||||
'json' => json_encode($params),
|
||||
];
|
||||
|
||||
return new TemplateResponse('updatenotification', 'admin', $params, '');
|
||||
return new TemplateResponse('updatenotification', 'admin', [], '');
|
||||
}
|
||||
|
||||
protected function filterChanges(array $changes): array {
|
||||
|
@ -162,8 +152,8 @@ class Admin implements ISettings {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param array $groupIds
|
||||
* @return array
|
||||
* @param list<string> $groupIds
|
||||
* @return list<array{id: string, displayname: string}>
|
||||
*/
|
||||
protected function getSelectedGroups(array $groupIds): array {
|
||||
$result = [];
|
||||
|
@ -174,26 +164,16 @@ class Admin implements ISettings {
|
|||
continue;
|
||||
}
|
||||
|
||||
$result[] = ['value' => $group->getGID(), 'label' => $group->getDisplayName()];
|
||||
$result[] = ['id' => $group->getGID(), 'displayname' => $group->getDisplayName()];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the section ID, e.g. 'sharing'
|
||||
*/
|
||||
public function getSection(): string {
|
||||
return 'overview';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int whether the form should be rather on the top or bottom of
|
||||
* the admin section. The forms are arranged in ascending order of the
|
||||
* priority values. It is required to return a value between 0 and 100.
|
||||
*
|
||||
* E.g.: 70
|
||||
*/
|
||||
public function getPriority(): int {
|
||||
return 11;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
<template>
|
||||
<div id="updatenotification" class="followupsection">
|
||||
<NcSettingsSection id="updatenotification" :title="t('updatenotification', 'Update')">
|
||||
<div class="update">
|
||||
<template v-if="isNewVersionAvailable">
|
||||
<p v-if="versionIsEol">
|
||||
<span class="warning">
|
||||
<span class="icon icon-error-white" />
|
||||
{{ t('updatenotification', 'The version you are running is not maintained anymore. Please make sure to update to a supported version as soon as possible.') }}
|
||||
</span>
|
||||
</p>
|
||||
<NcNoteCard v-if="versionIsEol" type="warning">
|
||||
{{ t('updatenotification', 'The version you are running is not maintained anymore. Please make sure to update to a supported version as soon as possible.') }}
|
||||
</NcNoteCard>
|
||||
|
||||
<p>
|
||||
<span v-html="newVersionAvailableString" /><br>
|
||||
|
@ -109,24 +106,41 @@
|
|||
<p id="oca_updatenotification_groups">
|
||||
{{ t('updatenotification', 'Notify members of the following groups about available updates:') }}
|
||||
<NcMultiselect v-model="notifyGroups"
|
||||
:options="availableGroups"
|
||||
:options="groups"
|
||||
:multiple="true"
|
||||
label="label"
|
||||
track-by="value"
|
||||
:tag-width="75" /><br>
|
||||
:searchable="true"
|
||||
label="displayname"
|
||||
:loading="loadingGroups"
|
||||
:show-no-options="false"
|
||||
:close-on-select="false"
|
||||
track-by="id"
|
||||
:tag-width="75"
|
||||
@search-change="searchGroup" /><br>
|
||||
<em v-if="currentChannel === 'daily' || currentChannel === 'git'">{{ t('updatenotification', 'Only notifications for app updates are available.') }}</em>
|
||||
<em v-if="currentChannel === 'daily'">{{ t('updatenotification', 'The selected update channel makes dedicated notifications for the server obsolete.') }}</em>
|
||||
<em v-if="currentChannel === 'git'">{{ t('updatenotification', 'The selected update channel does not support updates of the server.') }}</em>
|
||||
</p>
|
||||
</div>
|
||||
</NcSettingsSection>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { generateUrl, getRootUrl, generateOcsUrl } from '@nextcloud/router'
|
||||
import NcPopoverMenu from '@nextcloud/vue/dist/Components/NcPopoverMenu'
|
||||
import NcMultiselect from '@nextcloud/vue/dist/Components/NcMultiselect'
|
||||
import NcPopoverMenu from '@nextcloud/vue/dist/Components/NcPopoverMenu.js'
|
||||
import NcMultiselect from '@nextcloud/vue/dist/Components/NcMultiselect.js'
|
||||
import NcSettingsSection from '@nextcloud/vue/dist/Components/NcSettingsSection.js'
|
||||
import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
|
||||
import { VTooltip } from 'v-tooltip'
|
||||
import ClickOutside from 'vue-click-outside'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { showSuccess } from '@nextcloud/dialogs'
|
||||
import debounce from 'debounce'
|
||||
import { getLoggerBuilder } from '@nextcloud/logger'
|
||||
|
||||
const logger = getLoggerBuilder()
|
||||
.setApp('updatenotification')
|
||||
.detectUser()
|
||||
.build()
|
||||
|
||||
VTooltip.options.defaultHtml = false
|
||||
|
||||
|
@ -135,6 +149,8 @@ export default {
|
|||
components: {
|
||||
NcMultiselect,
|
||||
NcPopoverMenu,
|
||||
NcSettingsSection,
|
||||
NcNoteCard,
|
||||
},
|
||||
directives: {
|
||||
ClickOutside,
|
||||
|
@ -142,6 +158,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
loadingGroups: false,
|
||||
newVersionString: '',
|
||||
lastCheckedDate: '',
|
||||
isUpdateChecked: false,
|
||||
|
@ -158,7 +175,7 @@ export default {
|
|||
currentChannel: '',
|
||||
channels: [],
|
||||
notifyGroups: '',
|
||||
availableGroups: [],
|
||||
groups: [],
|
||||
isDefaultUpdateServerURL: true,
|
||||
enableChangeWatcher: false,
|
||||
|
||||
|
@ -174,9 +191,6 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
_$el: null,
|
||||
_$notifyGroups: null,
|
||||
|
||||
computed: {
|
||||
newVersionAvailableString() {
|
||||
return t('updatenotification', 'A new version is available: <strong>{newVersionString}</strong>', {
|
||||
|
@ -293,46 +307,41 @@ export default {
|
|||
watch: {
|
||||
notifyGroups(selectedOptions) {
|
||||
if (!this.enableChangeWatcher) {
|
||||
// The first time is when loading the app
|
||||
this.enableChangeWatcher = true
|
||||
return
|
||||
}
|
||||
|
||||
const selectedGroups = []
|
||||
_.each(selectedOptions, function(group) {
|
||||
selectedGroups.push(group.value)
|
||||
const groups = this.notifyGroups.map(group => {
|
||||
return group.id
|
||||
})
|
||||
|
||||
OCP.AppConfig.setValue('updatenotification', 'notify_groups', JSON.stringify(selectedGroups))
|
||||
OCP.AppConfig.setValue('updatenotification', 'notify_groups', JSON.stringify(groups))
|
||||
},
|
||||
isNewVersionAvailable() {
|
||||
if (!this.isNewVersionAvailable) {
|
||||
return
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: generateOcsUrl('apps/updatenotification/api/v1/applist/{newVersion}', { newVersion: this.newVersion }),
|
||||
type: 'GET',
|
||||
beforeSend(request) {
|
||||
request.setRequestHeader('Accept', 'application/json')
|
||||
},
|
||||
success: function(response) {
|
||||
this.availableAppUpdates = response.ocs.data.available
|
||||
this.missingAppUpdates = response.ocs.data.missing
|
||||
this.isListFetched = true
|
||||
this.appStoreFailed = false
|
||||
}.bind(this),
|
||||
error: function(xhr) {
|
||||
this.availableAppUpdates = []
|
||||
this.missingAppUpdates = []
|
||||
this.appStoreDisabled = xhr.responseJSON.ocs.data.appstore_disabled
|
||||
this.isListFetched = true
|
||||
this.appStoreFailed = true
|
||||
}.bind(this),
|
||||
axios.get(generateOcsUrl('apps/updatenotification/api/v1/applist/{newVersion}', {
|
||||
newVersion: this.newVersion,
|
||||
})).then(({ data }) => {
|
||||
this.availableAppUpdates = data.ocs.data.available
|
||||
this.missingAppUpdates = data.ocs.data.missing
|
||||
this.isListFetched = true
|
||||
this.appStoreFailed = false
|
||||
}).catch(({ data }) => {
|
||||
this.availableAppUpdates = []
|
||||
this.missingAppUpdates = []
|
||||
this.appStoreDisabled = data.ocs.data.appstore_disabled
|
||||
this.isListFetched = true
|
||||
this.appStoreFailed = true
|
||||
})
|
||||
},
|
||||
},
|
||||
beforeMount() {
|
||||
// Parse server data
|
||||
const data = JSON.parse($('#updatenotification').attr('data-json'))
|
||||
const data = loadState('updatenotification', 'data')
|
||||
|
||||
this.newVersion = data.newVersion
|
||||
this.newVersionString = data.newVersionString
|
||||
|
@ -360,51 +369,50 @@ export default {
|
|||
this.whatsNewData = this.whatsNewData.concat(data.changes.whatsNew.regular)
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this._$el = $(this.$el)
|
||||
this._$notifyGroups = this._$el.find('#oca_updatenotification_groups_list')
|
||||
this._$notifyGroups.on('change', function() {
|
||||
this.$emit('input')
|
||||
}.bind(this))
|
||||
|
||||
$.ajax({
|
||||
url: generateOcsUrl('cloud/groups'),
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
const results = []
|
||||
$.each(data.ocs.data.groups, function(i, group) {
|
||||
results.push({ value: group, label: group })
|
||||
})
|
||||
|
||||
this.availableGroups = results
|
||||
this.enableChangeWatcher = true
|
||||
}.bind(this),
|
||||
})
|
||||
this.searchGroup()
|
||||
},
|
||||
|
||||
methods: {
|
||||
searchGroup: debounce(async function(query) {
|
||||
this.loadingGroups = true
|
||||
try {
|
||||
const response = await axios.get(generateOcsUrl('cloud/groups/details'), {
|
||||
search: query,
|
||||
limit: 20,
|
||||
offset: 0,
|
||||
})
|
||||
this.groups = response.data.ocs.data.groups.sort(function(a, b) {
|
||||
return a.displayname.localeCompare(b.displayname)
|
||||
})
|
||||
} catch (err) {
|
||||
logger.error('Could not fetch groups', err)
|
||||
} finally {
|
||||
this.loadingGroups = false
|
||||
}
|
||||
}, 500),
|
||||
/**
|
||||
* Creates a new authentication token and loads the updater URL
|
||||
*/
|
||||
clickUpdaterButton() {
|
||||
$.ajax({
|
||||
url: generateUrl('/apps/updatenotification/credentials'),
|
||||
}).success(function(token) {
|
||||
axios.get(generateUrl('/apps/updatenotification/credentials'))
|
||||
.then(({ data }) => {
|
||||
// create a form to send a proper post request to the updater
|
||||
const form = document.createElement('form')
|
||||
form.setAttribute('method', 'post')
|
||||
form.setAttribute('action', getRootUrl() + '/updater/')
|
||||
const form = document.createElement('form')
|
||||
form.setAttribute('method', 'post')
|
||||
form.setAttribute('action', getRootUrl() + '/updater/')
|
||||
|
||||
const hiddenField = document.createElement('input')
|
||||
hiddenField.setAttribute('type', 'hidden')
|
||||
hiddenField.setAttribute('name', 'updater-secret-input')
|
||||
hiddenField.setAttribute('value', token)
|
||||
const hiddenField = document.createElement('input')
|
||||
hiddenField.setAttribute('type', 'hidden')
|
||||
hiddenField.setAttribute('name', 'updater-secret-input')
|
||||
hiddenField.setAttribute('value', data.token)
|
||||
|
||||
form.appendChild(hiddenField)
|
||||
form.appendChild(hiddenField)
|
||||
|
||||
document.body.appendChild(form)
|
||||
form.submit()
|
||||
})
|
||||
document.body.appendChild(form)
|
||||
form.submit()
|
||||
})
|
||||
},
|
||||
changeReleaseChannelToEnterprise() {
|
||||
this.changeReleaseChannel('enterprise')
|
||||
|
@ -418,15 +426,10 @@ export default {
|
|||
changeReleaseChannel(channel) {
|
||||
this.currentChannel = channel
|
||||
|
||||
$.ajax({
|
||||
url: generateUrl('/apps/updatenotification/channel'),
|
||||
type: 'POST',
|
||||
data: {
|
||||
channel: this.currentChannel,
|
||||
},
|
||||
success(data) {
|
||||
OC.msg.finishedAction('#channel_save_msg', data)
|
||||
},
|
||||
axios.post(generateUrl('/apps/updatenotification/channel'), {
|
||||
channel: this.currentChannel,
|
||||
}).then(({ data }) => {
|
||||
showSuccess(data.data.message)
|
||||
})
|
||||
|
||||
this.openedUpdateChannelMenu = false
|
||||
|
@ -455,8 +458,10 @@ export default {
|
|||
|
||||
<style lang="scss" scoped>
|
||||
#updatenotification {
|
||||
margin-top: -25px;
|
||||
margin-bottom: 200px;
|
||||
& > * {
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
div.update,
|
||||
p:not(.inlineblock) {
|
||||
margin-bottom: 25px;
|
||||
|
|
|
@ -8,6 +8,7 @@ declare(strict_types=1);
|
|||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*/
|
||||
script('updatenotification', 'updatenotification');
|
||||
/** @var array $_ */ ?>
|
||||
<div id="updatenotification" data-json="<?php p($_['json']); ?>"></div>
|
||||
\OCP\Util::addScript('updatenotification', 'updatenotification');
|
||||
?>
|
||||
|
||||
<div id="updatenotification"></div>
|
||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue