From e42c90fa21f765174dc44a52ee78f73a95a221ac Mon Sep 17 00:00:00 2001 From: Oleg Vavilov Date: Thu, 29 May 2025 00:42:46 +0300 Subject: [PATCH] [Feature]: Update git hooks and package json #2705 --- .pre-commit-config.yaml | 18 +++++++ frontend/.eslintignore | 2 + frontend/package.json | 2 +- .../FileUploader/FileEntry/index.tsx | 1 + .../layouts/AppLayout/TutorialPanel/hooks.ts | 7 ++- frontend/src/libs/fetchBaseQueryHeaders.ts | 5 -- frontend/src/libs/serverErrors.ts | 1 + frontend/src/pages/Runs/Details/index.tsx | 54 ++++++++++--------- frontend/src/pages/Runs/List/index.tsx | 23 +++++--- .../src/pages/User/Details/Billing/index.tsx | 33 ++++++------ frontend/src/pages/User/Details/index.tsx | 8 +-- frontend/src/pages/Volumes/List/hooks.tsx | 4 +- frontend/src/services/run.ts | 1 - frontend/webpack/env.js | 16 +++--- frontend/webpack/prod.js | 15 +++--- 15 files changed, 111 insertions(+), 79 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d9e8408e2..6ba9d9b41 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,3 +17,21 @@ repos: rev: v5.0.0 hooks: - id: end-of-file-fixer + + - repo: https://github.com/pre-commit/mirrors-eslint + rev: '' + hooks: + - id: eslint + name: ESLint + entry: eslint --fix --config frontend/.eslintrc --ignore-path frontend/.eslintignore + language: node + pass_filenames: false + cwd: "frontend/" + additional_dependencies: + - eslint@8.31.0 + - eslint-config-prettier@8.10.0 + - eslint-plugin-i18n@2.4.0 + - eslint-plugin-prettier@4.2.1 + - eslint-plugin-simple-import-sort@10.0.0 + - '@typescript-eslint/eslint-plugin@5.48.1' + - '@typescript-eslint/parser@5.48.1' diff --git a/frontend/.eslintignore b/frontend/.eslintignore index 340234e91..9016074a0 100644 --- a/frontend/.eslintignore +++ b/frontend/.eslintignore @@ -5,6 +5,8 @@ src/locale src/types src/setupProxy.js webpack/** +webpack/env.js +webpack/prod.js public staticServer.js webpack.config.js diff --git a/frontend/package.json b/frontend/package.json index 898ebab50..3191ba54c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -4,7 +4,7 @@ "main": "src/index.ts", "repository": "git@gitlab.com:dstackai/dstackai-website.git", "author": "Oleg Vavilov", - "license": "MIT", + "license": "Apache 2.0", "private": true, "scripts": { "start": "cross-env NODE_ENV=development webpack serve --config webpack.config.js", diff --git a/frontend/src/components/FileUploader/FileEntry/index.tsx b/frontend/src/components/FileUploader/FileEntry/index.tsx index 677b9ef88..bf002f358 100644 --- a/frontend/src/components/FileUploader/FileEntry/index.tsx +++ b/frontend/src/components/FileUploader/FileEntry/index.tsx @@ -22,6 +22,7 @@ export const FileEntry: React.FC = ({ file, showImage = false, truncateL }; reader.readAsDataURL(file); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const ext = file.name.split('.').pop()!; const displayFileName = file.name.length - ext.length - 1 > truncateLength ? `${file.name.slice(0, truncateLength)}... .${ext}` : file.name; diff --git a/frontend/src/layouts/AppLayout/TutorialPanel/hooks.ts b/frontend/src/layouts/AppLayout/TutorialPanel/hooks.ts index 9531fe684..2cdf5e5eb 100644 --- a/frontend/src/layouts/AppLayout/TutorialPanel/hooks.ts +++ b/frontend/src/layouts/AppLayout/TutorialPanel/hooks.ts @@ -1,7 +1,11 @@ import { useCallback, useEffect, useMemo, useRef } from 'react'; import { useNavigate } from 'react-router-dom'; -import { DISCORD_URL, QUICK_START_URL, TALLY_FORM_ID } from 'consts'; +import { + DISCORD_URL, + QUICK_START_URL, + // TALLY_FORM_ID +} from 'consts'; import { useAppDispatch, useAppSelector } from 'hooks'; import { goToUrl } from 'libs'; import { useGetRunsQuery } from 'services/run'; @@ -60,6 +64,7 @@ export const useTutorials = () => { dispatch(updateTutorialPanelState({ billingCompleted: true })); }, []); + // eslint-disable-next-line @typescript-eslint/no-empty-function const startConfigCliTutorial = useCallback(() => {}, [billingUrl]); const finishConfigCliTutorial = useCallback(() => { diff --git a/frontend/src/libs/fetchBaseQueryHeaders.ts b/frontend/src/libs/fetchBaseQueryHeaders.ts index e5fc269b5..d51735820 100644 --- a/frontend/src/libs/fetchBaseQueryHeaders.ts +++ b/frontend/src/libs/fetchBaseQueryHeaders.ts @@ -15,9 +15,4 @@ function baseQueryHeaders(headers: Headers, { getState }: Pick): Headers { - headers.set('X-API-VERSION', 'latest'); - return headers; -} - export default baseQueryHeaders; diff --git a/frontend/src/libs/serverErrors.ts b/frontend/src/libs/serverErrors.ts index 90e9d0c9b..ce2f6f0d6 100644 --- a/frontend/src/libs/serverErrors.ts +++ b/frontend/src/libs/serverErrors.ts @@ -36,6 +36,7 @@ export function isResponseServerError(formErrors: unknown): formErrors is Respon ); } +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function getServerError(error: any): string { let errorText = error?.error; diff --git a/frontend/src/pages/Runs/Details/index.tsx b/frontend/src/pages/Runs/Details/index.tsx index ca31b4608..0536b9eae 100644 --- a/frontend/src/pages/Runs/Details/index.tsx +++ b/frontend/src/pages/Runs/Details/index.tsx @@ -1,6 +1,6 @@ import React, { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; -import { Outlet, useNavigate, useParams } from 'react-router-dom'; +import { Outlet, /*useNavigate,*/ useParams } from 'react-router-dom'; import Button from '@cloudscape-design/components/button'; import { ContentLayout, DetailsHeader, Tabs } from 'components'; @@ -10,7 +10,11 @@ import { getServerError, riseRouterException } from 'libs'; import { ROUTES } from 'routes'; import { useDeleteRunsMutation, useGetRunQuery, useStopRunsMutation } from 'services/run'; -import { isAvailableAbortingForRun, isAvailableDeletingForRun, isAvailableStoppingForRun } from '../utils'; +import { + isAvailableAbortingForRun, + isAvailableStoppingForRun, + // isAvailableDeletingForRun, +} from '../utils'; import styles from './styles.module.scss'; @@ -21,7 +25,7 @@ enum CodeTab { export const RunDetailsPage: React.FC = () => { const { t } = useTranslation(); - const navigate = useNavigate(); + // const navigate = useNavigate(); const params = useParams(); const paramProjectName = params.projectName ?? ''; const paramRunId = params.runId ?? ''; @@ -41,7 +45,7 @@ export const RunDetailsPage: React.FC = () => { }, [runError]); const [stopRun, { isLoading: isStopping }] = useStopRunsMutation(); - const [deleteRun, { isLoading: isDeleting }] = useDeleteRunsMutation(); + const [, /* deleteRun ,*/ { isLoading: isDeleting }] = useDeleteRunsMutation(); useBreadcrumbs([ { @@ -100,30 +104,30 @@ export const RunDetailsPage: React.FC = () => { }); }; - const deleteClickHandle = () => { - if (!runData) { - return; - } - - deleteRun({ - project_name: paramProjectName, - runs_names: [runData.run_spec.run_name], - }) - .unwrap() - .then(() => { - navigate(ROUTES.RUNS.LIST); - }) - .catch((error) => { - pushNotification({ - type: 'error', - content: t('common.server_error', { error: getServerError(error) }), - }); - }); - }; + // const deleteClickHandle = () => { + // if (!runData) { + // return; + // } + // + // deleteRun({ + // project_name: paramProjectName, + // runs_names: [runData.run_spec.run_name], + // }) + // .unwrap() + // .then(() => { + // navigate(ROUTES.RUNS.LIST); + // }) + // .catch((error) => { + // pushNotification({ + // type: 'error', + // content: t('common.server_error', { error: getServerError(error) }), + // }); + // }); + // }; const isDisabledAbortButton = !runData || !isAvailableAbortingForRun(runData.status) || isStopping || isDeleting; const isDisabledStopButton = !runData || !isAvailableStoppingForRun(runData.status) || isStopping || isDeleting; - const isDisabledDeleteButton = !runData || !isAvailableDeletingForRun(runData.status) || isStopping || isDeleting; + // const isDisabledDeleteButton = !runData || !isAvailableDeletingForRun(runData.status) || isStopping || isDeleting; return (
diff --git a/frontend/src/pages/Runs/List/index.tsx b/frontend/src/pages/Runs/List/index.tsx index 315b43944..7e913714c 100644 --- a/frontend/src/pages/Runs/List/index.tsx +++ b/frontend/src/pages/Runs/List/index.tsx @@ -25,7 +25,7 @@ import styles from './styles.module.scss'; export const RunList: React.FC = () => { const { t } = useTranslation(); - const [searchParams, setSearchParams] = useSearchParams(); + const [, setSearchParams] = useSearchParams(); const [preferences] = useRunListPreferences(); useBreadcrumbs([ @@ -50,7 +50,10 @@ export const RunList: React.FC = () => { const { stopRuns, isStopping } = useStopRuns(); const { abortRuns, isAborting } = useAbortRuns(); - const { deleteRuns, isDeleting } = useDeleteRuns(); + const { + // deleteRuns, + isDeleting, + } = useDeleteRuns(); const { columns } = useColumnsDefinitions(); @@ -75,7 +78,11 @@ export const RunList: React.FC = () => { const { selectedItems } = collectionProps; - const { isDisabledAbortButton, isDisabledStopButton, isDisabledDeleteButton } = useDisabledStatesForButtons({ + const { + isDisabledAbortButton, + isDisabledStopButton, + // isDisabledDeleteButton + } = useDisabledStatesForButtons({ selectedRuns: selectedItems, isStopping, isAborting, @@ -94,11 +101,11 @@ export const RunList: React.FC = () => { stopRuns([...selectedItems]).then(() => actions.setSelectedItems([])); }; - const deleteClickHandle = () => { - if (!selectedItems?.length) return; - - deleteRuns([...selectedItems]).catch(console.log); - }; + // const deleteClickHandle = () => { + // if (!selectedItems?.length) return; + // + // deleteRuns([...selectedItems]).catch(console.log); + // }; return ( { const { data, isLoading } = useGetUserBillingInfoQuery({ username: paramUserName }); const [billingCheckout, { isLoading: isLoadingBillingCheckout }] = useUserBillingCheckoutSessionMutation(); - const [billingPortalSession, { isLoading: isLoadingBillingPortalSession }] = useUserBillingPortalSessionMutation(); + // const [billingPortalSession, { isLoading: isLoadingBillingPortalSession }] = useUserBillingPortalSessionMutation(); useBreadcrumbs([ { @@ -81,20 +81,21 @@ export const Billing: React.FC = () => { setShowPaymentModal(true); }; - const editPaymentMethod = () => { - billingPortalSession({ - username: paramUserName, - }) - .unwrap() - .then((data) => goToUrl(data.url)) - .catch((error) => { - pushNotification({ - type: 'error', - content: t('common.server_error', { error: getServerError(error) }), - }); - }) - .finally(closeModal); - }; + // const editPaymentMethod = () => { + // billingPortalSession({ + // username: paramUserName, + // }) + // .unwrap() + // .then((data) => goToUrl(data.url)) + // .catch((error) => { + // pushNotification({ + // type: 'error', + // content: t('common.server_error', { error: getServerError(error) }), + // }); + // }) + // .finally(closeModal); + // }; + const closeModal = () => { setShowPaymentModal(false); }; diff --git a/frontend/src/pages/User/Details/index.tsx b/frontend/src/pages/User/Details/index.tsx index 4d63f18f3..9a586a1dc 100644 --- a/frontend/src/pages/User/Details/index.tsx +++ b/frontend/src/pages/User/Details/index.tsx @@ -5,12 +5,12 @@ import { Outlet, useNavigate, useParams } from 'react-router-dom'; import { ConfirmationDialog, ContentLayout, SpaceBetween, Tabs } from 'components'; import { DetailsHeader } from 'components'; -import { useNotifications, usePermissionGuard } from 'hooks'; +import { useNotifications /* usePermissionGuard*/ } from 'hooks'; import { getServerError, riseRouterException } from 'libs'; import { ROUTES } from 'routes'; import { useDeleteUsersMutation, useGetUserQuery } from 'services/user'; -import { GlobalUserRole } from '../../../types'; +// import { GlobalUserRole } from '../../../types'; import { UserDetailsTabTypeEnum } from './types'; export { Settings as UserSettings } from './Settings'; @@ -24,9 +24,9 @@ export const UserDetails: React.FC = () => { const paramUserName = params.userName ?? ''; const navigate = useNavigate(); const { error: userError } = useGetUserQuery({ name: paramUserName }); - const [deleteUsers, { isLoading: isDeleting }] = useDeleteUsersMutation(); + const [deleteUsers /*, { isLoading: isDeleting }*/] = useDeleteUsersMutation(); const [pushNotification] = useNotifications(); - const [isAvailableDeleteUser] = usePermissionGuard({ allowedGlobalRoles: [GlobalUserRole.ADMIN] }); + // const [isAvailableDeleteUser] = usePermissionGuard({ allowedGlobalRoles: [GlobalUserRole.ADMIN] }); useEffect(() => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/frontend/src/pages/Volumes/List/hooks.tsx b/frontend/src/pages/Volumes/List/hooks.tsx index e6989ca56..372da3b7e 100644 --- a/frontend/src/pages/Volumes/List/hooks.tsx +++ b/frontend/src/pages/Volumes/List/hooks.tsx @@ -184,9 +184,9 @@ const getVolumeFinised = (volume: IVolume): string => { if (!volume.deleted_at && volume.status != 'failed') { return '-'; } - let finished = volume.last_processed_at + let finished = volume.last_processed_at; if (volume.deleted_at) { - finished = volume.deleted_at + finished = volume.deleted_at; } return format(new Date(finished), DATE_TIME_FORMAT); }; diff --git a/frontend/src/services/run.ts b/frontend/src/services/run.ts index 75969d937..0e8818597 100644 --- a/frontend/src/services/run.ts +++ b/frontend/src/services/run.ts @@ -1,6 +1,5 @@ import { sortBy as _sortBy } from 'lodash'; import { API } from 'api'; -import { BaseQueryMeta, BaseQueryResult } from '@reduxjs/toolkit/dist/query/baseQueryTypes'; import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; import fetchBaseQueryHeaders from 'libs/fetchBaseQueryHeaders'; diff --git a/frontend/webpack/env.js b/frontend/webpack/env.js index 905b546e4..6b6e854d4 100644 --- a/frontend/webpack/env.js +++ b/frontend/webpack/env.js @@ -1,8 +1,8 @@ -const {join} = require('path'); +const { join } = require('path'); -const apiURLs = '/api' +const apiURLs = '/api'; -const publicURLs = '/' +const publicURLs = '/'; const environment = process.env.NODE_ENV || 'production'; const isProd = environment === 'production'; @@ -17,10 +17,10 @@ const apiUrl = process.env.API_URL || apiURLs; const publicUrl = process.env.PUBLIC_URL || publicURLs; const uiVersion = process.env.UI_VERSION === 'sky' ? 'sky' : 'enterprise'; - -const title = uiVersion === 'enterprise' ? "dstack" : "dstack Sky"; -const description = "Get GPUs at the best prices and availability from a wide range of providers. No cloud " + - "account of your own is required.\n"; +const title = uiVersion === 'enterprise' ? 'dstack' : 'dstack Sky'; +const description = + 'Get GPUs at the best prices and availability from a wide range of providers. No cloud ' + + 'account of your own is required.\n'; module.exports = { environment, @@ -37,4 +37,4 @@ module.exports = { title, description, uiVersion, -} +}; diff --git a/frontend/webpack/prod.js b/frontend/webpack/prod.js index 496eb24fb..d970a0cf7 100644 --- a/frontend/webpack/prod.js +++ b/frontend/webpack/prod.js @@ -1,27 +1,26 @@ // production config -const {join} = require('path'); -const {buildDir, publicPath, srcDir} = require('./env'); +const { join } = require('path'); +const { buildDir, publicPath, srcDir } = require('./env'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); - module.exports = { - mode: "production", + mode: 'production', entry: join(srcDir, 'index.tsx'), output: { path: buildDir, - filename: "[name]-[contenthash].js", + filename: '[name]-[contenthash].js', publicPath: publicPath, clean: true, }, - devtool: "source-map", + devtool: 'source-map', plugins: [ new MiniCssExtractPlugin({ - filename: "[name]-[contenthash].css", + filename: '[name]-[contenthash].css', }), ], optimization: { minimize: true, - minimizer: [new CssMinimizerPlugin()] + minimizer: [new CssMinimizerPlugin()], }, };