chore: upgrade to eslint 9 (#2348)

* root + server

* frontend

* frontend-2

* dui3

* dui3

* tailwind theme

* ui-components

* preview service

* viewer

* viewer-sandbox

* fileimport-service

* webhook service

* objectloader

* shared

* ui-components-nuxt

* WIP full config

* WIP full linter

* eslint projectwide util

* minor fix

* removing redundant ci

* clean up test errors

* fixed prettier formatting

* CI improvements

* TSC lint fix

* 'buildBatch' needs to be async since some batch types (like Text) require it. Removed a disabled liniting rule from ObjLoader

* removed unnecessary void

---------

Co-authored-by: AlexandruPopovici <alexandrupopoviciioan@gmail.com>
This commit is contained in:
Kristaps Fabians Geikins
2024-06-12 14:38:02 +03:00
committed by GitHub
parent b6fbb411a3
commit 83d8035dc2
299 changed files with 4353 additions and 1905 deletions
+8 -8
View File
@@ -452,8 +452,8 @@ jobs:
working_directory: 'packages/server' working_directory: 'packages/server'
- run: - run:
name: 'Lint with TypeScript Compiler' name: 'Lint'
command: yarn lint:tsc command: yarn lint:ci
working_directory: 'packages/server' working_directory: 'packages/server'
- run: - run:
@@ -516,7 +516,7 @@ jobs:
- run: - run:
name: Lint everything name: Lint everything
command: yarn lint command: yarn lint:ci
working_directory: 'packages/frontend-2' working_directory: 'packages/frontend-2'
test-viewer: test-viewer:
@@ -550,7 +550,7 @@ jobs:
- run: - run:
name: Lint everything name: Lint everything
command: yarn lint command: yarn lint:ci
working_directory: 'packages/viewer' working_directory: 'packages/viewer'
- run: - run:
@@ -588,17 +588,17 @@ jobs:
- run: - run:
name: Lint tailwind theme name: Lint tailwind theme
command: yarn lint command: yarn lint:ci
working_directory: 'packages/tailwind-theme' working_directory: 'packages/tailwind-theme'
- run: - run:
name: Lint ui components name: Lint ui components
command: yarn lint command: yarn lint:ci
working_directory: 'packages/ui-components' working_directory: 'packages/ui-components'
- run: - run:
name: Lint component nuxt package name: Lint component nuxt package
command: yarn lint command: yarn lint:ci
working_directory: 'packages/ui-components-nuxt' working_directory: 'packages/ui-components-nuxt'
- run: - run:
@@ -1018,7 +1018,7 @@ jobs:
command: yarn build:public command: yarn build:public
- run: - run:
name: Lint viewer-sandbox name: Lint viewer-sandbox
command: yarn lint command: yarn lint:ci
working_directory: 'packages/viewer-sandbox' working_directory: 'packages/viewer-sandbox'
- run: - run:
name: Build viewer-sandbox name: Build viewer-sandbox
-47
View File
@@ -1,47 +0,0 @@
/** @type {import("eslint").Linter.Config} */
const config = {
root: true,
parserOptions: {
ecmaVersion: 2022
},
env: {
es2022: true,
node: true,
commonjs: true
},
extends: ['eslint:recommended', 'prettier'],
rules: {
camelcase: [
1,
{
properties: 'always'
}
],
'no-var': 'error',
'no-alert': 'error',
eqeqeq: 'error',
'prefer-const': 'warn',
'object-shorthand': 'warn'
},
overrides: [
{
files: '*.mjs',
parserOptions: {
sourceType: 'module'
}
}
],
ignorePatterns: [
'node_modules',
'dist',
'dist-*',
'public',
'events.json',
'.*.{ts,js,vue,tsx,jsx}',
'generated/**/*',
'.nuxt',
'.output'
]
}
module.exports = config
+1 -1
View File
@@ -5,7 +5,7 @@ set -e
if [ -n "$CI" ] if [ -n "$CI" ]
then then
echo "running eslint" echo "running eslint"
yarn lint yarn eslint:projectwide
echo "...eslint done" echo "...eslint done"
echo "running prettier" echo "running prettier"
yarn prettier:check yarn prettier:check
+1
View File
@@ -15,6 +15,7 @@ packages/viewer/example/speckleviewer.web.js
**/nuxt-modules/**/templates/*.js **/nuxt-modules/**/templates/*.js
packages/frontend-2/lib/common/generated/**/* packages/frontend-2/lib/common/generated/**/*
packages/dui3/lib/common/generated/**/* packages/dui3/lib/common/generated/**/*
packages/server/introspected-schema.graphql
package-lock.json package-lock.json
yarn.lock yarn.lock
+112
View File
@@ -0,0 +1,112 @@
import globals from 'globals'
import js from '@eslint/js'
import prettierConfig from 'eslint-config-prettier'
import { fileURLToPath } from 'url'
import { dirname } from 'path'
/**
* TODO:
* - Check speed (inspect ignored files, that we're not processing junk)
* - Fix lint-staged
*/
/**
* Feed in import.meta.url in your .mjs module to get the equivalent of __dirname
* @param {string} importMetaUrl
*/
export const getESMDirname = (importMetaUrl) => {
return dirname(fileURLToPath(importMetaUrl))
}
/**
* Configs that should only apply to repo root (shouldn't be inherited in subdirectories)
* @type {Array<import('eslint').Linter.FlatConfig>}
*/
const rootConfigs = [
{
ignores: [
'packages/**/*',
'.circleci',
'.devcontainer',
'.github',
'.husky',
'.vscode',
'.yarn',
'docker',
'node_modules',
'test-queries',
'setup'
]
},
{
files: ['*.{js,mjs,cjs}', '.*.{js,mjs,cjs}', 'utils/*.{js,mjs,cjs}'],
languageOptions: {
sourceType: 'commonjs',
globals: {
...globals.node
}
}
},
{
files: ['*.mjs', '.*.mjs', 'utils/*.mjs'],
languageOptions: {
sourceType: 'module'
}
}
]
/**
* Base configs that should be inherited in all packages as well
* @type {Array<import('eslint').Linter.FlatConfig>}
*/
export const baseConfigs = [
{
ignores: [
'**/node_modules/**',
'**/dist/**',
'**/dist-*/**',
'**/public/**',
'**/events.json',
'**/generated/**/*',
'**/.nuxt/**',
'**/.output/**'
]
},
{
files: ['**/*.mjs'],
languageOptions: {
sourceType: 'module'
}
},
{
files: ['**/*.cjs'],
languageOptions: {
sourceType: 'commonjs'
}
},
{
files: ['**/*.{js,mjs,cjs}', '**/.*.{js,mjs,cjs}'],
...js.configs.recommended
},
prettierConfig,
{
rules: {
camelcase: [
1,
{
properties: 'always'
}
],
'no-var': 'error',
'no-alert': 'error',
eqeqeq: 'error',
'prefer-const': 'warn',
'object-shorthand': 'warn'
}
}
]
const configs = [...baseConfigs, ...rootConfigs]
export { globals, prettierConfig }
export default configs
+1 -19
View File
@@ -1,22 +1,4 @@
const micromatch = require('micromatch')
const extList = ['ts', 'js', 'vue', 'tsx', 'jsx', 'json'].join(',')
module.exports = { module.exports = {
'*.{js,ts,vue}': (files) => { '*.{js,ts,vue,cjs,mjs,cts,mts}': 'yarn eslint:projectwide',
const finalFiles = micromatch.not(files, [
// Filter out files that start with a period, since they're ignored by default
`**/.*.{${extList}}`,
// Filter out generated folder files
`**/generated/**/*`,
// Filter out types in object loader
'**/packages/objectloader/types/**/*',
// Filter out nuxt plugin templates
'**/templates/plugin.js',
// ui-components ignore
'**/packages/ui-components/utils/tailwind-configure.d.ts'
])
return 'eslint --cache --max-warnings=0 ' + finalFiles.join(' ')
},
'*.**': 'prettier --check --ignore-unknown' '*.**': 'prettier --check --ignore-unknown'
} }
+18 -10
View File
@@ -13,7 +13,6 @@
"build:public": "yarn workspaces foreach -ptv --no-private run build", "build:public": "yarn workspaces foreach -ptv --no-private run build",
"build:tailwind-deps": "yarn workspaces foreach -iv -j unlimited --include '{@speckle/shared,@speckle/tailwind-theme,@speckle/ui-components}' run build", "build:tailwind-deps": "yarn workspaces foreach -iv -j unlimited --include '{@speckle/shared,@speckle/tailwind-theme,@speckle/ui-components}' run build",
"ensure:tailwind-deps": "node ./utils/ensure-tailwind-deps.mjs", "ensure:tailwind-deps": "node ./utils/ensure-tailwind-deps.mjs",
"lint": "node --max-old-space-size=4096 ./node_modules/eslint/bin/eslint.js . --ext .js,.ts,.vue --max-warnings=0",
"helm:readme:generate": "./utils/helm/update-schema-json.sh", "helm:readme:generate": "./utils/helm/update-schema-json.sh",
"prettier:check": "prettier --check .", "prettier:check": "prettier --check .",
"prettier:fix": "prettier --write .", "prettier:fix": "prettier --write .",
@@ -37,38 +36,47 @@
"dev:shared": "yarn workspace @speckle/shared dev", "dev:shared": "yarn workspace @speckle/shared dev",
"prepare": "husky install", "prepare": "husky install",
"postinstall": "husky install", "postinstall": "husky install",
"cm": "cz" "cm": "cz",
"eslint:inspect": "eslint-config-inspector",
"eslint:projectwide": "node ./utils/eslint-projectwide.mjs"
}, },
"devDependencies": { "devDependencies": {
"@eslint/config-inspector": "^0.4.10",
"@eslint/js": "^9.4.0",
"@rollup/plugin-typescript": "^11.1.0", "@rollup/plugin-typescript": "^11.1.0",
"@swc/core": "^1.2.222", "@swc/core": "^1.2.222",
"@types/eslint": "^8.4.1", "@types/eslint": "^8.56.10",
"@types/eslint__js": "^8.42.3",
"@types/lockfile": "^1.0.2", "@types/lockfile": "^1.0.2",
"commitizen": "^4.2.5", "commitizen": "^4.2.5",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"cz-conventional-changelog": "^3.3.0", "cz-conventional-changelog": "^3.3.0",
"eslint": "^8.11.0", "eslint": "^9.4.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^9.1.0",
"eslint-flat-config-utils": "^0.2.5",
"globals": "^15.4.0",
"husky": "^7.0.4", "husky": "^7.0.4",
"lint-staged": "^12.3.7", "lint-staged": "^12.3.7",
"lockfile": "^1.0.4", "lockfile": "^1.0.4",
"pino-pretty": "^9.1.1", "pino-pretty": "^9.1.1",
"prettier": "^2.5.1", "prettier": "^2.5.1",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"tsconfig-paths": "^4.0.0" "tsconfig-paths": "^4.0.0",
"zx": "^8.1.2"
}, },
"resolutions": { "resolutions": {
"@babel/traverse": ">=7.23.2", "@babel/traverse": ">=7.23.2",
"@microsoft/api-extractor/semver": "^7.5.4", "@microsoft/api-extractor/semver": "^7.5.4",
"@rushstack/node-core-library/semver": "^7.5.4", "@rushstack/node-core-library/semver": "^7.5.4",
"@typescript-eslint/eslint-plugin": "^6.4.1", "@typescript-eslint/eslint-plugin": "^7.12.0",
"@typescript-eslint/parser": "^6.4.1", "@typescript-eslint/parser": "^7.12.0",
"typescript-eslint": "^7.12.0",
"@types/react": "file:./packages/frontend-2/type-augmentations/stubs/types__react", "@types/react": "file:./packages/frontend-2/type-augmentations/stubs/types__react",
"axios": ">=1.6.0", "axios": ">=1.6.0",
"core-js": "3.22.4", "core-js": "3.22.4",
"core-js-compat/semver": "^7.5.4", "core-js-compat/semver": "^7.5.4",
"eslint": "^8.11.0", "eslint": "^9.4.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^9.1.0",
"express": ">=4.19.2", "express": ">=4.19.2",
"fast-xml-parser": ">=4.2.5", "fast-xml-parser": ">=4.2.5",
"graphql": "^15.3.0", "graphql": "^15.3.0",
-119
View File
@@ -1,119 +0,0 @@
const mainExtends = [
'plugin:nuxt/recommended',
'plugin:vue/vue3-recommended',
'prettier'
]
/** @type {import('eslint').Linter.Config} */
const config = {
env: {
node: true
},
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
parser: '@typescript-eslint/parser',
tsconfigRootDir: __dirname,
project: ['./tsconfig.eslint.json'],
extraFileExtensions: ['.vue']
},
extends: [...mainExtends],
plugins: ['@typescript-eslint'],
ignorePatterns: [
'**/templates/*',
'coverage',
'lib/common/generated/**/*',
'storybook-static',
'!.storybook',
'.nuxt',
'.output'
],
rules: {
camelcase: [
'error',
{
properties: 'always',
allow: ['^[\\w]+_[\\w]+Fragment$']
}
],
'no-alert': 'error',
eqeqeq: ['error', 'always', { null: 'always' }],
'no-console': 'off',
'no-var': 'error'
},
overrides: [
{
files: '*.test.{ts,js}',
env: {
jest: true
}
},
{
files: './{components|pages|store|lib}/*.{js,ts,vue}',
env: {
node: false,
browser: true
}
},
{
files: '*.{ts,tsx,vue}',
extends: ['plugin:@typescript-eslint/recommended', ...mainExtends],
rules: {
'@typescript-eslint/no-explicit-any': ['error'],
'@typescript-eslint/no-unsafe-argument': ['error'],
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
'@typescript-eslint/no-for-in-array': ['error'],
'@typescript-eslint/restrict-template-expressions': ['error'],
'@typescript-eslint/restrict-plus-operands': ['error'],
'@typescript-eslint/await-thenable': ['warn'],
'@typescript-eslint/ban-types': ['warn'],
'require-await': 'off',
'@typescript-eslint/require-await': 'error',
'no-undef': 'off'
}
},
{
files: '*.vue',
plugins: ['vuejs-accessibility'],
extends: [
'plugin:@typescript-eslint/recommended',
...mainExtends,
'plugin:vuejs-accessibility/recommended'
],
rules: {
'vue/component-tags-order': [
'error',
{ order: ['docs', 'template', 'script', 'style'] }
],
'vue/require-default-prop': 'off',
'vue/multi-word-component-names': 'off',
'vue/component-name-in-template-casing': [
'error',
'PascalCase',
{ registeredComponentsOnly: false }
],
'vuejs-accessibility/label-has-for': [
'error',
{
required: {
some: ['nesting', 'id']
}
}
]
}
},
{
files: '*.d.ts',
rules: {
'no-var': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/ban-types': 'off'
}
}
]
}
module.exports = config
@@ -26,7 +26,7 @@
</button> </button>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { DUIAccount } from 'lib/accounts/composables/setup' import type { DUIAccount } from 'lib/accounts/composables/setup'
import { ArrowTopRightOnSquareIcon } from '@heroicons/vue/20/solid' import { ArrowTopRightOnSquareIcon } from '@heroicons/vue/20/solid'
const props = defineProps<{ const props = defineProps<{
+1 -1
View File
@@ -83,7 +83,7 @@ import { XMarkIcon } from '@heroicons/vue/20/solid'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue' import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue'
import { useAccountStore } from '~/store/accounts' import { useAccountStore } from '~/store/accounts'
import { DUIAccount } from '~/lib/accounts/composables/setup' import type { DUIAccount } from '~/lib/accounts/composables/setup'
import { useDocumentInfoStore } from '~/store/uiConfig' import { useDocumentInfoStore } from '~/store/uiConfig'
const accountStore = useAccountStore() const accountStore = useAccountStore()
+125
View File
@@ -0,0 +1,125 @@
import { omit } from 'lodash-es'
import { baseConfigs, globals, getESMDirname } from '../../eslint.config.mjs'
import withNuxt from './.nuxt/eslint.config.mjs'
import pluginVueA11y from 'eslint-plugin-vuejs-accessibility'
const configs = await withNuxt([
{
rules: {
camelcase: [
'error',
{
properties: 'always',
allow: ['^[\\w]+_[\\w]+Fragment$']
}
],
'no-alert': 'error',
eqeqeq: ['error', 'always', { null: 'always' }],
'no-console': 'off',
'no-var': 'error'
}
},
{
files: ['**/*.{ts,vue,tsx,mts,cts}'],
languageOptions: {
parserOptions: {
project: ['./tsconfig.eslint.json'],
extraFileExtensions: ['.vue'],
tsconfigRootDir: getESMDirname(import.meta.url)
}
}
},
{
files: ['**/*.test.{ts,js}'],
languageOptions: {
globals: {
...globals.jest
}
}
},
{
files: ['./{components|pages|store|lib}/*.{js,ts,vue}'],
languageOptions: {
globals: {
...globals.browser
}
}
},
{
files: ['**/*.{ts,tsx,vue}'],
rules: {
'@typescript-eslint/no-explicit-any': ['error'],
'@typescript-eslint/no-unsafe-argument': ['error'],
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
'@typescript-eslint/no-for-in-array': ['error'],
'@typescript-eslint/restrict-plus-operands': ['error'],
'@typescript-eslint/await-thenable': ['warn'],
'@typescript-eslint/ban-types': ['warn'],
'require-await': 'off',
'@typescript-eslint/require-await': 'error',
'no-undef': 'off',
'@typescript-eslint/unified-signatures': 'off', // DX sucks in vue event definitions
'@typescript-eslint/no-dynamic-delete': 'off', // too restrictive
'@typescript-eslint/restrict-template-expressions': 'off', // too restrictive
'@typescript-eslint/no-invalid-void-type': 'off' // too restrictive
}
},
...pluginVueA11y.configs['flat/recommended'].map((c) => ({
...c,
files: [...(c.files || []), '**/*.vue'],
languageOptions: c.languageOptions
? omit(c.languageOptions, ['parserOptions', 'parser']) // Prevent overriding parser
: undefined
})),
{
files: ['**/*.vue'],
rules: {
'vue/component-tags-order': [
'error',
{ order: ['docs', 'template', 'script', 'style'] }
],
'vue/require-default-prop': 'off',
'vue/multi-word-component-names': 'off',
'vue/component-name-in-template-casing': [
'error',
'PascalCase',
{ registeredComponentsOnly: false }
],
'vuejs-accessibility/label-has-for': [
'error',
{
required: {
some: ['nesting', 'id']
}
}
],
'vue/html-self-closing': 'off' // messes with prettier
}
},
{
files: ['**/*.d.ts'],
rules: {
'no-var': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/ban-types': 'off'
}
}
]).prepend([
{
ignores: [
'**/node_modules/**',
'**/templates/*',
'./lib/common/generated/**/*',
'storybook-static',
'.nuxt/**',
'.output/**'
]
},
...baseConfigs
])
export default configs
@@ -1,7 +1,7 @@
import { ApolloClient, gql } from '@apollo/client/core' import { ApolloClient, gql } from '@apollo/client/core'
import { ApolloClients } from '@vue/apollo-composable' import { ApolloClients } from '@vue/apollo-composable'
import { ComputedRef, Ref } from 'vue' import type { ComputedRef, Ref } from 'vue'
import { Account } from '~/lib/bindings/definitions/IBasicConnectorBinding' import type { Account } from '~/lib/bindings/definitions/IBasicConnectorBinding'
import { resolveClientConfig } from '~/lib/core/configs/apollo' import { resolveClientConfig } from '~/lib/core/configs/apollo'
export type DUIAccount = { export type DUIAccount = {
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/require-await */
import { BaseBridge } from '~~/lib/bridge/base' import { BaseBridge } from '~~/lib/bridge/base'
import { IBinding } from '~~/lib/bindings/definitions/IBinding' import type { IBinding } from '~~/lib/bindings/definitions/IBinding'
export const IBasicConnectorBindingKey = 'baseBinding' export const IBasicConnectorBindingKey = 'baseBinding'
@@ -52,10 +52,6 @@ export type ToastInfo = {
} }
export class MockedBaseBinding extends BaseBridge { export class MockedBaseBinding extends BaseBridge {
constructor() {
super()
}
public async getAccounts() { public async getAccounts() {
return [] return []
} }
@@ -1,7 +1,5 @@
/* eslint-disable @typescript-eslint/require-await */
import { BaseBridge } from '~~/lib/bridge/base' import { BaseBridge } from '~~/lib/bridge/base'
import { IBinding } from '~~/lib/bindings/definitions/IBinding' import type { IBinding } from '~~/lib/bindings/definitions/IBinding'
/** /**
* The name under which this binding will be registered. * The name under which this binding will be registered.
@@ -25,10 +23,6 @@ export type Config = {
} }
export class MockedConfigBinding extends BaseBridge { export class MockedConfigBinding extends BaseBridge {
constructor() {
super()
}
getConfig() { getConfig() {
return { return {
darkTheme: false darkTheme: false
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/require-await */
import { BaseBridge } from '~~/lib/bridge/base' import { BaseBridge } from '~~/lib/bridge/base'
import { IBinding } from '~~/lib/bindings/definitions/IBinding' import type { IBinding } from '~~/lib/bindings/definitions/IBinding'
/** /**
* The name under which this binding will be registered. * The name under which this binding will be registered.
@@ -36,9 +36,6 @@ export type ComplexType = {
} }
export class MockedTestBinding extends BaseBridge { export class MockedTestBinding extends BaseBridge {
constructor() {
super()
}
public async sayHi(name: string, count: number, sayHelloNotHi: boolean) { public async sayHi(name: string, count: number, sayHelloNotHi: boolean) {
return `Hello from mocked bindings. Args: name = ${name}, count = ${count}, sayHelloNotHi = ${sayHelloNotHi.toString()}.` return `Hello from mocked bindings. Args: name = ${name}, count = ${count}, sayHelloNotHi = ${sayHelloNotHi.toString()}.`
} }
+2 -1
View File
@@ -1,4 +1,5 @@
import { createNanoEvents, Emitter } from 'nanoevents' import type { Emitter } from 'nanoevents'
import { createNanoEvents } from 'nanoevents'
/** /**
* A simple (typed) event emitter base class that host applications can use to send messages (and data) to the web ui, * A simple (typed) event emitter base class that host applications can use to send messages (and data) to the web ui,
+1 -1
View File
@@ -1,5 +1,5 @@
import { BaseBridge } from '~/lib/bridge/base' import { BaseBridge } from '~/lib/bridge/base'
import { IRawBridge } from '~/lib/bridge/definitions' import type { IRawBridge } from '~/lib/bridge/definitions'
/** /**
* A generic bridge class for Webivew2 or CefSharp. * A generic bridge class for Webivew2 or CefSharp.
*/ */
+7 -11
View File
@@ -1,19 +1,15 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { import type { ApolloLink, ApolloClientOptions } from '@apollo/client/core'
ApolloLink, import { InMemoryCache, split, from } from '@apollo/client/core'
InMemoryCache,
split,
ApolloClientOptions,
from
} from '@apollo/client/core'
import { setContext } from '@apollo/client/link/context' import { setContext } from '@apollo/client/link/context'
import { SubscriptionClient } from 'subscriptions-transport-ws' import { SubscriptionClient } from 'subscriptions-transport-ws'
import { createUploadLink } from 'apollo-upload-client' import { createUploadLink } from 'apollo-upload-client'
import { WebSocketLink } from '@apollo/client/link/ws' import { WebSocketLink } from '@apollo/client/link/ws'
import { getMainDefinition } from '@apollo/client/utilities' import { getMainDefinition } from '@apollo/client/utilities'
import { OperationDefinitionNode, Kind } from 'graphql' import type { OperationDefinitionNode } from 'graphql'
import { Nullable } from '@speckle/shared' import { Kind } from 'graphql'
import type { Nullable } from '@speckle/shared'
import { import {
buildAbstractCollectionMergeFunction, buildAbstractCollectionMergeFunction,
buildArrayMergeFunction, buildArrayMergeFunction,
@@ -303,7 +299,7 @@ function createLink(params: {
// Disable subscriptions if too many errors per minute // Disable subscriptions if too many errors per minute
const rpm = errorRpm.hit() const rpm = errorRpm.hit()
if ( if (
process.client && import.meta.client &&
wsClient && wsClient &&
!subscriptionsStopped && !subscriptionsStopped &&
rpm > STOP_SUBSCRIPTIONS_AT_ERRORS_PER_MIN rpm > STOP_SUBSCRIPTIONS_AT_ERRORS_PER_MIN
@@ -336,7 +332,7 @@ export const resolveClientConfig = (
const { httpEndpoint, authToken } = params const { httpEndpoint, authToken } = params
const wsEndpoint = httpEndpoint.replace('http', 'ws') const wsEndpoint = httpEndpoint.replace('http', 'ws')
const wsClient = process.client const wsClient = import.meta.client
? createWsClient({ wsEndpoint, authToken }) ? createWsClient({ wsEndpoint, authToken })
: undefined : undefined
const link = createLink({ httpEndpoint, wsClient, authToken }) const link = createLink({ httpEndpoint, wsClient, authToken })
@@ -1,5 +1,5 @@
import { Optional } from '@speckle/shared' import type { Optional } from '@speckle/shared'
import { FieldMergeFunction } from '@apollo/client/core' import type { FieldMergeFunction } from '@apollo/client/core'
interface AbstractCollection<T extends string> { interface AbstractCollection<T extends string> {
__typename: T __typename: T
+6 -1
View File
@@ -6,7 +6,12 @@ export default defineNuxtConfig({
shim: false, shim: false,
strict: true strict: true
}, },
modules: ['@nuxtjs/tailwindcss', '@speckle/ui-components-nuxt', '@pinia/nuxt'], modules: [
'@nuxt/eslint',
'@nuxtjs/tailwindcss',
'@speckle/ui-components-nuxt',
'@pinia/nuxt'
],
alias: { alias: {
// Rewriting all lodash calls to lodash-es for proper tree-shaking & chunk splitting // Rewriting all lodash calls to lodash-es for proper tree-shaking & chunk splitting
lodash: 'lodash-es' lodash: 'lodash-es'
+9 -6
View File
@@ -13,11 +13,12 @@
"generate": "nuxt generate", "generate": "nuxt generate",
"preview": "nuxt preview", "preview": "nuxt preview",
"postinstall": "yarn ensure:tailwind-deps && nuxt prepare", "postinstall": "yarn ensure:tailwind-deps && nuxt prepare",
"lint:js": "eslint --ext \".js,.ts,.vue\" .", "lint:js": "eslint .",
"lint:tsc": "vue-tsc --noEmit", "lint:tsc": "vue-tsc --noEmit",
"lint:prettier": "prettier --config ../../.prettierrc --ignore-path ../../.prettierignore --check .", "lint:prettier": "prettier --config ../../.prettierrc --ignore-path ../../.prettierignore --check .",
"lint:css": "stylelint \"**/*.{css,vue}\"", "lint:css": "stylelint \"**/*.{css,vue}\"",
"lint": "yarn lint:js && yarn lint:tsc && yarn lint:prettier && yarn lint:css", "lint": "yarn lint:js && yarn lint:tsc && yarn lint:prettier && yarn lint:css",
"lint:ci": "yarn lint:tsc && yarn lint:css",
"gqlgen": "graphql-codegen", "gqlgen": "graphql-codegen",
"gqlgen:watch": "graphql-codegen --watch" "gqlgen:watch": "graphql-codegen --watch"
}, },
@@ -44,18 +45,20 @@
"devDependencies": { "devDependencies": {
"@graphql-codegen/cli": "^2.13.6", "@graphql-codegen/cli": "^2.13.6",
"@graphql-codegen/client-preset": "^1.2.5", "@graphql-codegen/client-preset": "^1.2.5",
"@nuxt/eslint": "^0.3.13",
"@nuxtjs/tailwindcss": "^6.7.0", "@nuxtjs/tailwindcss": "^6.7.0",
"@types/apollo-upload-client": "^17.0.1", "@types/apollo-upload-client": "^17.0.1",
"@types/eslint": "^8.56.10",
"@types/lodash-es": "^4.17.6", "@types/lodash-es": "^4.17.6",
"@types/node": "^18", "@types/node": "^18",
"@typescript-eslint/eslint-plugin": "^7.12.0",
"@typescript-eslint/parser": "^7.12.0",
"@vitejs/plugin-legacy": "^4.0.3", "@vitejs/plugin-legacy": "^4.0.3",
"autoprefixer": "^10.4.14", "autoprefixer": "^10.4.14",
"concurrently": "^7.5.0", "concurrently": "^7.5.0",
"eslint": "^8.24.0", "eslint": "^9.4.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-nuxt": "^4.0.0", "eslint-plugin-vuejs-accessibility": "^2.3.0",
"eslint-plugin-vue": "^9.5.1",
"eslint-plugin-vuejs-accessibility": "^1.2.0",
"nuxt": "^3.6.3", "nuxt": "^3.6.3",
"postcss": "^8.4.31", "postcss": "^8.4.31",
"postcss-custom-properties": "^12.1.9", "postcss-custom-properties": "^12.1.9",
+2 -3
View File
@@ -42,9 +42,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ArrowLeftIcon } from '@heroicons/vue/20/solid' import { ArrowLeftIcon, CheckIcon, MinusIcon, XMarkIcon } from '@heroicons/vue/20/solid'
import { TestEventArgs } from '~/lib/bindings/definitions/ITestBinding' import type { TestEventArgs } from '~/lib/bindings/definitions/ITestBinding'
import { CheckIcon, MinusIcon, XMarkIcon } from '@heroicons/vue/20/solid'
const { $testBindings } = useNuxtApp() const { $testBindings } = useNuxtApp()
const tests = ref([ const tests = ref([
+4 -4
View File
@@ -1,22 +1,22 @@
import { IRawBridge } from '~/lib/bridge/definitions' import type { IRawBridge } from '~/lib/bridge/definitions'
import { GenericBridge } from '~/lib/bridge/generic' import { GenericBridge } from '~/lib/bridge/generic'
import { SketchupBridge } from '~/lib/bridge/sketchup' import { SketchupBridge } from '~/lib/bridge/sketchup'
import type { IBasicConnectorBinding } from '~/lib/bindings/definitions/IBasicConnectorBinding'
import { import {
IBasicConnectorBinding,
IBasicConnectorBindingKey, IBasicConnectorBindingKey,
MockedBaseBinding MockedBaseBinding
} from '~/lib/bindings/definitions/IBasicConnectorBinding' } from '~/lib/bindings/definitions/IBasicConnectorBinding'
import type { ITestBinding } from '~/lib/bindings/definitions/ITestBinding'
import { import {
ITestBinding,
ITestBindingKey, ITestBindingKey,
MockedTestBinding MockedTestBinding
} from '~/lib/bindings/definitions/ITestBinding' } from '~/lib/bindings/definitions/ITestBinding'
import type { IConfigBinding } from '~/lib/bindings/definitions/IConfigBinding'
import { import {
IConfigBinding,
IConfigBindingKey, IConfigBindingKey,
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
MockedConfigBinding MockedConfigBinding
+1 -1
View File
@@ -1,5 +1,5 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { DocumentInfo } from 'lib/bindings/definitions/IBasicConnectorBinding' import type { DocumentInfo } from 'lib/bindings/definitions/IBasicConnectorBinding'
export const useDocumentInfoStore = defineStore('documentInfoStore', () => { export const useDocumentInfoStore = defineStore('documentInfoStore', () => {
const app = useNuxtApp() const app = useNuxtApp()
+1 -1
View File
@@ -1,5 +1,5 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { Config } from 'lib/bindings/definitions/IConfigBinding' import type { Config } from 'lib/bindings/definitions/IConfigBinding'
export const useDocumentInfoStore = defineStore('documentInfoStore', () => { export const useDocumentInfoStore = defineStore('documentInfoStore', () => {
const { $configBinding } = useNuxtApp() const { $configBinding } = useNuxtApp()
-11
View File
@@ -1,11 +0,0 @@
/**
* Extends repo root config, only put changes here that are scoped to this specific package
* (if you already are - evaluate whether you really need package scoped linting rules)
*/
/** @type {import("eslint").Linter.Config} */
const config = {
rules: {}
}
module.exports = config
@@ -0,0 +1,17 @@
import { baseConfigs, globals } from '../../eslint.config.mjs'
/**
* @type {Array<import('eslint').Linter.FlatConfig>}
*/
const configs = [
...baseConfigs,
{
languageOptions: {
globals: {
...globals.node
}
}
}
]
export default configs
@@ -14,7 +14,7 @@ async function main() {
parentLogger.child({ streamId, branchName, userId, fileId, filePath }), parentLogger.child({ streamId, branchName, userId, fileId, filePath }),
'ifc' 'ifc'
) )
// eslint-disable-next-line no-console
logger.info('ARGV: ', filePath, userId, streamId, branchName, commitMessage) logger.info('ARGV: ', filePath, userId, streamId, branchName, commitMessage)
const data = fs.readFileSync(filePath) const data = fs.readFileSync(filePath)
@@ -1,4 +1,3 @@
/* eslint-disable no-console */
/* eslint-disable camelcase */ /* eslint-disable camelcase */
const WebIFC = require('web-ifc/web-ifc-api-node') const WebIFC = require('web-ifc/web-ifc-api-node')
const { logger } = require('../observability/logging.js') const { logger } = require('../observability/logging.js')
+3 -3
View File
@@ -17,7 +17,7 @@
"scripts": { "scripts": {
"dev": "cross-env POSTGRES_URL=postgres://speckle:speckle@127.0.0.1/speckle NODE_ENV=development LOG_PRETTY=true SPECKLE_SERVER_URL=http://127.0.0.1:3000 nodemon --no-experimental-fetch ./src/daemon.js", "dev": "cross-env POSTGRES_URL=postgres://speckle:speckle@127.0.0.1/speckle NODE_ENV=development LOG_PRETTY=true SPECKLE_SERVER_URL=http://127.0.0.1:3000 nodemon --no-experimental-fetch ./src/daemon.js",
"parse:ifc": "node --no-experimental-fetch ./ifc/import_file.js ./ifc/ifcs/steelplates.ifc 33763848d6 2e4bfb467a main File upload: steelplates.ifc", "parse:ifc": "node --no-experimental-fetch ./ifc/import_file.js ./ifc/ifcs/steelplates.ifc 33763848d6 2e4bfb467a main File upload: steelplates.ifc",
"lint": "eslint . --ext .js,.ts" "lint": "eslint ."
}, },
"bugs": { "bugs": {
"url": "https://github.com/specklesystems/speckle-server/issues" "url": "https://github.com/specklesystems/speckle-server/issues"
@@ -38,8 +38,8 @@
}, },
"devDependencies": { "devDependencies": {
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^8.11.0", "eslint": "^9.4.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^9.1.0",
"nodemon": "^2.0.20", "nodemon": "^2.0.20",
"prettier": "^2.5.1" "prettier": "^2.5.1"
} }
@@ -1,4 +1,3 @@
/* eslint-disable no-console */
'use strict' 'use strict'
const { const {
-129
View File
@@ -1,129 +0,0 @@
const mainExtends = [
'plugin:nuxt/recommended',
'plugin:vue/vue3-recommended',
// 'plugin:storybook/recommended',
'prettier'
]
/** @type {import('eslint').Linter.Config} */
const config = {
env: {
node: true
},
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
parser: '@typescript-eslint/parser',
tsconfigRootDir: __dirname,
project: ['./tsconfig.eslint.json'],
extraFileExtensions: ['.vue']
},
extends: [...mainExtends],
plugins: ['@typescript-eslint'],
ignorePatterns: [
'**/templates/*',
'coverage',
'lib/common/generated/**/*',
'storybook-static',
'!.storybook',
'.nuxt',
'.output'
],
rules: {
camelcase: [
'error',
{
properties: 'always',
allow: ['^[\\w]+_[\\w]+Fragment$']
}
],
'no-alert': 'error',
eqeqeq: ['error', 'always', { null: 'always' }],
'no-console': 'error',
'no-var': 'error'
},
overrides: [
{
files: '*.test.{ts,js}',
env: {
jest: true
}
},
{
files: './{components|pages|store|lib}/*.{js,ts,vue}',
env: {
node: false,
browser: true
}
},
{
files: '*.{ts,tsx,vue}',
extends: ['plugin:@typescript-eslint/recommended', ...mainExtends],
rules: {
'@typescript-eslint/no-explicit-any': ['error'],
'@typescript-eslint/no-unsafe-argument': ['error'],
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
'@typescript-eslint/no-for-in-array': ['error'],
'@typescript-eslint/restrict-template-expressions': ['error'],
'@typescript-eslint/restrict-plus-operands': ['error'],
'@typescript-eslint/await-thenable': ['warn'],
'@typescript-eslint/ban-types': ['warn'],
'require-await': 'off',
'@typescript-eslint/require-await': 'error',
'no-undef': 'off'
}
},
{
files: '*.vue',
plugins: ['vuejs-accessibility'],
extends: [
'plugin:@typescript-eslint/recommended',
...mainExtends,
'plugin:vuejs-accessibility/recommended'
],
rules: {
'vue/component-tags-order': [
'error',
{ order: ['docs', 'template', 'script', 'style'] }
],
'vue/require-default-prop': 'off',
'vue/multi-word-component-names': 'off',
'vue/component-name-in-template-casing': [
'error',
'PascalCase',
{ registeredComponentsOnly: false }
],
'vuejs-accessibility/label-has-for': [
'error',
{
required: {
some: ['nesting', 'id']
}
}
]
}
},
{
files: '*.d.ts',
rules: {
'no-var': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/ban-types': 'off'
}
}
// {
// files: '*.stories.{js,ts}',
// rules: {
// // this one feels busted, tells me to await synchronous calls
// 'storybook/await-interactions': 'off',
// // storybook types suck and can't be augmented
// '@typescript-eslint/no-unsafe-call': 'off'
// }
// }
]
}
module.exports = config
@@ -49,12 +49,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { useQuery } from '@vue/apollo-composable' import { useQuery } from '@vue/apollo-composable'
import { AuthStrategy } from '~~/lib/auth/helpers/strategies' import { AuthStrategy } from '~~/lib/auth/helpers/strategies'
import { useLoginOrRegisterUtils } from '~~/lib/auth/composables/auth' import { useLoginOrRegisterUtils, useAuthManager } from '~~/lib/auth/composables/auth'
import { loginServerInfoQuery } from '~~/lib/auth/graphql/queries' import { loginServerInfoQuery } from '~~/lib/auth/graphql/queries'
import { LayoutDialog, LayoutPanel } from '@speckle/ui-components' import { LayoutDialog, LayoutPanel } from '@speckle/ui-components'
import { ArrowRightIcon } from '@heroicons/vue/20/solid' import { ArrowRightIcon } from '@heroicons/vue/20/solid'
import { registerRoute } from '~~/lib/common/helpers/route' import { registerRoute } from '~~/lib/common/helpers/route'
import { useAuthManager } from '~~/lib/auth/composables/auth'
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@@ -63,7 +63,7 @@
v-if="serverInfo.termsOfService" v-if="serverInfo.termsOfService"
class="mt-2 text-xs text-foreground-2 text-center terms-of-service" class="mt-2 text-xs text-foreground-2 text-center terms-of-service"
v-html="serverInfo.termsOfService" v-html="serverInfo.termsOfService"
></div> />
<div class="mt-2 sm:mt-8 text-center text-xs sm:text-base"> <div class="mt-2 sm:mt-8 text-center text-xs sm:text-base">
<span class="mr-2">Already have an account?</span> <span class="mr-2">Already have an account?</span>
<CommonTextLink :to="finalLoginRoute" :icon-right="ArrowRightIcon"> <CommonTextLink :to="finalLoginRoute" :icon-right="ArrowRightIcon">
@@ -93,7 +93,7 @@ const getButtonComponent = (strat: StrategyType) => {
} }
const onClick = (strat: StrategyType) => { const onClick = (strat: StrategyType) => {
if (!process.client) return if (!import.meta.client) return
const redirectUrl = buildAuthUrl(strat) const redirectUrl = buildAuthUrl(strat)
mixpanel.track('Log In', { mixpanel.track('Log In', {
@@ -50,13 +50,15 @@ import type {
CreatableFunctionTemplate, CreatableFunctionTemplate,
FunctionDetailsFormValues FunctionDetailsFormValues
} from '~/lib/automate/helpers/functions' } from '~/lib/automate/helpers/functions'
import { automateGithubAppAuthorizationRoute } from '~/lib/common/helpers/route' import {
automateGithubAppAuthorizationRoute,
automationFunctionRoute
} from '~/lib/common/helpers/route'
import { useEnumSteps, useEnumStepsWidgetSetup } from '~/lib/form/composables/steps' import { useEnumSteps, useEnumStepsWidgetSetup } from '~/lib/form/composables/steps'
import { useForm } from 'vee-validate' import { useForm } from 'vee-validate'
import { useCreateAutomateFunction } from '~/lib/automate/composables/management' import { useCreateAutomateFunction } from '~/lib/automate/composables/management'
import { useMutationLoading } from '@vue/apollo-composable' import { useMutationLoading } from '@vue/apollo-composable'
import type { AutomateFunctionCreateDialogDoneStep_AutomateFunctionFragment } from '~~/lib/common/generated/gql/graphql' import type { AutomateFunctionCreateDialogDoneStep_AutomateFunctionFragment } from '~~/lib/common/generated/gql/graphql'
import { automationFunctionRoute } from '~/lib/common/helpers/route'
import { useMixpanel } from '~/lib/core/composables/mp' import { useMixpanel } from '~/lib/core/composables/mp'
enum FunctionCreateSteps { enum FunctionCreateSteps {
@@ -4,10 +4,7 @@
class="pt-4 flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between" class="pt-4 flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between"
> >
<Portal to="navigation"> <Portal to="navigation">
<HeaderNavLink <HeaderNavLink :to="automationFunctionsRoute" :name="'Automate Functions'" />
:to="automationFunctionsRoute"
:name="'Automate Functions'"
></HeaderNavLink>
</Portal> </Portal>
<h1 class="h3 font-bold">Automate Functions</h1> <h1 class="h3 font-bold">Automate Functions</h1>
@@ -84,7 +81,7 @@ const canCreateFunction = computed(
() => !!props.activeUser?.id && !!availableTemplates.value.length () => !!props.activeUser?.id && !!availableTemplates.value.length
) )
if (process.client) { if (import.meta.client) {
watch( watch(
() => route.query['ghAuth'] as Nullable<string>, () => route.query['ghAuth'] as Nullable<string>,
(ghAuthVal) => { (ghAuthVal) => {
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<!-- eslint-disable vuejs-accessibility/click-events-have-key-events --> <!-- eslint-disable vuejs-accessibility/click-events-have-key-events -->
<template> <template>
<a <a
@@ -60,7 +60,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useMutation } from '@vue/apollo-composable' import { useMutation } from '@vue/apollo-composable'
import { AllScopes } from '@speckle/shared' import type { AllScopes } from '@speckle/shared'
import { import {
LayoutDialog, LayoutDialog,
FormSelectBadges, FormSelectBadges,
@@ -74,7 +74,12 @@ import {
createApplicationMutation, createApplicationMutation,
editApplicationMutation editApplicationMutation
} from '~~/lib/developer-settings/graphql/mutations' } from '~~/lib/developer-settings/graphql/mutations'
import { isItemSelected } from '~~/lib/common/helpers/validation' import {
isItemSelected,
isRequired,
isUrl,
fullyResetForm
} from '~~/lib/common/helpers/validation'
import { useForm } from 'vee-validate' import { useForm } from 'vee-validate'
import { import {
convertThrowIntoFetchResult, convertThrowIntoFetchResult,
@@ -82,7 +87,6 @@ import {
getFirstErrorMessage getFirstErrorMessage
} from '~~/lib/common/helpers/graphql' } from '~~/lib/common/helpers/graphql'
import { useGlobalToast, ToastNotificationType } from '~~/lib/common/composables/toast' import { useGlobalToast, ToastNotificationType } from '~~/lib/common/composables/toast'
import { isRequired, isUrl, fullyResetForm } from '~~/lib/common/helpers/validation'
import { useServerInfoScopes } from '~~/lib/common/composables/serverInfo' import { useServerInfoScopes } from '~~/lib/common/composables/serverInfo'
const props = defineProps<{ const props = defineProps<{
@@ -39,7 +39,7 @@ const onError = (err: unknown) => logger.error(err)
const onProcessed = (val: { accepted: boolean }) => { const onProcessed = (val: { accepted: boolean }) => {
const { accepted } = val const { accepted } = val
if (accepted && projectId.value && process.client) { if (accepted && projectId.value && import.meta.client) {
goToProject({ id: projectId.value }) goToProject({ id: projectId.value })
} }
} }
@@ -22,6 +22,6 @@ const props = defineProps<{
} }
}>() }>()
const isDev = ref(process.dev) const isDev = ref(import.meta.dev)
const finalError = computed(() => formatAppError(props.error)) const finalError = computed(() => formatAppError(props.error))
</script> </script>
@@ -63,7 +63,7 @@ const props = withDefaults(
defineModel<string>() defineModel<string>()
const { value } = useField<string>(props.name, props.rules) const { value } = useField<string>(props.name, props.rules)
const body = computed(() => (process.client ? document.body : undefined)) const body = computed(() => (import.meta.client ? document.body : undefined))
const isEditing = ref(true) const isEditing = ref(true)
const isPreviewDisabled = computed(() => !(value.value || '').trim().length) const isPreviewDisabled = computed(() => !(value.value || '').trim().length)
@@ -128,7 +128,6 @@ const onAdd = () => {
const path = control.value.path const path = control.value.path
const val = createDefaultValue(control.value.schema, props.schema) const val = createDefaultValue(control.value.schema, props.schema)
// eslint-disable-next-line @typescript-eslint/unbound-method
const addItem = baseControl.addItem const addItem = baseControl.addItem
if (!addItem) return if (!addItem) return
@@ -43,7 +43,6 @@ const {
onChangeValueConverter: (val) => toISOString(val as string) onChangeValueConverter: (val) => toISOString(val as string)
}) })
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
const modelValue = computed(() => const modelValue = computed(() =>
control.value.data control.value.data
? (control.value.data as string).replace(zuluTimeSuffix, '') ? (control.value.data as string).replace(zuluTimeSuffix, '')
@@ -13,6 +13,5 @@ const props = defineProps({
...rendererProps<ControlElement>() ...rendererProps<ControlElement>()
}) })
// eslint-disable-next-line @typescript-eslint/unbound-method
const controlOverrides = useJsonFormsOneOfEnumControl(props) const controlOverrides = useJsonFormsOneOfEnumControl(props)
</script> </script>
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template> <template>
<Menu <Menu
as="div" as="div"
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<!-- eslint-disable vuejs-accessibility/click-events-have-key-events --> <!-- eslint-disable vuejs-accessibility/click-events-have-key-events -->
<template> <template>
<div class="relative"> <div class="relative">
@@ -405,7 +406,7 @@ const goToFirstUncompletedStep = () => {
const firstNonCompleteStepIndex = steps.value.findIndex((s) => s.completed === false) const firstNonCompleteStepIndex = steps.value.findIndex((s) => s.completed === false)
activateStep(firstNonCompleteStepIndex) activateStep(firstNonCompleteStepIndex)
if (process.client) { if (import.meta.client) {
mp.track('Onboarding Action', { mp.track('Onboarding Action', {
type: 'action', type: 'action',
name: 'checklist', name: 'checklist',
@@ -60,7 +60,7 @@ const openState = computed({
const hasDownloadedManager = useSynchronizedCookie<boolean>(`hasDownloadedManager`) const hasDownloadedManager = useSynchronizedCookie<boolean>(`hasDownloadedManager`)
const getOs = () => { const getOs = () => {
if (process.server) return 'unknown' if (import.meta.server) return 'unknown'
const userAgent = window.navigator.userAgent const userAgent = window.navigator.userAgent
const platform = const platform =
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template> <template>
<!-- eslint-disable-next-line vuejs-accessibility/mouse-events-have-key-events --> <!-- eslint-disable-next-line vuejs-accessibility/mouse-events-have-key-events -->
<div <div
@@ -122,7 +123,7 @@ const setParentDimensions = () => {
parentWidth = parent.value?.getBoundingClientRect().width as number parentWidth = parent.value?.getBoundingClientRect().width as number
parentHeight = parent.value?.getBoundingClientRect().height as number parentHeight = parent.value?.getBoundingClientRect().height as number
} }
if (process.client) useResizeObserver(document.body, () => setParentDimensions()) if (import.meta.client) useResizeObserver(document.body, () => setParentDimensions())
const positionMagic = ref(0) const positionMagic = ref(0)
const calculatePanoramaStyle = (e: MouseEvent) => { const calculatePanoramaStyle = (e: MouseEvent) => {
@@ -157,7 +158,7 @@ watch(hovered, (newVal) => {
shouldLoadPanorama.value = true shouldLoadPanorama.value = true
}) })
if (process.client) { if (import.meta.client) {
// Trigger transitions when preview image changes // Trigger transitions when preview image changes
watch(finalPreviewUrl, (newVal, oldVal) => { watch(finalPreviewUrl, (newVal, oldVal) => {
if (newVal === oldVal) return if (newVal === oldVal) return
@@ -27,10 +27,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { isArray } from 'lodash-es' import { isArray } from 'lodash-es'
import { import type { CommentPermissions } from '~~/lib/projects/helpers/components'
CommentPermissions, import { commentPermissionsSelectItems } from '~~/lib/projects/helpers/components'
commentPermissionsSelectItems
} from '~~/lib/projects/helpers/components'
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:modelValue', v: CommentPermissions): void (e: 'update:modelValue', v: CommentPermissions): void
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<!-- eslint-disable vuejs-accessibility/click-events-have-key-events --> <!-- eslint-disable vuejs-accessibility/click-events-have-key-events -->
<!-- eslint-disable vuejs-accessibility/mouse-events-have-key-events --> <!-- eslint-disable vuejs-accessibility/mouse-events-have-key-events -->
<template> <template>
@@ -93,7 +94,7 @@ import type {
import { modelRoute } from '~~/lib/common/helpers/route' import { modelRoute } from '~~/lib/common/helpers/route'
import { graphql } from '~~/lib/common/generated/gql' import { graphql } from '~~/lib/common/generated/gql'
import { SpeckleViewer, SourceApps } from '@speckle/shared' import { SpeckleViewer, SourceApps } from '@speckle/shared'
import { VersionActionTypes } from '~~/lib/projects/helpers/components' import type { VersionActionTypes } from '~~/lib/projects/helpers/components'
import { isPendingVersionFragment } from '~~/lib/projects/helpers/models' import { isPendingVersionFragment } from '~~/lib/projects/helpers/models'
import { ChatBubbleLeftRightIcon } from '@heroicons/vue/24/solid' import { ChatBubbleLeftRightIcon } from '@heroicons/vue/24/solid'
@@ -19,7 +19,7 @@
import type { Optional } from '@speckle/shared' import type { Optional } from '@speckle/shared'
import { graphql } from '~~/lib/common/generated/gql' import { graphql } from '~~/lib/common/generated/gql'
import type { ProjectDiscussionsPageHeader_ProjectFragment } from '~~/lib/common/generated/gql/graphql' import type { ProjectDiscussionsPageHeader_ProjectFragment } from '~~/lib/common/generated/gql/graphql'
import { GridListToggleValue } from '~~/lib/layout/helpers/components' import type { GridListToggleValue } from '~~/lib/layout/helpers/components'
graphql(` graphql(`
fragment ProjectDiscussionsPageHeader_Project on Project { fragment ProjectDiscussionsPageHeader_Project on Project {
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<!-- eslint-disable vuejs-accessibility/mouse-events-have-key-events --> <!-- eslint-disable vuejs-accessibility/mouse-events-have-key-events -->
<template> <template>
<div <div
@@ -100,7 +100,7 @@ import type {
ProjectModelsPageHeader_ProjectFragment ProjectModelsPageHeader_ProjectFragment
} from '~~/lib/common/generated/gql/graphql' } from '~~/lib/common/generated/gql/graphql'
import { modelRoute } from '~~/lib/common/helpers/route' import { modelRoute } from '~~/lib/common/helpers/route'
import { GridListToggleValue } from '~~/lib/layout/helpers/components' import type { GridListToggleValue } from '~~/lib/layout/helpers/components'
import { PlusIcon } from '@heroicons/vue/24/solid' import { PlusIcon } from '@heroicons/vue/24/solid'
import { canModifyModels } from '~~/lib/projects/helpers/permissions' import { canModifyModels } from '~~/lib/projects/helpers/permissions'
import { CubeIcon } from '@heroicons/vue/24/outline' import { CubeIcon } from '@heroicons/vue/24/outline'
@@ -44,14 +44,16 @@ import type {
PendingFileUploadFragment, PendingFileUploadFragment,
ProjectPageLatestItemsModelsFragment, ProjectPageLatestItemsModelsFragment,
SingleLevelModelTreeItemFragment, SingleLevelModelTreeItemFragment,
FormUsersSelectItemFragment FormUsersSelectItemFragment,
ProjectModelsTreeTopLevelQueryVariables
} from '~~/lib/common/generated/gql/graphql' } from '~~/lib/common/generated/gql/graphql'
import { useQuery, useQueryLoading } from '@vue/apollo-composable' import { useQuery, useQueryLoading } from '@vue/apollo-composable'
import { projectModelsTreeTopLevelQuery } from '~~/lib/projects/graphql/queries' import {
projectModelsTreeTopLevelQuery,
projectModelsTreeTopLevelPaginationQuery
} from '~~/lib/projects/graphql/queries'
import { canModifyModels } from '~~/lib/projects/helpers/permissions' import { canModifyModels } from '~~/lib/projects/helpers/permissions'
import type { ProjectModelsTreeTopLevelQueryVariables } from '~~/lib/common/generated/gql/graphql'
import type { Nullable, SourceAppDefinition } from '@speckle/shared' import type { Nullable, SourceAppDefinition } from '@speckle/shared'
import { projectModelsTreeTopLevelPaginationQuery } from '~~/lib/projects/graphql/queries'
import type { InfiniteLoaderState } from '~~/lib/global/helpers/components' import type { InfiniteLoaderState } from '~~/lib/global/helpers/components'
import { useEvictProjectModelFields } from '~~/lib/projects/composables/modelManagement' import { useEvictProjectModelFields } from '~~/lib/projects/composables/modelManagement'
import { allProjectModelsRoute } from '~~/lib/common/helpers/route' import { allProjectModelsRoute } from '~~/lib/common/helpers/route'
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<!-- eslint-disable vuejs-accessibility/mouse-events-have-key-events --> <!-- eslint-disable vuejs-accessibility/mouse-events-have-key-events -->
<template> <template>
<div class="space-y-4 relative" @mouseleave="showActionsMenu = false"> <div class="space-y-4 relative" @mouseleave="showActionsMenu = false">
@@ -7,7 +7,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ProjectPageTeamDialogFragment } from '~~/lib/common/generated/gql/graphql' import type { ProjectPageTeamDialogFragment } from '~~/lib/common/generated/gql/graphql'
import { graphql } from '~~/lib/common/generated/gql' import { graphql } from '~~/lib/common/generated/gql'
import { OpenSectionType } from '~~/lib/projects/helpers/components' import type { OpenSectionType } from '~~/lib/projects/helpers/components'
graphql(` graphql(`
fragment ProjectPageTeamDialog on Project { fragment ProjectPageTeamDialog on Project {
@@ -39,8 +39,7 @@
import { roleSelectItems } from '~~/lib/projects/helpers/components' import { roleSelectItems } from '~~/lib/projects/helpers/components'
import { Roles } from '@speckle/shared' import { Roles } from '@speckle/shared'
import type { StreamRoles } from '@speckle/shared' import type { StreamRoles } from '@speckle/shared'
import { reduce } from 'lodash-es' import { reduce, isArray } from 'lodash-es'
import { isArray } from 'lodash-es'
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:modelValue', v: StreamRoles): void (e: 'update:modelValue', v: StreamRoles): void
@@ -9,8 +9,10 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ProjectVisibility } from '~~/lib/common/generated/gql/graphql' import type {
import type { ProjectsPageTeamDialogManagePermissions_ProjectFragment } from '~~/lib/common/generated/gql/graphql' ProjectVisibility,
ProjectsPageTeamDialogManagePermissions_ProjectFragment
} from '~~/lib/common/generated/gql/graphql'
import { useTeamManagePermissionsInternals } from '~~/lib/projects/composables/team' import { useTeamManagePermissionsInternals } from '~~/lib/projects/composables/team'
import { graphql } from '~~/lib/common/generated/gql/gql' import { graphql } from '~~/lib/common/generated/gql/gql'
@@ -124,7 +124,7 @@ const onLoginClick = () => {
}) })
} }
if (process.client) { if (import.meta.client) {
watch( watch(
() => props.autoAccept, () => props.autoAccept,
async (newVal, oldVal) => { async (newVal, oldVal) => {
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template> <template>
<div class="text-foreground"> <div class="text-foreground">
<div class="w-full text-sm overflow-x-auto overflow-y-visible simple-scrollbar"> <div class="w-full text-sm overflow-x-auto overflow-y-visible simple-scrollbar">
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template> <template>
<div class="max-w-xl w-screen h-[100dvh] flex items-center justify-center"> <div class="max-w-xl w-screen h-[100dvh] flex items-center justify-center">
<Transition <Transition
@@ -49,7 +49,7 @@
<script setup lang="ts"> <script setup lang="ts">
// Disclaimer, not the cleanest code. // Disclaimer, not the cleanest code.
import type { Nullable } from '@speckle/shared' import type { Nullable } from '@speckle/shared'
import { Vector3 } from 'three' import type { Vector3 } from 'three'
import { items as slideshowItemsRaw } from '~~/lib/tour/slideshowItems' import { items as slideshowItemsRaw } from '~~/lib/tour/slideshowItems'
import { ArrowRightIcon } from '@heroicons/vue/24/solid' import { ArrowRightIcon } from '@heroicons/vue/24/solid'
import { useViewerAnchoredPoints } from '~~/lib/viewer/composables/anchorPoints' import { useViewerAnchoredPoints } from '~~/lib/viewer/composables/anchorPoints'
@@ -12,7 +12,7 @@ const {
} = useInjectedViewer() } = useInjectedViewer()
onMounted(async () => { onMounted(async () => {
if (!process.client) return if (!import.meta.client) return
await isInitializedPromise await isInitializedPromise
container.style.display = 'block' container.style.display = 'block'
@@ -24,7 +24,7 @@ onMounted(async () => {
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
if (!process.client) return if (!import.meta.client) return
container.style.display = 'none' container.style.display = 'none'
document.body.appendChild(container) document.body.appendChild(container)
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template> <template>
<div v-if="showControls"> <div v-if="showControls">
<div <div
@@ -290,7 +291,7 @@ const startResizing = (event: MouseEvent) => {
startWidth = width.value startWidth = width.value
} }
if (process.client) { if (import.meta.client) {
useResizeObserver(scrollableControlsContainer, (entries) => { useResizeObserver(scrollableControlsContainer, (entries) => {
// const entry = entries[0] // const entry = entries[0]
const { height: newHeight } = entries[0].contentRect const { height: newHeight } = entries[0].contentRect
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template> <template>
<div <div
ref="resizableElement" ref="resizableElement"
@@ -106,7 +107,7 @@ const startResizing = (event: MouseEvent) => {
startWidth = width.value startWidth = width.value
} }
if (process.client) { if (import.meta.client) {
useEventListener(resizeHandle, 'mousedown', startResizing) useEventListener(resizeHandle, 'mousedown', startResizing)
useEventListener(document, 'mousemove', (event) => { useEventListener(document, 'mousemove', (event) => {
@@ -87,9 +87,8 @@ import {
convertCommentEditorValueToInput convertCommentEditorValueToInput
} from '~~/lib/viewer/helpers/comments' } from '~~/lib/viewer/helpers/comments'
import { useMixpanel } from '~~/lib/core/composables/mp' import { useMixpanel } from '~~/lib/core/composables/mp'
import { useThreadUtilities } from '~~/lib/viewer/composables/ui' import { useThreadUtilities, useSelectionUtilities } from '~~/lib/viewer/composables/ui'
import { useEmbed } from '~/lib/viewer/composables/setup/embed' import { useEmbed } from '~/lib/viewer/composables/setup/embed'
import { useSelectionUtilities } from '~~/lib/viewer/composables/ui'
const { isEnabled: isEmbedEnabled } = useEmbed() const { isEnabled: isEmbedEnabled } = useEmbed()
@@ -439,7 +439,7 @@ const onLoadThreadContext = async () => {
} }
const onCopyLink = async () => { const onCopyLink = async () => {
if (process.server) return if (import.meta.server) return
const url = getLinkToThread(projectId.value, props.modelValue) const url = getLinkToThread(projectId.value, props.modelValue)
if (!url) return if (!url) return
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template> <template>
<!-- eslint-disable-next-line vuejs-accessibility/click-events-have-key-events --> <!-- eslint-disable-next-line vuejs-accessibility/click-events-have-key-events -->
<div <div
@@ -93,7 +94,6 @@ const open = (id: string) => {
const formattedDate = computed(() => dayjs(props.thread.createdAt).from(dayjs())) const formattedDate = computed(() => dayjs(props.thread.createdAt).from(dayjs()))
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const isThreadResourceLoaded = computed(() => { const isThreadResourceLoaded = computed(() => {
const thread = props.thread const thread = props.thread
const loadedResources = resourceItems.value const loadedResources = resourceItems.value
@@ -1,58 +0,0 @@
<template>
<div>
<div
:class="`flex group justify-between pl-1 py-1 items-center text-foreground cursor-pointer w-full max-w-full overflow-hidden select-none rounded border-l-4 hover:bg-primary-muted hover:shadow-md transition-all ${
isSelected ? 'border-primary bg-primary-muted' : 'border-transparent'
}`"
@click="setSelection()"
@keypress="keyboardClick(setSelection)"
>
<div class="flex space-x-2 items-center truncate">
<span :class="`w-3 h-3 rounded ${colorClasses}`"></span>
<span class="truncate">
{{ name }}
</span>
<span class="text-xs text-foreground-2">({{ objectIds.length }})</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { keyboardClick } from '@speckle/ui-components'
import { useSelectionUtilities } from '~~/lib/viewer/composables/ui'
const {
clearSelection,
setSelectionFromObjectIds,
objects: selectedObjects
} = useSelectionUtilities()
const props = defineProps<{
name: 'unchanged' | 'added' | 'removed' | 'modified'
objectIds: string[]
}>()
const colorClasses = computed(() => {
switch (props.name) {
case 'added':
return 'bg-green-500'
case 'removed':
return 'bg-rose-500'
case 'modified':
return 'bg-yellow-500'
case 'unchanged':
default:
return 'bg-neutral-500'
}
})
const isSelected = computed(() => {
const selObjsIds = selectedObjects.value.map((o) => o.id as string)
return selObjsIds.some((id: string) => props.objectIds.includes(id))
})
const setSelection = () => {
if (isSelected.value) return clearSelection()
setSelectionFromObjectIds(props.objectIds)
}
</script>
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template> <template>
<div <div
:class="`bg-foundation-2 shadow h-24 flex items-center justify-center flex-col rounded-md min-w-0 cursor-pointer :class="`bg-foundation-2 shadow h-24 flex items-center justify-center flex-col rounded-md min-w-0 cursor-pointer
@@ -65,10 +65,9 @@
import { ChevronLeftIcon } from '@heroicons/vue/24/solid' import { ChevronLeftIcon } from '@heroicons/vue/24/solid'
import { VisualDiffMode } from '@speckle/viewer' import { VisualDiffMode } from '@speckle/viewer'
import { useInjectedViewerState } from '~~/lib/viewer/composables/setup' import { useInjectedViewerState } from '~~/lib/viewer/composables/setup'
import { uniqBy } from 'lodash-es' import { uniqBy, debounce } from 'lodash-es'
import type { SpeckleObject } from '~~/lib/common/helpers/sceneExplorer' import type { SpeckleObject } from '~~/lib/common/helpers/sceneExplorer'
import { useMixpanel } from '~~/lib/core/composables/mp' import { useMixpanel } from '~~/lib/core/composables/mp'
import { debounce } from 'lodash-es'
defineEmits<{ defineEmits<{
(e: 'close'): void (e: 'close'): void
@@ -143,7 +142,6 @@ const added = computed(() => {
const addedIds = computed(() => added.value.map((o) => o.id as string)) const addedIds = computed(() => added.value.map((o) => o.id as string))
const removed = computed(() => { const removed = computed(() => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
const mapped = diffState.result.value?.removed.map( const mapped = diffState.result.value?.removed.map(
(node) => node.model.raw as SpeckleObject (node) => node.model.raw as SpeckleObject
) )
@@ -35,7 +35,6 @@ if (props.object['referencedId']) {
} }
const kvps = computed(() => { const kvps = computed(() => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const obj = (result.value?.stream?.object?.data || props.object) as Record< const obj = (result.value?.stream?.object?.data || props.object) as Record<
string, string,
unknown unknown
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template> <template>
<div <div
:class="`w-full bg-foundation-2 hover:bg-blue-500/5 rounded pl-1 py-1 border-l-2 text-xs ${ :class="`w-full bg-foundation-2 hover:bg-blue-500/5 rounded pl-1 py-1 border-l-2 text-xs ${
@@ -119,6 +119,7 @@ const rootNodes = computed(() => {
refhack.value refhack.value
if (!worldTree.value) return [] if (!worldTree.value) return []
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
expandLevel.value = -1 expandLevel.value = -1
const nodes = [] const nodes = []
const rootNodes = worldTree.value._root.children as ExplorerNode[] const rootNodes = worldTree.value._root.children as ExplorerNode[]
@@ -176,6 +176,7 @@ const numericActiveFilter = computed(() => activeFilter.value as NumericProperty
const searchString = ref<string | undefined>(undefined) const searchString = ref<string | undefined>(undefined)
const relevantFiltersSearched = computed(() => { const relevantFiltersSearched = computed(() => {
if (!searchString.value) return relevantFilters.value if (!searchString.value) return relevantFilters.value
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
itemCount.value = 30 // nasty, but yolo - reset max limit on search change itemCount.value = 30 // nasty, but yolo - reset max limit on search change
return relevantFilters.value.filter((f) => return relevantFilters.value.filter((f) =>
f.key.toLowerCase().includes((searchString.value as string).toLowerCase()) f.key.toLowerCase().includes((searchString.value as string).toLowerCase())
@@ -202,7 +203,6 @@ const title = computed(() => {
currentFilterKey.startsWith('parameters.') && currentFilterKey.startsWith('parameters.') &&
currentFilterKey.endsWith('.value') currentFilterKey.endsWith('.value')
) { ) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
return ( return (
props.filters.find( props.filters.find(
(f) => f.key === currentFilterKey.replace('.value', '.name') (f) => f.key === currentFilterKey.replace('.value', '.name')
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template> <template>
<div> <div>
<!-- eslint-disable-next-line vuejs-accessibility/click-events-have-key-events --> <!-- eslint-disable-next-line vuejs-accessibility/click-events-have-key-events -->
@@ -1,7 +1,5 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template> <template>
<!-- -->
<!-- WIP -->
<!-- -->
<div class="w-full select-none"> <div class="w-full select-none">
<!-- Header --> <!-- Header -->
<div class="bg-foundation w-full rounded-md py-1 px-1"> <div class="bg-foundation w-full rounded-md py-1 px-1">
@@ -210,6 +208,7 @@ const childrenLength = computed(() => {
return rawSpeckleData.elements.length return rawSpeckleData.elements.length
if (rawSpeckleData.children && Array.isArray(rawSpeckleData.children)) if (rawSpeckleData.children && Array.isArray(rawSpeckleData.children))
return rawSpeckleData.children.length return rawSpeckleData.children.length
return 0
}) })
const isSingleCollection = computed(() => { const isSingleCollection = computed(() => {
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template> <template>
<div class="relative"> <div class="relative">
<!-- eslint-disable-next-line vuejs-accessibility/click-events-have-key-events --> <!-- eslint-disable-next-line vuejs-accessibility/click-events-have-key-events -->
@@ -1,3 +1,4 @@
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template> <template>
<div <div
:class="`bg-foundation group relative block w-full space-y-2 rounded-md pb-2 text-left ${ :class="`bg-foundation group relative block w-full space-y-2 rounded-md pb-2 text-left ${
+1 -2
View File
@@ -1,7 +1,6 @@
import { ensureError } from '@speckle/shared' import { ensureError } from '@speckle/shared'
import { useClipboard as coreUseClipboard } from '@vueuse/core' import { useClipboard as coreUseClipboard, useBreakpoints } from '@vueuse/core'
import { ToastNotificationType, useGlobalToast } from '~~/lib/common/composables/toast' import { ToastNotificationType, useGlobalToast } from '~~/lib/common/composables/toast'
import { useBreakpoints } from '@vueuse/core'
import { TailwindBreakpoints } from '~~/lib/common/helpers/tailwind' import { TailwindBreakpoints } from '~~/lib/common/helpers/tailwind'
/** /**
* A wrapper over vueuse's useClipboard that also triggers toast notifications * A wrapper over vueuse's useClipboard that also triggers toast notifications
+1 -1
View File
@@ -7,7 +7,7 @@ export const useApiOrigin = () => {
public: { apiOrigin, backendApiOrigin } public: { apiOrigin, backendApiOrigin }
} = useRuntimeConfig() } = useRuntimeConfig()
if (process.server && backendApiOrigin.length > 1) { if (import.meta.server && backendApiOrigin.length > 1) {
return backendApiOrigin return backendApiOrigin
} }
+3 -3
View File
@@ -32,9 +32,9 @@ export const useStrictLogger = async (
) )
let logger: ReturnType<typeof buildFakePinoLogger> let logger: ReturnType<typeof buildFakePinoLogger>
if (process.server) { if (import.meta.server) {
const { buildLogger } = await import('~/server/lib/core/helpers/observability') const { buildLogger } = await import('~/server/lib/core/helpers/observability')
logger = buildLogger('info', process.dev ? true : false) // no runtime config, so falling back to default settings logger = buildLogger('info', import.meta.dev ? true : false) // no runtime config, so falling back to default settings
} else { } else {
logger = buildFakePinoLogger() logger = buildFakePinoLogger()
} }
@@ -49,7 +49,7 @@ export const useStrictLogger = async (
* Calls to this are skipped outside of dev mode. * Calls to this are skipped outside of dev mode.
*/ */
export const useDevLogger = () => { export const useDevLogger = () => {
if (!process.dev) return noop if (!import.meta.dev) return noop
const logger = useLogger() const logger = useLogger()
const info = logger.info.bind(logger) const info = logger.info.bind(logger)
+125
View File
@@ -0,0 +1,125 @@
import { omit } from 'lodash-es'
import { baseConfigs, globals, getESMDirname } from '../../eslint.config.mjs'
import withNuxt from './.nuxt/eslint.config.mjs'
import pluginVueA11y from 'eslint-plugin-vuejs-accessibility'
const configs = withNuxt([
{
rules: {
camelcase: [
'error',
{
properties: 'always',
allow: ['^[\\w]+_[\\w]+Fragment$']
}
],
'no-alert': 'error',
eqeqeq: ['error', 'always', { null: 'always' }],
'no-console': 'error',
'no-var': 'error'
}
},
{
files: ['**/*.{ts,vue}'],
languageOptions: {
parserOptions: {
project: ['./tsconfig.eslint.json'],
extraFileExtensions: ['.vue'],
tsconfigRootDir: getESMDirname(import.meta.url)
}
}
},
{
files: ['**/*.test.{ts,js}'],
languageOptions: {
globals: {
...globals.jest
}
}
},
{
files: ['./{components|pages|store|lib}/*.{js,ts,vue}'],
languageOptions: {
globals: {
...globals.browser
}
}
},
{
files: ['**/*.{ts,tsx,vue}'],
rules: {
'@typescript-eslint/no-explicit-any': ['error'],
'@typescript-eslint/no-unsafe-argument': ['error'],
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
'@typescript-eslint/no-for-in-array': ['error'],
'@typescript-eslint/restrict-plus-operands': ['error'],
'@typescript-eslint/await-thenable': ['warn'],
'@typescript-eslint/ban-types': ['warn'],
'require-await': 'off',
'@typescript-eslint/require-await': 'error',
'no-undef': 'off',
'@typescript-eslint/unified-signatures': 'off', // DX sucks in vue event definitions
'@typescript-eslint/no-dynamic-delete': 'off', // too restrictive
'@typescript-eslint/restrict-template-expressions': 'off', // too restrictive
'@typescript-eslint/no-invalid-void-type': 'off' // too restrictive
}
},
...pluginVueA11y.configs['flat/recommended'].map((c) => ({
...c,
files: [...(c.files || []), '**/*.vue'],
languageOptions: c.languageOptions
? omit(c.languageOptions, ['parserOptions', 'parser']) // Prevent overriding parser
: undefined
})),
{
files: ['**/*.vue'],
rules: {
'vue/component-tags-order': [
'error',
{ order: ['docs', 'template', 'script', 'style'] }
],
'vue/require-default-prop': 'off',
'vue/multi-word-component-names': 'off',
'vue/component-name-in-template-casing': [
'error',
'PascalCase',
{ registeredComponentsOnly: false }
],
'vuejs-accessibility/label-has-for': [
'error',
{
required: {
some: ['nesting', 'id']
}
}
],
'vue/html-self-closing': 'off' // messes with prettier
}
},
{
files: ['**/*.d.ts'],
rules: {
'no-var': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/ban-types': 'off'
}
}
]).prepend([
{
ignores: [
'**/node_modules/**',
'**/templates/*',
'./lib/common/generated/**/*',
'storybook-static',
'.nuxt/**',
'.output/**'
]
},
...baseConfigs
])
export default configs
@@ -1,3 +0,0 @@
<template>
<slot />
</template>
@@ -1,3 +0,0 @@
<template>
<slot />
</template>
@@ -179,7 +179,7 @@ export const useAuthManager = () => {
* Check for 'emailverifiedstatus' in query string and report it to user * Check for 'emailverifiedstatus' in query string and report it to user
*/ */
const watchEmailVerificationStatus = () => { const watchEmailVerificationStatus = () => {
if (process.server) return if (import.meta.server) return
watch( watch(
() => () =>
@@ -222,7 +222,7 @@ export const useAuthManager = () => {
* (either used just logged in or registered) * (either used just logged in or registered)
*/ */
const watchLoginAccessCode = () => { const watchLoginAccessCode = () => {
if (process.server) return if (import.meta.server) return
watch( watch(
() => route.query['access_code'] as Optional<string>, () => route.query['access_code'] as Optional<string>,
@@ -123,7 +123,7 @@ export function useProcessOnboarding() {
const finishOnboarding = async (state: OnboardingState, goToDashboard = true) => { const finishOnboarding = async (state: OnboardingState, goToDashboard = true) => {
const user = activeUser.value const user = activeUser.value
if (process.server) if (import.meta.server)
throw new UnsupportedEnvironmentError("Can't process onboarding during SSR") throw new UnsupportedEnvironmentError("Can't process onboarding during SSR")
if (!distinctId.value || !user) if (!distinctId.value || !user)
@@ -34,7 +34,7 @@ export const usePostAuthRedirect = (
deleteState() deleteState()
if (process.server) { if (import.meta.server) {
const url = new URL(pathWithQuery, 'http://notimportant.com') const url = new URL(pathWithQuery, 'http://notimportant.com')
router router
.push({ .push({
@@ -5,7 +5,7 @@ import DOMPurify from 'dompurify'
const purify = async (source: string) => { const purify = async (source: string) => {
let purify: DOMPurify.DOMPurifyI let purify: DOMPurify.DOMPurifyI
if (process.server) { if (import.meta.server) {
const jsdom = await import('jsdom') const jsdom = await import('jsdom')
const window = new jsdom.JSDOM('').window const window = new jsdom.JSDOM('').window
purify = DOMPurify(window) purify = DOMPurify(window)
@@ -31,7 +31,7 @@ export const useSynchronizedCookie = <CookieValue = string>(
const cookie = useCookie<CookieValue>(name, finalOpts as any) const cookie = useCookie<CookieValue>(name, finalOpts as any)
// Hack to resolve Safari & Brave limiting client-side cookies to 7 days - set temporary cookie to be read from server-side where it'll be fixed // Hack to resolve Safari & Brave limiting client-side cookies to 7 days - set temporary cookie to be read from server-side where it'll be fixed
if (process.client && isBraveOrSafari()) { if (import.meta.client && isBraveOrSafari()) {
const tmpCookie = useCookie(`tmp-${name}`, finalOpts as any) const tmpCookie = useCookie(`tmp-${name}`, finalOpts as any)
watch(cookie, (newVal) => { watch(cookie, (newVal) => {
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import type { NuxtApp } from 'nuxt/dist/app/nuxt' import type { NuxtApp } from 'nuxt/dist/app/nuxt'
/** /**
@@ -5,7 +5,7 @@ import {
serverInfoBlobSizeLimitQuery serverInfoBlobSizeLimitQuery
} from '~~/lib/common/graphql/queries' } from '~~/lib/common/graphql/queries'
import { prettyFileSize } from '~~/lib/core/helpers/file' import { prettyFileSize } from '~~/lib/core/helpers/file'
import { AllScopes } from '@speckle/shared' import type { AllScopes } from '@speckle/shared'
export function useServerFileUploadLimit() { export function useServerFileUploadLimit() {
const { result } = useQuery(serverInfoBlobSizeLimitQuery) const { result } = useQuery(serverInfoBlobSizeLimitQuery)
@@ -1,3 +1,5 @@
import { useStorage } from '@vueuse/core'
import { isString, uniq } from 'lodash-es'
export { export {
ThrottleOrDebounce, ThrottleOrDebounce,
HorizontalDirection, HorizontalDirection,
@@ -5,13 +7,11 @@ export {
useOnBeforeWindowUnload, useOnBeforeWindowUnload,
useResponsiveHorizontalDirectionCalculation useResponsiveHorizontalDirectionCalculation
} from '@speckle/ui-components' } from '@speckle/ui-components'
import { useStorage } from '@vueuse/core'
import { isString, uniq } from 'lodash-es'
export function useDisableGlobalTextSelection() { export function useDisableGlobalTextSelection() {
const disableTextSelection = ref(false) const disableTextSelection = ref(false)
if (process.client) { if (import.meta.client) {
watch(disableTextSelection, (newVal, oldVal) => { watch(disableTextSelection, (newVal, oldVal) => {
if (!!newVal === !!oldVal) return if (!!newVal === !!oldVal) return
@@ -32,12 +32,12 @@ export function useItemsExpandedState(params: { stateName: string }) {
}) })
const fakeState = ref(initializer()) const fakeState = ref(initializer())
const storageState = process.server const storageState = import.meta.server
? fakeState ? fakeState
: useStorage('useItemsExpandedState-' + params.stateName, initializer) : useStorage('useItemsExpandedState-' + params.stateName, initializer)
const hasMounted = ref(false) const hasMounted = ref(false)
const useRealState = computed(() => process.client && hasMounted.value) const useRealState = computed(() => import.meta.client && hasMounted.value)
const state = computed({ const state = computed({
get: () => { get: () => {
@@ -2,7 +2,7 @@ import { md5 } from '@speckle/shared'
export { md5 } export { md5 }
export const base64Encode = (str: string): string => { export const base64Encode = (str: string): string => {
if (process.server) { if (import.meta.server) {
return Buffer.from(str).toString('base64') return Buffer.from(str).toString('base64')
} else { } else {
return btoa(str) return btoa(str)
@@ -10,7 +10,7 @@ export const base64Encode = (str: string): string => {
} }
export const base64Decode = (str: string): string => { export const base64Decode = (str: string): string => {
if (process.server) { if (import.meta.server) {
return Buffer.from(str, 'base64').toString('utf8') return Buffer.from(str, 'base64').toString('utf8')
} else { } else {
return atob(str) return atob(str)
@@ -1,15 +1,15 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { isUndefinedOrVoid } from '@speckle/shared' import { isUndefinedOrVoid } from '@speckle/shared'
import type { Optional } from '@speckle/shared' import type { Optional } from '@speckle/shared'
import { ApolloError, ApolloCache, defaultDataIdFromObject } from '@apollo/client/core' import { ApolloError, defaultDataIdFromObject } from '@apollo/client/core'
import type { import type {
FetchResult, FetchResult,
DataProxy, DataProxy,
TypedDocumentNode, TypedDocumentNode,
ServerError, ServerError,
ServerParseError ServerParseError,
ApolloCache
} from '@apollo/client/core' } from '@apollo/client/core'
import { GraphQLError } from 'graphql' import { GraphQLError } from 'graphql'
import type { DocumentNode } from 'graphql' import type { DocumentNode } from 'graphql'
@@ -101,7 +101,6 @@ export function convertThrowIntoFetchResult(
} else if (err instanceof Error) { } else if (err instanceof Error) {
gqlErrors = [new GraphQLError(err.message)] gqlErrors = [new GraphQLError(err.message)]
} else { } else {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
gqlErrors = [new GraphQLError(`${err}`)] gqlErrors = [new GraphQLError(`${err}`)]
} }
@@ -141,7 +140,7 @@ export function updateCacheByFilter<TData, TVariables = unknown>(
* mutate anything being passed into this function! E.g. if you want to mutate arrays, * mutate anything being passed into this function! E.g. if you want to mutate arrays,
* create new arrays through slice()/filter() instead * create new arrays through slice()/filter() instead
*/ */
updater: (data: TData) => TData | undefined | void, updater: (data: TData) => TData | undefined,
options: Partial<{ options: Partial<{
/** /**
* Whether to suppress errors that occur when the fragment being queried * Whether to suppress errors that occur when the fragment being queried
@@ -329,7 +328,6 @@ export function modifyObjectFields<
} }
) => ) =>
| Optional<ModifyFnCacheData<D>> | Optional<ModifyFnCacheData<D>>
| void
| Parameters<Modifier<ModifyFnCacheData<D>>>[1]['DELETE'] | Parameters<Modifier<ModifyFnCacheData<D>>>[1]['DELETE']
| Parameters<Modifier<ModifyFnCacheData<D>>>[1]['INVALIDATE'], | Parameters<Modifier<ModifyFnCacheData<D>>>[1]['INVALIDATE'],
options?: Partial<{ options?: Partial<{
@@ -337,7 +335,7 @@ export function modifyObjectFields<
debug: boolean debug: boolean
}> }>
) { ) {
const { fieldNameWhitelist, debug = !!(process.dev && process.client) } = const { fieldNameWhitelist, debug = !!(import.meta.dev && import.meta.client) } =
options || {} options || {}
const logger = useLogger() const logger = useLogger()
@@ -346,7 +344,6 @@ export function modifyObjectFields<
if (!debug) return if (!debug) return
const [message, ...rest] = args const [message, ...rest] = args
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
logger.debug(`[${invocationId}] ${message}`, ...rest) logger.debug(`[${invocationId}] ${message}`, ...rest)
} }
@@ -1,6 +1,6 @@
import type { LocationQueryRaw } from 'vue-router' import type { LocationQueryRaw } from 'vue-router'
import { deserializeHashState, serializeHashState } from '~~/lib/common/composables/url' import { deserializeHashState, serializeHashState } from '~~/lib/common/composables/url'
import { ViewerHashStateKeys } from '~~/lib/viewer/composables/setup/urlHashState' import type { ViewerHashStateKeys } from '~~/lib/viewer/composables/setup/urlHashState'
export const profileRoute = '/profile' export const profileRoute = '/profile'
export const authBlockedDueToVerificationRoute = '/error-email-verify' export const authBlockedDueToVerificationRoute = '/error-email-verify'
@@ -11,6 +11,7 @@ import { TailwindBreakpoints } from '@speckle/ui-components'
export function markClassesUsed(classes: string[]) { export function markClassesUsed(classes: string[]) {
// this doesn't do anything, we just need PurgeCSS to be able to read // this doesn't do anything, we just need PurgeCSS to be able to read
// invocations of this function // invocations of this function
// eslint-disable-next-line no-constant-binary-expression
false && classes false && classes
} }
@@ -9,8 +9,8 @@ import Link from '@tiptap/extension-link'
import HardBreak from '@tiptap/extension-hard-break' import HardBreak from '@tiptap/extension-hard-break'
import History from '@tiptap/extension-history' import History from '@tiptap/extension-history'
import Placeholder from '@tiptap/extension-placeholder' import Placeholder from '@tiptap/extension-placeholder'
import { Node, Extension, Editor } from '@tiptap/core' import { Node, Extension } from '@tiptap/core'
import type { CommandProps } from '@tiptap/core' import type { CommandProps, Editor } from '@tiptap/core'
import { TextSelection } from '@tiptap/pm/state' import { TextSelection } from '@tiptap/pm/state'
import { VALID_HTTP_URL } from '~~/lib/common/helpers/validation' import { VALID_HTTP_URL } from '~~/lib/common/helpers/validation'
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { ValidationHelpers } from '@speckle/ui-components' import { ValidationHelpers } from '@speckle/ui-components'
import { useForm } from 'vee-validate' import type { useForm } from 'vee-validate'
export const VALID_HTTP_URL = ValidationHelpers.VALID_HTTP_URL export const VALID_HTTP_URL = ValidationHelpers.VALID_HTTP_URL
export const VALID_EMAIL = ValidationHelpers.VALID_EMAIL export const VALID_EMAIL = ValidationHelpers.VALID_EMAIL

Some files were not shown because too many files have changed in this diff Show More