Compare commits

...
Author SHA1 Message Date
Shivam Mishra 0893ff3548 style: remove redundant space 2026-03-11 13:27:28 +05:30
Shivam Mishra 17a6fa6c1d feat: upgrade to eslint 10 2026-03-11 13:20:31 +05:30
30 changed files with 515 additions and 1757 deletions
-256
View File
@@ -1,256 +0,0 @@
module.exports = {
extends: [
'airbnb-base/legacy',
'prettier',
'plugin:vue/vue3-recommended',
'plugin:vitest-globals/recommended',
// use recommended-legacy when upgrading the plugin to v4
'plugin:@intlify/vue-i18n/recommended',
],
overrides: [
{
files: ['**/*.spec.{j,t}s?(x)'],
env: {
'vitest-globals/env': true,
},
},
{
files: ['**/*.story.vue'],
rules: {
'vue/no-undef-components': [
'error',
{
ignorePatterns: ['Variant', 'Story'],
},
],
// Story files can have static strings, it doesn't need to handle i18n always.
'vue/no-bare-strings-in-template': 'off',
'no-console': 'off',
},
},
],
plugins: ['html', 'prettier'],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {
'prettier/prettier': ['error'],
camelcase: 'off',
'no-param-reassign': 'off',
'import/no-extraneous-dependencies': 'off',
'import/prefer-default-export': 'off',
'import/no-named-as-default': 'off',
'jsx-a11y/no-static-element-interactions': 'off',
'jsx-a11y/click-events-have-key-events': 'off',
'jsx-a11y/label-has-associated-control': 'off',
'jsx-a11y/label-has-for': 'off',
'jsx-a11y/anchor-is-valid': 'off',
'import/no-unresolved': 'off',
'vue/html-indent': 'off',
'vue/multi-word-component-names': 'off',
'vue/next-tick-style': ['error', 'callback'],
'vue/block-order': [
'error',
{
order: ['script', 'template', 'style'],
},
],
'vue/component-name-in-template-casing': [
'error',
'PascalCase',
{
registeredComponentsOnly: true,
},
],
'vue/component-options-name-casing': ['error', 'PascalCase'],
'vue/custom-event-name-casing': ['error', 'camelCase'],
'vue/define-emits-declaration': ['error'],
'vue/define-macros-order': [
'error',
{
order: ['defineProps', 'defineEmits'],
defineExposeLast: false,
},
],
'vue/define-props-declaration': ['error', 'runtime'],
'vue/match-component-import-name': ['error'],
'vue/no-bare-strings-in-template': [
'error',
{
allowlist: [
'(',
')',
',',
'.',
'&',
'+',
'-',
'=',
'*',
'/',
'#',
'%',
'!',
'?',
':',
'[',
']',
'{',
'}',
'<',
'>',
'⌘',
'📄',
'🎉',
'🚀',
'💬',
'👥',
'📥',
'🔖',
'❌',
'✅',
'\u00b7',
'\u2022',
'\u2010',
'\u2013',
'\u2014',
'\u2212',
'|',
],
attributes: {
'/.+/': [
'title',
'aria-label',
'aria-placeholder',
'aria-roledescription',
'aria-valuetext',
],
input: ['placeholder'],
},
directives: ['v-text'],
},
],
'vue/no-empty-component-block': 'error',
'vue/no-multiple-objects-in-class': 'error',
'vue/no-root-v-if': 'warn',
'vue/no-static-inline-styles': [
'error',
{
allowBinding: false,
},
],
'vue/no-template-target-blank': [
'error',
{
allowReferrer: false,
enforceDynamicLinks: 'always',
},
],
'vue/no-required-prop-with-default': [
'error',
{
autofix: false,
},
],
'vue/no-this-in-before-route-enter': 'error',
'vue/no-undef-components': [
'error',
{
ignorePatterns: [
'^woot-',
'^fluent-',
'^multiselect',
'^router-link',
'^router-view',
'^ninja-keys',
'^FormulateForm',
'^FormulateInput',
'^highlightjs',
],
},
],
'vue/no-unused-emit-declarations': 'error',
'vue/no-unused-refs': 'error',
'vue/no-use-v-else-with-v-for': 'error',
'vue/prefer-true-attribute-shorthand': 'error',
'vue/no-useless-v-bind': [
'error',
{
ignoreIncludesComment: false,
ignoreStringEscape: false,
},
],
'vue/no-v-text': 'error',
'vue/padding-line-between-blocks': ['error', 'always'],
'vue/prefer-separate-static-class': 'error',
'vue/require-explicit-slots': 'error',
'vue/require-macro-variable-name': [
'error',
{
defineProps: 'props',
defineEmits: 'emit',
defineSlots: 'slots',
useSlots: 'slots',
useAttrs: 'attrs',
},
],
'vue/no-unused-properties': [
'error',
{
groups: ['props'],
deepData: false,
ignorePublicMembers: false,
unreferencedOptions: [],
},
],
'vue/max-attributes-per-line': [
'error',
{
singleline: {
max: 20,
},
multiline: {
max: 1,
},
},
],
'vue/html-self-closing': [
'error',
{
html: {
void: 'always',
normal: 'always',
component: 'always',
},
svg: 'always',
math: 'always',
},
],
'vue/no-v-html': 'off',
'vue/component-definition-name-casing': 'off',
'vue/singleline-html-element-content-newline': 'off',
'import/extensions': ['off'],
'no-console': 'error',
'@intlify/vue-i18n/no-dynamic-keys': 'warn',
'@intlify/vue-i18n/no-unused-keys': [
'warn',
{
extensions: ['.js', '.vue'],
},
],
},
settings: {
'vue-i18n': {
localeDir: './app/javascript/*/i18n/**.json',
},
},
env: {
browser: true,
node: true,
},
globals: {
bus: true,
vi: true,
},
};
@@ -13,7 +13,6 @@ class ApiClient {
return `${this.baseUrl()}/${this.resource}`;
}
// eslint-disable-next-line class-methods-use-this
get accountIdFromRoute() {
const isInsideAccountScopedURLs =
window.location.pathname.includes('/app/accounts');
@@ -8,7 +8,6 @@ class CacheEnabledApiClient extends ApiClient {
this.dataManager = new DataManager(this.accountIdFromRoute);
}
// eslint-disable-next-line class-methods-use-this
get cacheModelName() {
throw new Error('cacheModelName is not defined');
}
@@ -25,12 +24,10 @@ class CacheEnabledApiClient extends ApiClient {
return axios.get(this.url);
}
// eslint-disable-next-line class-methods-use-this
extractDataFromResponse(response) {
return response.data.payload;
}
// eslint-disable-next-line class-methods-use-this
marshallData(dataToParse) {
return { data: { payload: dataToParse } };
}
@@ -7,7 +7,6 @@ class ChangelogApi extends ApiClient {
super('changelog', { apiVersion: 'v1' });
}
// eslint-disable-next-line class-methods-use-this
fetchFromHub() {
return axios.get(CHANGELOG_API_URL);
}
@@ -7,7 +7,6 @@ class VoiceAPI extends ApiClient {
super('voice', { accountScoped: true });
}
// eslint-disable-next-line class-methods-use-this
initiateCall(contactId, inboxId) {
return ContactsAPI.initiateCall(contactId, inboxId).then(r => r.data);
}
-1
View File
@@ -72,7 +72,6 @@ class ContactAPI extends ApiClient {
return axios.get(requestURL);
}
// eslint-disable-next-line default-param-last
filter(page = 1, sortAttr = 'name', queryPayload) {
let requestURL = `${this.url}/filter?${buildContactParams(page, sortAttr)}`;
return axios.post(requestURL, queryPayload);
-1
View File
@@ -6,7 +6,6 @@ class Inboxes extends CacheEnabledApiClient {
super('inboxes', { accountScoped: true });
}
// eslint-disable-next-line class-methods-use-this
get cacheModelName() {
return 'inbox';
}
-1
View File
@@ -5,7 +5,6 @@ class LabelsAPI extends CacheEnabledApiClient {
super('labels', { accountScoped: true });
}
// eslint-disable-next-line class-methods-use-this
get cacheModelName() {
return 'label';
}
-1
View File
@@ -31,7 +31,6 @@ class ReportsAPI extends ApiClient {
});
}
// eslint-disable-next-line default-param-last
getSummary(since, until, type = 'account', id, groupBy, businessHours) {
return axios.get(`${this.url}/summary`, {
params: {
-3
View File
@@ -7,17 +7,14 @@ export class TeamsAPI extends CacheEnabledApiClient {
super('teams', { accountScoped: true });
}
// eslint-disable-next-line class-methods-use-this
get cacheModelName() {
return 'team';
}
// eslint-disable-next-line class-methods-use-this
extractDataFromResponse(response) {
return response.data;
}
// eslint-disable-next-line class-methods-use-this
marshallData(dataToParse) {
return { data: dataToParse };
}
@@ -56,7 +56,6 @@ const state = reactive({ ...initialState });
const urlValidators = {
shouldBeAValidURLPattern: value => {
try {
// eslint-disable-next-line
new URLPattern(value);
return true;
} catch {
@@ -99,7 +99,6 @@ import { useBranding } from 'shared/composables/useBranding';
* @property {number} inboxId - The ID of the inbox to which the message belongs
*/
// eslint-disable-next-line vue/define-macros-order
const props = defineProps({
id: { type: Number, required: true },
messageType: {
@@ -124,12 +123,12 @@ const props = defineProps({
createdAt: { type: Number, required: true }, // eslint-disable-line vue/no-unused-properties
currentUserId: { type: Number, required: true }, // eslint-disable-line vue/no-unused-properties
groupWithNext: { type: Boolean, default: false },
inboxId: { type: Number, default: null }, // eslint-disable-line vue/no-unused-properties
inboxId: { type: Number, default: null },
inboxSupportsReplyTo: { type: Object, default: () => ({}) },
inReplyTo: { type: Object, default: null }, // eslint-disable-line vue/no-unused-properties
isEmailInbox: { type: Boolean, default: false },
private: { type: Boolean, default: false },
additionalAttributes: { type: Object, default: () => ({}) }, // eslint-disable-line vue/no-unused-properties
additionalAttributes: { type: Object, default: () => ({}) },
sender: { type: Object, default: null },
senderId: { type: Number, default: null },
senderType: { type: String, default: null },
@@ -18,9 +18,7 @@ const MAXIMUM_FILE_UPLOAD_SIZE = 4; // in MB
const createState = (
content,
placeholder,
// eslint-disable-next-line default-param-last
plugins = [],
// eslint-disable-next-line default-param-last
methods = {},
enabledMenuOptions
) => {
@@ -35,8 +35,7 @@ export default {
default: '00:00',
},
// inbox prop is used in /mixins/inboxMixin,
// remove this props when refactoring to composable if not needed
// eslint-disable-next-line vue/no-unused-properties
// remove this props when refactoring to composable if not neededs
inbox: {
type: Object,
default: () => ({}),
@@ -1,7 +1,6 @@
import lamejs from '@breezystack/lamejs';
const writeString = (view, offset, string) => {
// eslint-disable-next-line no-plusplus
for (let i = 0; i < string.length; i++) {
view.setUint8(offset + i, string.charCodeAt(i));
}
@@ -29,9 +28,8 @@ const bufferToWav = async (buffer, numChannels, sampleRate) => {
// WAV Data
const offset = 44;
// eslint-disable-next-line no-plusplus
for (let i = 0; i < buffer.length; i++) {
// eslint-disable-next-line no-plusplus
for (let channel = 0; channel < numChannels; channel++) {
const sample = Math.max(
-1,
@@ -37,12 +37,10 @@ class ActionCableConnector extends BaseActionCableConnector {
};
}
// eslint-disable-next-line class-methods-use-this
onReconnect = () => {
emitter.emit(BUS_EVENTS.WEBSOCKET_RECONNECT);
};
// eslint-disable-next-line class-methods-use-this
onDisconnected = () => {
emitter.emit(BUS_EVENTS.WEBSOCKET_DISCONNECT);
};
@@ -90,7 +88,6 @@ class ActionCableConnector extends BaseActionCableConnector {
this.app.$store.dispatch('updateConversation', data);
};
// eslint-disable-next-line class-methods-use-this
onLogout = () => AuthAPI.logout();
onMessageCreated = data => {
@@ -106,7 +103,6 @@ class ActionCableConnector extends BaseActionCableConnector {
});
};
// eslint-disable-next-line class-methods-use-this
onReload = () => window.location.reload();
onStatusChange = data => {
@@ -161,7 +157,6 @@ class ActionCableConnector extends BaseActionCableConnector {
}, 30000);
};
// eslint-disable-next-line class-methods-use-this
fetchConversationStats = () => {
emitter.emit('fetch_conversation_stats');
};
@@ -212,9 +212,8 @@ export const isCustomAttribute = (attrs, key) => {
};
export const generateCustomAttributes = (
// eslint-disable-next-line default-param-last
conversationAttributes = [],
// eslint-disable-next-line default-param-last
contactAttributes = [],
conversationlabel,
contactlabel
@@ -61,7 +61,6 @@ export class EmailQuoteExtractor {
tempDiv.innerHTML = DOMPurify.sanitize(htmlContent);
// Check for class-based quotes
// eslint-disable-next-line no-restricted-syntax
for (const selector of QUOTE_INDICATORS) {
if (tempDiv.querySelector(selector)) {
return true;
@@ -18,7 +18,6 @@ export const verifyServiceWorkerExistence = (callback = () => {}) => {
.register('/sw.js')
.then(registration => callback(registration))
.catch(registrationError => {
// eslint-disable-next-line
console.log('SW registration failed: ', registrationError);
});
};
@@ -69,7 +68,6 @@ export const registerSubscription = (onSuccess = () => {}) => {
onSuccess();
})
.catch(error => {
// eslint-disable-next-line no-console
console.error('Push subscription registration failed:', error);
useAlert('This browser does not support desktop notification');
});
@@ -77,7 +75,6 @@ export const registerSubscription = (onSuccess = () => {}) => {
export const requestPushPermissions = ({ onSuccess }) => {
if (!('Notification' in window)) {
// eslint-disable-next-line no-console
console.warn('Notification is not supported');
useAlert('This browser does not support desktop notification');
} else if (Notification.permission === 'granted') {
@@ -288,10 +288,9 @@ describe('templateHelper', () => {
});
it('should handle special characters in template variables', () => {
/* eslint-disable no-template-curly-in-string */
const templateText =
'Welcome {{user_name}}, your order #{{order_id}} costs ${{amount}}';
/* eslint-enable no-template-curly-in-string */
const processedParams = {
body: {
user_name: 'John & Jane',
@@ -1,5 +1,4 @@
<script>
/* eslint-env browser */
/* global FB */
import { useVuelidate } from '@vuelidate/core';
import { useAlert } from 'dashboard/composables';
@@ -10,7 +10,6 @@ export const getAudioContext = () => {
return audioCtx;
};
// eslint-disable-next-line default-param-last
export const getAlertAudio = async (baseUrl = '', requestContext) => {
const audioCtx = getAudioContext();
const playSound = audioBuffer => {
@@ -34,7 +33,6 @@ export const getAlertAudio = async (baseUrl = '', requestContext) => {
.then(response => response.arrayBuffer())
.then(buffer => {
audioCtx.decodeAudioData(buffer).then(playSound);
// eslint-disable-next-line no-promise-executor-return
return new Promise(res => res());
})
.catch(() => {
@@ -74,10 +74,8 @@ class BaseActionCableConnector {
}, RECONNECT_INTERVAL);
};
// eslint-disable-next-line class-methods-use-this
onReconnect = () => {};
// eslint-disable-next-line class-methods-use-this
onDisconnected = () => {};
disconnect() {
@@ -1,4 +1,3 @@
/* eslint-disable max-classes-per-file */
export class DuplicateContactException extends Error {
constructor(data) {
super('DUPLICATE_CONTACT');
@@ -48,7 +48,6 @@ export default {
}`;
},
avatarUrl() {
// eslint-disable-next-line
const displayImage = this.useInboxAvatarForBot
? this.inboxAvatarUrl
: '/assets/images/chatwoot_bot.png';
@@ -96,7 +96,6 @@ class ActionCableConnector extends BaseActionCableConnector {
this.app.$store.dispatch('agent/updatePresence', data.users);
};
// eslint-disable-next-line class-methods-use-this
onContactMerge = data => {
const { pubsub_token: pubsubToken } = data;
ActionCableConnector.refreshConnector(pubsubToken);
-2
View File
@@ -1,8 +1,6 @@
const getUuid = () =>
'xxxxxxxx4xxx'.replace(/[xy]/g, c => {
// eslint-disable-next-line
const r = (Math.random() * 16) | 0;
// eslint-disable-next-line
const v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
+246
View File
@@ -0,0 +1,246 @@
const js = require('@eslint/js');
const pluginVue = require('eslint-plugin-vue');
const pluginVueI18n = require('@intlify/eslint-plugin-vue-i18n');
const prettierRecommended = require('eslint-plugin-prettier/recommended');
const globals = require('globals');
const vitestGlobals = {
describe: 'readonly',
it: 'readonly',
test: 'readonly',
expect: 'readonly',
beforeEach: 'readonly',
afterEach: 'readonly',
beforeAll: 'readonly',
afterAll: 'readonly',
vi: 'readonly',
vitest: 'readonly',
suite: 'readonly',
};
module.exports = [
{ ignores: ['node_modules/**', 'public/**', 'vendor/**'] },
js.configs.recommended,
...pluginVue.configs['flat/recommended'],
...pluginVueI18n.configs['flat/recommended'],
prettierRecommended,
{
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.browser,
...globals.node,
bus: 'writable',
vi: 'readonly',
},
},
settings: {
'vue-i18n': {
localeDir: './app/javascript/*/i18n/**.json',
},
},
rules: {
// Carried from airbnb-base/legacy
eqeqeq: ['error', 'always', { null: 'ignore' }],
'no-alert': 'error',
'no-eval': 'error',
'no-implied-eval': 'error',
'no-new-func': 'error',
'no-proto': 'error',
'no-return-assign': 'error',
'no-script-url': 'error',
'no-sequences': 'error',
'no-shadow': 'error',
'no-throw-literal': 'error',
'no-unused-expressions': 'error',
'no-useless-call': 'error',
'prefer-promise-reject-errors': 'error',
camelcase: 'off',
'no-console': 'error',
'no-param-reassign': 'off',
'no-unused-vars': ['error', { caughtErrors: 'none', ignoreRestSiblings: true }],
'no-useless-assignment': 'warn',
'preserve-caught-error': 'off',
// Vue
'vue/block-order': ['error', { order: ['script', 'template', 'style'] }],
'vue/component-definition-name-casing': 'off',
'vue/component-name-in-template-casing': [
'error',
'PascalCase',
{ registeredComponentsOnly: true },
],
'vue/component-options-name-casing': ['error', 'PascalCase'],
'vue/custom-event-name-casing': ['error', 'camelCase'],
'vue/define-emits-declaration': ['error'],
'vue/define-macros-order': [
'error',
{ order: ['defineProps', 'defineEmits'], defineExposeLast: false },
],
'vue/define-props-declaration': ['error', 'runtime'],
'vue/html-indent': 'off',
'vue/html-self-closing': [
'error',
{
html: { void: 'always', normal: 'always', component: 'always' },
svg: 'always',
math: 'always',
},
],
'vue/match-component-import-name': ['error'],
'vue/max-attributes-per-line': [
'error',
{ singleline: { max: 20 }, multiline: { max: 1 } },
],
'vue/multi-word-component-names': 'off',
'vue/next-tick-style': ['error', 'callback'],
'vue/no-bare-strings-in-template': [
'error',
{
allowlist: [
'(',
')',
',',
'.',
'&',
'+',
'-',
'=',
'*',
'/',
'#',
'%',
'!',
'?',
':',
'[',
']',
'{',
'}',
'<',
'>',
'⌘',
'📄',
'🎉',
'🚀',
'💬',
'👥',
'📥',
'🔖',
'❌',
'✅',
'\u00b7',
'\u2022',
'\u2010',
'\u2013',
'\u2014',
'\u2212',
'|',
],
attributes: {
'/.+/': [
'title',
'aria-label',
'aria-placeholder',
'aria-roledescription',
'aria-valuetext',
],
input: ['placeholder'],
},
directives: ['v-text'],
},
],
'vue/no-empty-component-block': 'error',
'vue/no-multiple-objects-in-class': 'error',
'vue/no-required-prop-with-default': ['error', { autofix: false }],
'vue/no-root-v-if': 'warn',
'vue/no-static-inline-styles': ['error', { allowBinding: false }],
'vue/no-template-target-blank': [
'error',
{ allowReferrer: false, enforceDynamicLinks: 'always' },
],
'vue/no-this-in-before-route-enter': 'error',
'vue/no-undef-components': [
'error',
{
ignorePatterns: [
'^woot-',
'^fluent-',
'^multiselect',
'^router-link',
'^router-view',
'^ninja-keys',
'^FormulateForm',
'^FormulateInput',
'^highlightjs',
],
},
],
'vue/no-unused-emit-declarations': 'error',
'vue/no-unused-properties': [
'error',
{
groups: ['props'],
deepData: false,
ignorePublicMembers: false,
unreferencedOptions: [],
},
],
'vue/no-unused-refs': 'error',
'vue/no-use-v-else-with-v-for': 'error',
'vue/no-useless-v-bind': [
'error',
{ ignoreIncludesComment: false, ignoreStringEscape: false },
],
'vue/no-v-html': 'off',
'vue/no-v-text': 'error',
'vue/padding-line-between-blocks': ['error', 'always'],
'vue/prefer-separate-static-class': 'error',
'vue/prefer-true-attribute-shorthand': 'error',
'vue/require-explicit-slots': 'error',
'vue/require-macro-variable-name': [
'error',
{
defineProps: 'props',
defineEmits: 'emit',
defineSlots: 'slots',
useSlots: 'slots',
useAttrs: 'attrs',
},
],
'vue/singleline-html-element-content-newline': 'off',
// Vue i18n
'@intlify/vue-i18n/no-dynamic-keys': 'warn',
'@intlify/vue-i18n/no-unused-keys': [
'warn',
{ extensions: ['.js', '.vue'] },
],
},
},
// Spec files
{
files: ['**/*.spec.{j,t}s?(x)'],
languageOptions: {
globals: vitestGlobals,
},
},
// Story files
{
files: ['**/*.story.vue'],
rules: {
'vue/no-undef-components': [
'error',
{ ignorePatterns: ['Variant', 'Story'] },
],
'vue/no-bare-strings-in-template': 'off',
'no-console': 'off',
},
},
];
+8 -9
View File
@@ -122,16 +122,14 @@
"@size-limit/file": "^8.2.4",
"@vitest/coverage-v8": "3.0.5",
"@vue/test-utils": "^2.4.6",
"@eslint/js": "^10.0.0",
"autoprefixer": "^10.4.20",
"eslint": "^8.57.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint": "^10.0.0",
"eslint-config-prettier": "^10.0.0",
"eslint-interactive": "^11.1.0",
"eslint-plugin-html": "7.1.0",
"eslint-plugin-import": "2.30.0",
"eslint-plugin-prettier": "5.2.1",
"eslint-plugin-vitest-globals": "^1.5.0",
"eslint-plugin-vue": "^9.28.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-vue": "^10.8.0",
"globals": "^16.0.0",
"fake-indexeddb": "^6.0.0",
"histoire": "0.17.15",
"husky": "^7.0.0",
@@ -160,7 +158,8 @@
"overrides": {
"vite-node": "2.0.1",
"vite": "5.4.21",
"vitest": "3.0.5"
"vitest": "3.0.5",
"vue-eslint-parser": "^10.0.0"
}
},
"lint-staged": {
+255 -1445
View File
File diff suppressed because it is too large Load Diff