diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..9efea1fac --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = tab +indent_size = 4 +trim_trailing_whitespace = true + +[package*.json] +indent_size = 2 +indent_style = space + +[*.md] +trim_trailing_whitespace = false + +[*.svg] +insert_final_newline = false + +[*.{yml,yaml}] +indent_size = 2 +indent_style = space diff --git a/.eslintrc.js b/.eslintrc.js index 193638c5f..0eec952ff 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,17 +1,17 @@ module.exports = { globals: { - appVersion: true + appVersion: true, }, parserOptions: { - requireConfigFile: false + requireConfigFile: false, }, - extends: [ - '@nextcloud' - ], + extends: ['@nextcloud'], rules: { 'jsdoc/require-jsdoc': 'off', 'jsdoc/tag-lines': 'off', 'vue/first-attribute-linebreak': 'off', - 'import/extensions': 'off' - } + 'import/extensions': 'off', + 'max-len': ['error', { code: 120 }], + }, + ignorePatterns: ['node_modules/*', 'js/*', 'vendor/*', 'dev/apps/*', 'l10n/*'], } diff --git a/jest.config.js b/jest.config.js index c7fcfab8b..9c74101ce 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,3 @@ -const path = require('path') -const rootDir = path.resolve(__dirname, '../../../') - module.exports = { testMatch: ['**/tests/**/*.spec.{js,ts}'], moduleNameMapper: { @@ -10,6 +7,7 @@ module.exports = { transform: { // process *.vue files with vue-jest '\\.vue$': '@vue/vue2-jest', + // eslint-disable-next-line max-len '.+\\.(css|styl|less|sass|scss|jpg|jpeg|png|svg|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|avif)$': 'jest-transform-stub', '\\.c?js$': 'babel-jest', diff --git a/package.json b/package.json index 42801c648..5545c6103 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,11 @@ "scripts": { "build": "NODE_ENV=production webpack --progress --config webpack.js", "dev": "NODE_ENV=development webpack --progress --config webpack.js", - "watch": "NODE_ENV=development webpack --progress --watch --config webpack.js", + "watch": "npm run dev -- --watch", "lint": "eslint --ext .js,.vue src tests", - "lint:fix": "eslint --ext .js,.vue src tests --fix", + "lint:fix": "npm run lint -- --fix", "stylelint": "stylelint css src", - "stylelint:fix": "stylelint css src --fix", + "stylelint:fix": "npm run stylelint -- --fix", "test:unit": "jest --silent", "test:unit:watch": "jest --watch --no-coverage" }, diff --git a/src/adminSettings.js b/src/adminSettings.js index 6708b7a88..279ec72a6 100644 --- a/src/adminSettings.js +++ b/src/adminSettings.js @@ -15,10 +15,10 @@ import Vue from 'vue' import './bootstrap.js' import AdminSettings from './components/AdminSettings.vue' -// eslint-disable-next-line +// eslint-disable-next-line no-unused-expressions 'use strict' -// eslint-disable-next-line +// eslint-disable-next-line no-new new Vue({ el: '#openproject_prefs', render: h => h(AdminSettings), diff --git a/src/personalSettings.js b/src/personalSettings.js index 4b0dc92a6..ed29783e1 100644 --- a/src/personalSettings.js +++ b/src/personalSettings.js @@ -15,10 +15,10 @@ import Vue from 'vue' import './bootstrap.js' import PersonalSettings from './components/PersonalSettings.vue' -// eslint-disable-next-line +// eslint-disable-next-line no-unused-expressions 'use strict' -// eslint-disable-next-line +// eslint-disable-next-line no-new new Vue({ el: '#openproject_prefs', render: h => h(PersonalSettings), diff --git a/src/reference.js b/src/reference.js index c27b23269..135c4e883 100644 --- a/src/reference.js +++ b/src/reference.js @@ -30,7 +30,9 @@ __webpack_public_path__ = OC.linkTo('integration_openproject', 'js/') // eslint- registerWidget('integration_openproject_work_package', async (el, { richObjectType, richObject, accessible }) => { // here we lazy load the components so it does not slow down the initial page load const { default: Vue } = await import(/* webpackChunkName: "reference-wp-lazy" */'vue') - const { default: WorkPackageReferenceWidget } = await import(/* webpackChunkName: "reference-wp-lazy" */'./views/WorkPackageReferenceWidget.vue') + const { default: WorkPackageReferenceWidget } = await import( + /* webpackChunkName: "reference-wp-lazy" */'./views/WorkPackageReferenceWidget.vue' + ) Vue.mixin({ methods: { t, n } }) const Widget = Vue.extend(WorkPackageReferenceWidget) new Widget({ @@ -44,7 +46,8 @@ registerWidget('integration_openproject_work_package', async (el, { richObjectTy registerCustomPickerElement('openproject-work-package-ref', async (el, { providerId, accessible }) => { const { default: Vue } = await import(/* webpackChunkName: "reference-picker-lazy" */'vue') - const { default: WorkPackagePickerElement } = await import(/* webpackChunkName: "reference-picker-lazy" */'./views/WorkPackagePickerElement.vue') + const { default: WorkPackagePickerElement } = await import( + /* webpackChunkName: "reference-picker-lazy" */'./views/WorkPackagePickerElement.vue') Vue.mixin({ methods: { t, n } }) const Element = Vue.extend(WorkPackagePickerElement) diff --git a/src/utils.js b/src/utils.js index 77b955e27..a4c3e3015 100644 --- a/src/utils.js +++ b/src/utils.js @@ -56,8 +56,14 @@ export const WORKPACKAGES_SEARCH_ORIGIN = { LINK_MULTIPLE_FILES_MODAL: 'link-multiple-files-modal', } export const USER_SETTINGS = { - NAVIGATION_LINK_DESCRIPTION: t('integration_openproject', 'Displays a link to your OpenProject instance in the Nextcloud header.'), - UNIFIED_SEARCH_DESCRIPTION: t('integration_openproject', 'Allows you to search OpenProject work packages via the universal search bar in Nextcloud.'), + NAVIGATION_LINK_DESCRIPTION: t( + 'integration_openproject', + 'Displays a link to your OpenProject instance in the Nextcloud header.', + ), + UNIFIED_SEARCH_DESCRIPTION: t( + 'integration_openproject', + 'Allows you to search OpenProject work packages via the universal search bar in Nextcloud.', + ), } export const NO_OPTION_TEXT_STATE = { diff --git a/stylelint.config.js b/stylelint.config.js index 297320188..665d87a3b 100644 --- a/stylelint.config.js +++ b/stylelint.config.js @@ -3,6 +3,6 @@ stylelintConfig.rules = { ...stylelintConfig.rules, 'declaration-colon-space-after': 'always', 'max-empty-lines': 1, - "block-opening-brace-space-before": "always" + 'block-opening-brace-space-before': 'always', } module.exports = stylelintConfig diff --git a/tests/jest/views/LinkMultipleFilesModal.spec.js b/tests/jest/views/LinkMultipleFilesModal.spec.js index 60e698c6b..292704295 100644 --- a/tests/jest/views/LinkMultipleFilesModal.spec.js +++ b/tests/jest/views/LinkMultipleFilesModal.spec.js @@ -161,11 +161,14 @@ describe('LinkMultipleFilesModal.vue', () => { beforeEach(() => { wrapper = mountWrapper() }) - it.each([STATE.NO_TOKEN, STATE.ERROR, STATE.OK])('shows the empty message when state is other than loading', async (state) => { - await wrapper.setData({ state }) - await localVue.nextTick() - expect(wrapper.find(emptyContentSelector).exists()).toBeTruthy() - }) + it.each([STATE.NO_TOKEN, STATE.ERROR, STATE.OK])( + 'shows the empty message when state is other than loading', + async (state) => { + await wrapper.setData({ state }) + await localVue.nextTick() + expect(wrapper.find(emptyContentSelector).exists()).toBeTruthy() + }, + ) it('shows message "Add a new link to all selected files" when admin config is okay', async () => { wrapper = mount(LinkMultipleFilesModal, { diff --git a/tests/jest/views/ProjectsTab.spec.js b/tests/jest/views/ProjectsTab.spec.js index 515e48ce8..3aad46096 100644 --- a/tests/jest/views/ProjectsTab.spec.js +++ b/tests/jest/views/ProjectsTab.spec.js @@ -135,11 +135,14 @@ describe('ProjectsTab.vue', () => { }) }) describe('empty content', () => { - it.each([STATE.NO_TOKEN, STATE.ERROR, STATE.OK])('shows the empty message when state is other than loading', async (state) => { - wrapper.setData({ state }) - await localVue.nextTick() - expect(wrapper.find(emptyContentSelector).exists()).toBeTruthy() - }) + it.each([STATE.NO_TOKEN, STATE.ERROR, STATE.OK])( + 'shows the empty message when state is other than loading', + async (state) => { + wrapper.setData({ state }) + await localVue.nextTick() + expect(wrapper.find(emptyContentSelector).exists()).toBeTruthy() + }, + ) it('should set projects as empty when the list of linked work packages are empty', () => { expect(wrapper.classes()).toContain('projects--empty') }) diff --git a/webpack.js b/webpack.js index 23dbcbb02..9d2e0c6a7 100644 --- a/webpack.js +++ b/webpack.js @@ -14,13 +14,22 @@ webpackConfig.stats = { const appId = 'integration_openproject' webpackConfig.entry = { - personalSettings: { import: path.join(__dirname, 'src', 'personalSettings.js'), filename: appId + '-personalSettings.js' }, + personalSettings: { + import: path.join(__dirname, 'src', 'personalSettings.js'), + filename: appId + '-personalSettings.js', + }, adminSettings: { import: path.join(__dirname, 'src', 'adminSettings.js'), filename: appId + '-adminSettings.js' }, dashboard: { import: path.join(__dirname, 'src', 'dashboard.js'), filename: appId + '-dashboard.js' }, 'openproject-tab': { import: path.join(__dirname, 'src', 'projectTab.js'), filename: appId + '-projectTab.js' }, fileActions: { import: path.join(__dirname, 'src', 'fileActions.js'), filename: appId + '-fileActions.js' }, - filesPlugin: { import: path.join(__dirname, 'src/filesPlugin', 'filesPlugin'), filename: appId + '-filesPlugin.js' }, - filesPluginLessThan28: { import: path.join(__dirname, 'src/filesPlugin', 'filesPluginLessThan28.js'), filename: appId + '-filesPluginLessThan28.js' }, + filesPlugin: { + import: path.join(__dirname, 'src/filesPlugin', 'filesPlugin'), + filename: appId + '-filesPlugin.js', + }, + filesPluginLessThan28: { + import: path.join(__dirname, 'src/filesPlugin', 'filesPluginLessThan28.js'), + filename: appId + '-filesPluginLessThan28.js', + }, reference: { import: path.join(__dirname, 'src', 'reference.js'), filename: appId + '-reference.js' }, } @@ -29,7 +38,7 @@ webpackConfig.plugins.push( extensions: ['js', 'vue'], files: 'src', failOnError: !isDev, - }) + }), ) webpackConfig.plugins.push( new StyleLintPlugin({