Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Enable ESLint for apps and fix all errors #46082

Merged
merged 4 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
9 changes: 9 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,13 @@ module.exports = {
mode: 'typescript',
},
},
overrides: [
// Allow any in tests
{
files: ['**/*.spec.ts'],
rules: {
'@typescript-eslint/no-explicit-any': 'warn',
},
}
],
}
8 changes: 8 additions & 0 deletions __tests__/mock-window.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

window.OC = { ...window.OC }
window.OCA = { ...window.OCA }
window.OCP = { ...window.OCP }
12 changes: 6 additions & 6 deletions apps/comments/src/services/DavClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ const client = createClient(getRootPath())

// set CSRF token header
const setHeaders = (token) => {
client.setHeaders({
// Add this so the server knows it is an request from the browser
'X-Requested-With': 'XMLHttpRequest',
// Inject user auth
requesttoken: token ?? '',
})
client.setHeaders({
// Add this so the server knows it is an request from the browser
'X-Requested-With': 'XMLHttpRequest',
// Inject user auth
requesttoken: token ?? '',
})
}

// refresh headers when request token changes
Expand Down
2 changes: 1 addition & 1 deletion apps/comments/src/services/GetComments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const getDirectoryFiles = function(
// Map all items to a consistent output structure (results)
return responseItems.map(item => {
// Each item should contain a stat object
const props = item.propstat!.prop!;
const props = item.propstat!.prop!

return prepareFileFromProps(props, props.id!.toString(), isDetailed)
})
Expand Down
2 changes: 1 addition & 1 deletion apps/comments/src/utils/cancelableRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const cancelableRequest = function(request) {
const fetch = async function(url, options) {
const response = await request(
url,
Object.assign({ signal }, options)
Object.assign({ signal }, options),
)
return response
}
Expand Down
35 changes: 17 additions & 18 deletions apps/dav/src/components/AbsenceForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
:clear-search-on-blur="() => false"
:user-select="true"
:options="options"
@search="asyncFind"
>
@search="asyncFind">
<template #no-options="{ search }">
{{ search ?$t('dav', 'No results.') : $t('dav', 'Start typing.') }}
</template>
Expand All @@ -51,21 +50,21 @@
</template>

<script>
import { getCurrentUser } from '@nextcloud/auth'
import { showError, showSuccess } from '@nextcloud/dialogs'
import { loadState } from '@nextcloud/initial-state'
import { generateOcsUrl } from '@nextcloud/router'
import { ShareType } from '@nextcloud/sharing'
import { formatDateAsYMD } from '../utils/date.js'
import axios from '@nextcloud/axios'
import debounce from 'debounce'
import logger from '../service/logger.js'

import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
import NcTextArea from '@nextcloud/vue/dist/Components/NcTextArea.js'
import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
import NcDateTimePickerNative from '@nextcloud/vue/dist/Components/NcDateTimePickerNative.js'
import { generateOcsUrl } from '@nextcloud/router'
import { getCurrentUser } from '@nextcloud/auth'
import debounce from 'debounce'
import axios from '@nextcloud/axios'
import { formatDateAsYMD } from '../utils/date.js'
import { loadState } from '@nextcloud/initial-state'
import { showError, showSuccess } from '@nextcloud/dialogs'
import { Type as ShareTypes } from '@nextcloud/sharing'

import logger from '../service/logger.js'

export default {
name: 'AbsenceForm',
Expand All @@ -74,17 +73,17 @@ export default {
NcTextField,
NcTextArea,
NcDateTimePickerNative,
NcSelect
NcSelect,
},
data() {
const { firstDay, lastDay, status, message ,replacementUserId ,replacementUserDisplayName } = loadState('dav', 'absence', {})
const { firstDay, lastDay, status, message, replacementUserId, replacementUserDisplayName } = loadState('dav', 'absence', {})
return {
loading: false,
status: status ?? '',
message: message ?? '',
firstDay: firstDay ? new Date(firstDay) : new Date(),
lastDay: lastDay ? new Date(lastDay) : null,
replacementUserId: replacementUserId ,
replacementUserId,
replacementUser: replacementUserId ? { user: replacementUserId, displayName: replacementUserDisplayName } : null,
searchLoading: false,
options: [],
Expand Down Expand Up @@ -126,10 +125,10 @@ export default {
return {
user: result.uuid || result.value.shareWith,
displayName: result.name || result.label,
subtitle: result.dsc | ''
subtitle: result.dsc | '',
}
},

async asyncFind(query) {
this.searchLoading = true
await this.debounceGetSuggestions(query.trim())
Expand All @@ -142,7 +141,7 @@ export default {
async getSuggestions(search) {

const shareType = [
ShareTypes.SHARE_TYPE_USER,
ShareType.SHARE_TYPE_USER,
]

let request = null
Expand Down
2 changes: 1 addition & 1 deletion apps/dav/src/dav/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ export const getClient = memoize((service) => {
onRequestTokenUpdate(setHeaders)
setHeaders(getRequestToken())

return client;
return client
})
4 changes: 2 additions & 2 deletions apps/dav/src/service/PreferenceService.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export async function enableUserStatusAutomation() {
}),
{
configValue: 'yes',
}
},
)
}

Expand All @@ -29,6 +29,6 @@ export async function disableUserStatusAutomation() {
generateOcsUrl('/apps/provisioning_api/api/v1/config/users/{appId}/{configKey}', {
appId: 'dav',
configKey: 'user_status_automation',
})
}),
)
}
4 changes: 2 additions & 2 deletions apps/dav/src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ const CalDavSettingsView = new View({
sendInvitations: loadState('dav', 'sendInvitations'),
generateBirthdayCalendar: loadState(
'dav',
'generateBirthdayCalendar'
'generateBirthdayCalendar',
),
sendEventReminders: loadState('dav', 'sendEventReminders'),
sendEventRemindersToSharedUsers: loadState(
'dav',
'sendEventRemindersToSharedUsers'
'sendEventRemindersToSharedUsers',
),
sendEventRemindersPush: loadState('dav', 'sendEventRemindersPush'),
}
Expand Down
12 changes: 6 additions & 6 deletions apps/dav/src/views/CalDavSettings.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,27 +54,27 @@ describe('CalDavSettings', () => {
},
Vue => {
Vue.prototype.$t = jest.fn((app, text) => text)
}
},
)
expect(TLUtils.container).toMatchSnapshot()
const sendInvitations = TLUtils.getByLabelText(
'Send invitations to attendees'
'Send invitations to attendees',
)
expect(sendInvitations).toBeChecked()
const generateBirthdayCalendar = TLUtils.getByLabelText(
'Automatically generate a birthday calendar'
'Automatically generate a birthday calendar',
)
expect(generateBirthdayCalendar).toBeChecked()
const sendEventReminders = TLUtils.getByLabelText(
'Send notifications for events'
'Send notifications for events',
)
expect(sendEventReminders).toBeChecked()
const sendEventRemindersToSharedUsers = TLUtils.getByLabelText(
'Send reminder notifications to calendar sharees as well'
'Send reminder notifications to calendar sharees as well',
)
expect(sendEventRemindersToSharedUsers).toBeChecked()
const sendEventRemindersPush = TLUtils.getByLabelText(
'Enable notifications for events via push'
'Enable notifications for events via push',
)
expect(sendEventRemindersPush).toBeChecked()

Expand Down
4 changes: 2 additions & 2 deletions apps/dav/src/views/CalDavSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export default {
OCP.AppConfig.setValue(
'dav',
'sendInvitations',
value ? 'yes' : 'no'
value ? 'yes' : 'no',
)
},
sendEventReminders(value) {
Expand All @@ -138,7 +138,7 @@ export default {
OCP.AppConfig.setValue(
'dav',
'sendEventRemindersToSharedUsers',
value ? 'yes' : 'no'
value ? 'yes' : 'no',
)
},
sendEventRemindersPush(value) {
Expand Down
7 changes: 4 additions & 3 deletions apps/federatedfilesharing/src/components/AdminSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,14 @@
</template>

<script>
import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
import NcSettingsSection from '@nextcloud/vue/dist/Components/NcSettingsSection.js'
import { loadState } from '@nextcloud/initial-state'
import { showError } from '@nextcloud/dialogs'
import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
import { confirmPassword } from '@nextcloud/password-confirmation'
import axios from '@nextcloud/axios'
import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
import NcSettingsSection from '@nextcloud/vue/dist/Components/NcSettingsSection.js'

import '@nextcloud/password-confirmation/dist/style.css'
susnux marked this conversation as resolved.
Show resolved Hide resolved

export default {
Expand Down
4 changes: 2 additions & 2 deletions apps/federatedfilesharing/src/components/PersonalSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M502 197q-96 0-96.5 1.5t-1.5 137-1.5 138-2 2.5T266 432.5 132.5 390t-30 94T74 578l232 77q21 8 21 10t-79.5 117.5T168 899t79.5 56.5T328 1011t81-110 82-110 41 55l83 115q43 60 44 60t79.5-58 79-59-76-112.5-76-113.5T795 632.5t129.5-44-28-94T867 400t-128 42-128.5 43-2.5-7.5-1-38.5l-3-108q-4-133-5-133.5t-97-.5z" /></svg>
</template>
</NcButton>
<NcButton @click="showHtml = !showHtml"
class="social-button__website-button">
<NcButton class="social-button__website-button"
@click="showHtml = !showHtml">
<template #icon>
<Web :size="20" />
</template>
Expand Down
2 changes: 1 addition & 1 deletion apps/federatedfilesharing/src/external.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
}

window.OCA.Sharing._adjustDialog = function() {
const $dialog = $('.oc-dialog:visible')

Check warning on line 65 in apps/federatedfilesharing/src/external.js

View workflow job for this annotation

GitHub Actions / NPM lint

The global property or function $ was deprecated in Nextcloud 19.0.0
const $buttons = $dialog.find('button')
// hack the buttons
$dialog.find('.ui-icon').remove()
Expand Down Expand Up @@ -98,7 +98,7 @@
const callbackAddShare = function(result, share) {
const password = share.password || ''
if (result) {
$.post(

Check warning on line 101 in apps/federatedfilesharing/src/external.js

View workflow job for this annotation

GitHub Actions / NPM lint

The global property or function $ was deprecated in Nextcloud 19.0.0
generateUrl('apps/federatedfilesharing/askForFederatedShare'),
{
remote: share.remote,
Expand All @@ -109,7 +109,7 @@
password,
},
).done(function(data) {
if (data.hasOwnProperty('legacyMount')) {
if (Object.hasOwn(data, 'legacyMount')) {
reloadFilesList()
} else {
window.OC.Notification.showTemporary(data.message)
Expand All @@ -136,7 +136,7 @@
*/
const processSharesToConfirm = function() {
// check for new server-to-server shares which need to be approved
$.get(generateUrl('/apps/files_sharing/api/externalShares'), {}, function(shares) {

Check warning on line 139 in apps/federatedfilesharing/src/external.js

View workflow job for this annotation

GitHub Actions / NPM lint

The global property or function $ was deprecated in Nextcloud 19.0.0
let index
for (index = 0; index < shares.length; ++index) {
window.OCA.Sharing.showAddExternalDialog(
Expand All @@ -145,13 +145,13 @@
function(result, share) {
if (result) {
// Accept
$.post(generateUrl('/apps/files_sharing/api/externalShares'), { id: share.id })

Check warning on line 148 in apps/federatedfilesharing/src/external.js

View workflow job for this annotation

GitHub Actions / NPM lint

The global property or function $ was deprecated in Nextcloud 19.0.0
.then(function() {
reloadFilesList()
})
} else {
// Delete
$.ajax({

Check warning on line 154 in apps/federatedfilesharing/src/external.js

View workflow job for this annotation

GitHub Actions / NPM lint

The global property or function $ was deprecated in Nextcloud 19.0.0
url: generateUrl('/apps/files_sharing/api/externalShares/' + share.id),
type: 'DELETE',
})
Expand All @@ -169,7 +169,7 @@
processSharesToConfirm()
}

$('body').on('window.OCA.Notification.Action', function(e) {

Check warning on line 172 in apps/federatedfilesharing/src/external.js

View workflow job for this annotation

GitHub Actions / NPM lint

The global property or function $ was deprecated in Nextcloud 19.0.0
if (e.notification.app === 'files_sharing' && e.notification.object_type === 'remote_share' && e.action.type === 'POST') {
// User accepted a remote share reload
reloadFilesList()
Expand Down
1 change: 1 addition & 0 deletions apps/files/src/actions/deleteAction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@
expect(axios.delete).toBeCalledTimes(1)
expect(axios.delete).toBeCalledWith('https://cloud.domain.com/remote.php/dav/files/test/foobar.txt')

expect(eventBus.emit).toBeCalledTimes(1)

Check warning on line 185 in apps/files/src/actions/deleteAction.spec.ts

View workflow job for this annotation

GitHub Actions / NPM lint

Caution: `eventBus` also has a named export `emit`. Check if you meant to write `import {emit} from '@nextcloud/event-bus'` instead
expect(eventBus.emit).toBeCalledWith('files:node:deleted', file)

Check warning on line 186 in apps/files/src/actions/deleteAction.spec.ts

View workflow job for this annotation

GitHub Actions / NPM lint

Caution: `eventBus` also has a named export `emit`. Check if you meant to write `import {emit} from '@nextcloud/event-bus'` instead
})

test('Delete action batch', async () => {
Expand All @@ -191,6 +191,7 @@
jest.spyOn(eventBus, 'emit')

const confirmMock = jest.fn()
// @ts-expect-error We only mock what needed
window.OC = { dialogs: { confirmDestructive: confirmMock } }

const file1 = new File({
Expand Down Expand Up @@ -219,8 +220,8 @@
expect(axios.delete).toHaveBeenNthCalledWith(1, 'https://cloud.domain.com/remote.php/dav/files/test/foo.txt')
expect(axios.delete).toHaveBeenNthCalledWith(2, 'https://cloud.domain.com/remote.php/dav/files/test/bar.txt')

expect(eventBus.emit).toBeCalledTimes(2)

Check warning on line 223 in apps/files/src/actions/deleteAction.spec.ts

View workflow job for this annotation

GitHub Actions / NPM lint

Caution: `eventBus` also has a named export `emit`. Check if you meant to write `import {emit} from '@nextcloud/event-bus'` instead
expect(eventBus.emit).toHaveBeenNthCalledWith(1, 'files:node:deleted', file1)

Check warning on line 224 in apps/files/src/actions/deleteAction.spec.ts

View workflow job for this annotation

GitHub Actions / NPM lint

Caution: `eventBus` also has a named export `emit`. Check if you meant to write `import {emit} from '@nextcloud/event-bus'` instead
expect(eventBus.emit).toHaveBeenNthCalledWith(2, 'files:node:deleted', file2)
})

Expand Down
2 changes: 1 addition & 1 deletion apps/files/src/actions/deleteAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export const action = new FileAction({
.every(permission => (permission & Permission.DELETE) !== 0)
},

async exec(node: Node, view: View, dir: string) {
async exec(node: Node) {
susnux marked this conversation as resolved.
Show resolved Hide resolved
try {
await axios.delete(node.encodedSource)

Expand Down
3 changes: 2 additions & 1 deletion apps/files/src/actions/favoriteAction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ const favoriteView = {
name: 'Favorites',
} as View

global.window.OC = {
window.OC = {
...window.OC,
TAG_FAVORITE: '_$!<Favorite>!$_',
}

Expand Down
5 changes: 4 additions & 1 deletion apps/files/src/actions/openFolderAction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ describe('Open folder action enabled tests', () => {
describe('Open folder action execute tests', () => {
test('Open folder', async () => {
const goToRouteMock = jest.fn()
// @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation
window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } }

const folder = new Folder({
Expand All @@ -114,11 +115,12 @@ describe('Open folder action execute tests', () => {
// Silent action
expect(exec).toBe(null)
expect(goToRouteMock).toBeCalledTimes(1)
expect(goToRouteMock).toBeCalledWith(null, { fileid: 1, view: 'files' }, { dir: '/FooBar' })
expect(goToRouteMock).toBeCalledWith(null, { fileid: '1', view: 'files' }, { dir: '/FooBar' })
})

test('Open folder fails without node', async () => {
const goToRouteMock = jest.fn()
// @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation
window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } }

const exec = await action.exec(null as unknown as Node, view, '/')
Expand All @@ -128,6 +130,7 @@ describe('Open folder action execute tests', () => {

test('Open folder fails without Folder', async () => {
const goToRouteMock = jest.fn()
// @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation
window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } }

const file = new File({
Expand Down
2 changes: 1 addition & 1 deletion apps/files/src/actions/openFolderAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const action = new FileAction({

window.OCP.Files.Router.goToRoute(
null,
{ view: view.id, fileid: node.fileid },
{ view: view.id, fileid: String(node.fileid) },
{ dir: node.path },
)
return null
Expand Down
6 changes: 4 additions & 2 deletions apps/files/src/actions/openInFilesAction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ describe('Open in files action enabled tests', () => {
describe('Open in files action execute tests', () => {
test('Open in files', async () => {
const goToRouteMock = jest.fn()
// @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation
window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } }

const file = new File({
Expand All @@ -59,11 +60,12 @@ describe('Open in files action execute tests', () => {
// Silent action
expect(exec).toBe(null)
expect(goToRouteMock).toBeCalledTimes(1)
expect(goToRouteMock).toBeCalledWith(null, { fileid: 1, view: 'files' }, { dir: '/Foo', openfile: 'true' })
expect(goToRouteMock).toBeCalledWith(null, { fileid: '1', view: 'files' }, { dir: '/Foo', openfile: 'true' })
})

test('Open in files with folder', async () => {
const goToRouteMock = jest.fn()
// @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation
window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } }

const file = new Folder({
Expand All @@ -79,6 +81,6 @@ describe('Open in files action execute tests', () => {
// Silent action
expect(exec).toBe(null)
expect(goToRouteMock).toBeCalledTimes(1)
expect(goToRouteMock).toBeCalledWith(null, { fileid: 1, view: 'files' }, { dir: '/Foo/Bar', openfile: 'true' })
expect(goToRouteMock).toBeCalledWith(null, { fileid: '1', view: 'files' }, { dir: '/Foo/Bar', openfile: 'true' })
})
})
2 changes: 1 addition & 1 deletion apps/files/src/actions/openInFilesAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const action = new FileAction({

window.OCP.Files.Router.goToRoute(
null, // use default route
{ view: 'files', fileid: node.fileid },
{ view: 'files', fileid: String(node.fileid) },
{ dir, openfile: 'true' },
)
return null
Expand Down
3 changes: 2 additions & 1 deletion apps/files/src/actions/sidebarAction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ describe('Open sidebar action exec tests', () => {
const openMock = jest.fn()
window.OCA = { Files: { Sidebar: { open: openMock } } }
const goToRouteMock = jest.fn()
// @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation
window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } }

const file = new File({
Expand All @@ -125,7 +126,7 @@ describe('Open sidebar action exec tests', () => {
expect(openMock).toBeCalledWith('/foobar.txt')
expect(goToRouteMock).toBeCalledWith(
null,
{ view: view.id, fileid: 1 },
{ view: view.id, fileid: '1' },
{ dir: '/' },
true,
)
Expand Down
Loading
Loading