Compare commits

...

1 Commits

Author SHA1 Message Date
Vinícius Lourenço
6720449610 feat(vite): migrate away from webpack 2026-02-20 16:37:00 -03:00
47 changed files with 4496 additions and 5237 deletions

View File

@@ -58,19 +58,19 @@ jobs:
run: |
mkdir -p frontend
echo 'CI=1' > frontend/.env
echo 'INTERCOM_APP_ID="${{ secrets.INTERCOM_APP_ID }}"' >> frontend/.env
echo 'SEGMENT_ID="${{ secrets.SEGMENT_ID }}"' >> frontend/.env
echo 'SENTRY_AUTH_TOKEN="${{ secrets.SENTRY_AUTH_TOKEN }}"' >> frontend/.env
echo 'SENTRY_ORG="${{ secrets.SENTRY_ORG }}"' >> frontend/.env
echo 'SENTRY_PROJECT_ID="${{ secrets.SENTRY_PROJECT_ID }}"' >> frontend/.env
echo 'SENTRY_DSN="${{ secrets.SENTRY_DSN }}"' >> frontend/.env
echo 'TUNNEL_URL="${{ secrets.TUNNEL_URL }}"' >> frontend/.env
echo 'TUNNEL_DOMAIN="${{ secrets.TUNNEL_DOMAIN }}"' >> frontend/.env
echo 'POSTHOG_KEY="${{ secrets.POSTHOG_KEY }}"' >> frontend/.env
echo 'PYLON_APP_ID="${{ secrets.PYLON_APP_ID }}"' >> frontend/.env
echo 'APPCUES_APP_ID="${{ secrets.APPCUES_APP_ID }}"' >> frontend/.env
echo 'PYLON_IDENTITY_SECRET="${{ secrets.PYLON_IDENTITY_SECRET }}"' >> frontend/.env
echo 'DOCS_BASE_URL="https://signoz.io"' >> frontend/.env
echo 'VITE_INTERCOM_APP_ID="${{ secrets.INTERCOM_APP_ID }}"' >> frontend/.env
echo 'VITE_SEGMENT_ID="${{ secrets.SEGMENT_ID }}"' >> frontend/.env
echo 'VITE_SENTRY_AUTH_TOKEN="${{ secrets.SENTRY_AUTH_TOKEN }}"' >> frontend/.env
echo 'VITE_SENTRY_ORG="${{ secrets.SENTRY_ORG }}"' >> frontend/.env
echo 'VITE_SENTRY_PROJECT_ID="${{ secrets.SENTRY_PROJECT_ID }}"' >> frontend/.env
echo 'VITE_SENTRY_DSN="${{ secrets.SENTRY_DSN }}"' >> frontend/.env
echo 'VITE_TUNNEL_URL="${{ secrets.TUNNEL_URL }}"' >> frontend/.env
echo 'VITE_TUNNEL_DOMAIN="${{ secrets.TUNNEL_DOMAIN }}"' >> frontend/.env
echo 'VITE_POSTHOG_KEY="${{ secrets.POSTHOG_KEY }}"' >> frontend/.env
echo 'VITE_PYLON_APP_ID="${{ secrets.PYLON_APP_ID }}"' >> frontend/.env
echo 'VITE_APPCUES_APP_ID="${{ secrets.APPCUES_APP_ID }}"' >> frontend/.env
echo 'VITE_PYLON_IDENTITY_SECRET="${{ secrets.PYLON_IDENTITY_SECRET }}"' >> frontend/.env
echo 'VITE_DOCS_BASE_URL="https://signoz.io"' >> frontend/.env
- name: cache-dotenv
uses: actions/cache@v4
with:

View File

@@ -64,12 +64,12 @@ jobs:
run: |
mkdir -p frontend
echo 'CI=1' > frontend/.env
echo 'TUNNEL_URL="${{ secrets.NP_TUNNEL_URL }}"' >> frontend/.env
echo 'TUNNEL_DOMAIN="${{ secrets.NP_TUNNEL_DOMAIN }}"' >> frontend/.env
echo 'PYLON_APP_ID="${{ secrets.NP_PYLON_APP_ID }}"' >> frontend/.env
echo 'APPCUES_APP_ID="${{ secrets.NP_APPCUES_APP_ID }}"' >> frontend/.env
echo 'PYLON_IDENTITY_SECRET="${{ secrets.NP_PYLON_IDENTITY_SECRET }}"' >> frontend/.env
echo 'DOCS_BASE_URL="https://staging.signoz.io"' >> frontend/.env
echo 'VITE_TUNNEL_URL="${{ secrets.NP_TUNNEL_URL }}"' >> frontend/.env
echo 'VITE_TUNNEL_DOMAIN="${{ secrets.NP_TUNNEL_DOMAIN }}"' >> frontend/.env
echo 'VITE_PYLON_APP_ID="${{ secrets.NP_PYLON_APP_ID }}"' >> frontend/.env
echo 'VITE_APPCUES_APP_ID="${{ secrets.NP_APPCUES_APP_ID }}"' >> frontend/.env
echo 'VITE_PYLON_IDENTITY_SECRET="${{ secrets.NP_PYLON_IDENTITY_SECRET }}"' >> frontend/.env
echo 'VITE_DOCS_BASE_URL="https://staging.signoz.io"' >> frontend/.env
- name: cache-dotenv
uses: actions/cache@v4
with:

View File

@@ -24,19 +24,19 @@ jobs:
- name: dotenv-frontend
working-directory: frontend
run: |
echo 'INTERCOM_APP_ID="${{ secrets.INTERCOM_APP_ID }}"' > .env
echo 'SEGMENT_ID="${{ secrets.SEGMENT_ID }}"' >> .env
echo 'SENTRY_AUTH_TOKEN="${{ secrets.SENTRY_AUTH_TOKEN }}"' >> .env
echo 'SENTRY_ORG="${{ secrets.SENTRY_ORG }}"' >> .env
echo 'SENTRY_PROJECT_ID="${{ secrets.SENTRY_PROJECT_ID }}"' >> .env
echo 'SENTRY_DSN="${{ secrets.SENTRY_DSN }}"' >> .env
echo 'TUNNEL_URL="${{ secrets.TUNNEL_URL }}"' >> .env
echo 'TUNNEL_DOMAIN="${{ secrets.TUNNEL_DOMAIN }}"' >> .env
echo 'POSTHOG_KEY="${{ secrets.POSTHOG_KEY }}"' >> .env
echo 'PYLON_APP_ID="${{ secrets.PYLON_APP_ID }}"' >> .env
echo 'APPCUES_APP_ID="${{ secrets.APPCUES_APP_ID }}"' >> .env
echo 'PYLON_IDENTITY_SECRET="${{ secrets.PYLON_IDENTITY_SECRET }}"' >> .env
echo 'DOCS_BASE_URL="https://signoz.io"' >> .env
echo 'VITE_INTERCOM_APP_ID="${{ secrets.INTERCOM_APP_ID }}"' > .env
echo 'VITE_SEGMENT_ID="${{ secrets.SEGMENT_ID }}"' >> .env
echo 'VITE_SENTRY_AUTH_TOKEN="${{ secrets.SENTRY_AUTH_TOKEN }}"' >> .env
echo 'VITE_SENTRY_ORG="${{ secrets.SENTRY_ORG }}"' >> .env
echo 'VITE_SENTRY_PROJECT_ID="${{ secrets.SENTRY_PROJECT_ID }}"' >> .env
echo 'VITE_SENTRY_DSN="${{ secrets.SENTRY_DSN }}"' >> .env
echo 'VITE_TUNNEL_URL="${{ secrets.TUNNEL_URL }}"' >> .env
echo 'VITE_TUNNEL_DOMAIN="${{ secrets.TUNNEL_DOMAIN }}"' >> .env
echo 'VITE_POSTHOG_KEY="${{ secrets.POSTHOG_KEY }}"' >> .env
echo 'VITE_PYLON_APP_ID="${{ secrets.PYLON_APP_ID }}"' >> .env
echo 'VITE_APPCUES_APP_ID="${{ secrets.APPCUES_APP_ID }}"' >> .env
echo 'VITE_PYLON_IDENTITY_SECRET="${{ secrets.PYLON_IDENTITY_SECRET }}"' >> .env
echo 'VITE_DOCS_BASE_URL="https://signoz.io"' >> .env
- name: node-setup
uses: actions/setup-node@v5
with:

View File

@@ -238,4 +238,4 @@ py-clean: ## Clear all pycache and pytest cache from tests directory recursively
.PHONY: gen-mocks
gen-mocks:
@echo ">> Generating mocks"
@mockery --config .mockery.yml
@mockery --config .mockery.yml

View File

@@ -1,16 +0,0 @@
{
"presets": [
"@babel/preset-env",
["@babel/preset-react", { "runtime": "automatic" }],
"@babel/preset-typescript"
],
"plugins": [
"react-hot-loader/babel",
"@babel/plugin-proposal-class-properties"
],
"env": {
"production": {
"presets": ["minify"]
}
}
}

View File

@@ -7,7 +7,6 @@ module.exports = {
browser: true,
es2021: true,
node: true,
'jest/globals': true,
},
extends: [
'eslint:recommended',
@@ -33,7 +32,7 @@ module.exports = {
'simple-import-sort', // Auto-sort imports
'react-hooks', // React Hooks rules
'prettier', // Code formatting
'jest', // Jest test rules
// 'jest', // Disabled due to old version of eslint
'jsx-a11y', // Accessibility rules
'import', // Import/export linting
'sonarjs', // Code quality/complexity

View File

@@ -0,0 +1,4 @@
export const ENVIRONMENT = {
baseURL: process.env.VITE_FRONTEND_API_ENDPOINT || '',
wsURL: process.env.VITE_WEBSOCKET_API_ENDPOINT || '',
};

19
frontend/babel.config.cjs Normal file
View File

@@ -0,0 +1,19 @@
module.exports = {
presets: [
['@babel/preset-env', { modules: 'auto' }],
['@babel/preset-react', { runtime: 'automatic' }],
['@babel/preset-typescript'],
],
plugins: [
'@babel/plugin-proposal-class-properties',
],
env: {
test: {
presets: [
['@babel/preset-env', { modules: 'commonjs', targets: { node: 'current' } }],
['@babel/preset-react', { runtime: 'automatic' }],
['@babel/preset-typescript'],
],
},
},
};

View File

@@ -1,6 +0,0 @@
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
],
};

View File

@@ -1,8 +0,0 @@
{
"files": [
{
"path": "./build/**.js",
"maxSize": "1.2MB"
}
]
}

View File

@@ -1,8 +1,8 @@
NODE_ENV="development"
BUNDLE_ANALYSER="true"
FRONTEND_API_ENDPOINT="http://localhost:8080/"
PYLON_APP_ID="pylon-app-id"
APPCUES_APP_ID="appcess-app-id"
PYLON_IDENTITY_SECRET="pylon-identity-secret"
VITE_FRONTEND_API_ENDPOINT="http://localhost:8080/"
VITE_PYLON_APP_ID="pylon-app-id"
VITE_APPCUES_APP_ID="appcess-app-id"
VITE_PYLON_IDENTITY_SECRET="pylon-identity-secret"
CI="1"
CI="1"

View File

@@ -1,3 +1,4 @@
// oxlint-disable typescript/no-require-imports
const crypto = require('crypto');
const fs = require('fs');
const glob = require('glob');

View File

@@ -1,127 +1,119 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
http-equiv="Cache-Control"
content="no-cache, no-store, must-revalidate, max-age: 0"
/>
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<!-- Preconnect to CDNs -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="preconnect" href="https://cdn.vercel.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"
rel="stylesheet"
/>
<title data-react-helmet="true">
Open source Observability platform | SigNoz
</title>
<meta
data-react-helmet="true"
property="og:title"
content="Open source Observability platform | SigNoz"
/>
<meta
data-react-helmet="true"
name="description"
content="SigNoz is an open source observability platform to help you find issues in your deployed applications & solve them quickly. It provides a single pane of glass for metrics, traces and logs with deep filtering and aggregation to pin down specific issues very quickly."
/>
<meta
data-react-helmet="true"
property="og:description"
content="SigNoz is an open source observability platform to help you find issues in your deployed applications & solve them quickly. It provides a single pane of glass for metrics, traces and logs with deep filtering and aggregation to pin down specific issues very quickly."
/>
<meta
data-react-helmet="true"
property="og:image"
content="/images/signoz-hero-image.webp"
/>
<meta
data-react-helmet="true"
name="twitter:image"
content="/images/signoz-hero-image.webp"
/>
<meta
data-react-helmet="true"
name="twitter:image:alt"
content="Image for Open source Observability platform | SigNoz"
/>
<meta
data-react-helmet="true"
name="twitter:card"
content="summary_large_image"
/>
<meta data-react-helmet="true" name="docusaurus_locale" content="en" />
<meta data-react-helmet="true" name="docusaurus_tag" content="default" />
<meta name="robots" content="noindex" />
<link data-react-helmet="true" rel="shortcut icon" href="/favicon.ico" />
<% if (htmlWebpackPlugin.options.templateParameters.preloadFonts) { %> <%
htmlWebpackPlugin.options.templateParameters.preloadFonts.forEach(function(font)
{ %>
<link
rel="preload"
href="<%= font.href %>"
as="<%= font.as %>"
type="<%= font.type %>"
crossorigin="<%= font.crossorigin %>"
/>
<% }); %> <% } %>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script>
const PYLON_APP_ID = '<%= htmlWebpackPlugin.options.PYLON_APP_ID %>';
(function () {
var e = window;
var t = document;
var n = function () {
n.e(arguments);
};
n.q = [];
n.e = function (e) {
n.q.push(e);
};
e.Pylon = n;
var r = function () {
var e = t.createElement('script');
e.setAttribute('type', 'text/javascript');
e.setAttribute('async', 'true');
e.setAttribute(
'src',
'https://widget.usepylon.com/widget/' + PYLON_APP_ID,
);
var n = t.getElementsByTagName('script')[0];
n.parentNode.insertBefore(e, n);
};
if (t.readyState === 'complete') {
r();
} else if (e.addEventListener) {
e.addEventListener('load', r, false);
}
})();
</script>
<script type="text/javascript">
window.AppcuesSettings = { enableURLDetection: true };
</script>
<script>
const APPCUES_APP_ID = '<%= htmlWebpackPlugin.options.APPCUES_APP_ID %>';
(function (d, t) {
var a = d.createElement(t);
a.async = 1;
a.src = '//fast.appcues.com/' + APPCUES_APP_ID + '.js';
var s = d.getElementsByTagName(t)[0];
s.parentNode.insertBefore(a, s);
})(document, 'script');
</script>
<link rel="stylesheet" href="/css/uPlot.min.css" />
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
http-equiv="Cache-Control"
content="no-cache, no-store, must-revalidate, max-age: 0"
/>
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="preconnect" href="https://cdn.vercel.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"
rel="stylesheet"
/>
<title data-react-helmet="true">
Open source Observability platform | SigNoz
</title>
<meta
data-react-helmet="true"
property="og:title"
content="Open source Observability platform | SigNoz"
/>
<meta
data-react-helmet="true"
name="description"
content="SigNoz is an open source observability platform to help you find issues in your deployed applications & solve them quickly. It provides a single pane of glass for metrics, traces and logs with deep filtering and aggregation to pin down specific issues very quickly."
/>
<meta
data-react-helmet="true"
property="og:description"
content="SigNoz is an open source observability platform to help you find issues in your deployed applications & solve them quickly. It provides a single pane of glass for metrics, traces and logs with deep filtering and aggregation to pin down specific issues very quickly."
/>
<meta
data-react-helmet="true"
property="og:image"
content="/images/signoz-hero-image.webp"
/>
<meta
data-react-helmet="true"
name="twitter:image"
content="/images/signoz-hero-image.webp"
/>
<meta
data-react-helmet="true"
name="twitter:image:alt"
content="Image for Open source Observability platform | SigNoz"
/>
<meta
data-react-helmet="true"
name="twitter:card"
content="summary_large_image"
/>
<meta data-react-helmet="true" name="docusaurus_locale" content="en" />
<meta data-react-helmet="true" name="docusaurus_tag" content="default" />
<meta name="robots" content="noindex" />
<link data-react-helmet="true" rel="shortcut icon" href="/favicon.ico" />
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script>
var PYLON_APP_ID = '<%- PYLON_APP_ID %>';
if (PYLON_APP_ID) {
(function () {
var e = window;
var t = document;
var n = function () {
n.e(arguments);
};
n.q = [];
n.e = function (e) {
n.q.push(e);
};
e.Pylon = n;
var r = function () {
var e = t.createElement('script');
e.setAttribute('type', 'text/javascript');
e.setAttribute('async', 'true');
e.setAttribute(
'src',
'https://widget.usepylon.com/widget/' + PYLON_APP_ID,
);
var n = t.getElementsByTagName('script')[0];
n.parentNode.insertBefore(e, n);
};
if (t.readyState === 'complete') {
r();
} else if (e.addEventListener) {
e.addEventListener('load', r, false);
}
})();
}
</script>
<script type="text/javascript">
window.AppcuesSettings = { enableURLDetection: true };
</script>
<script>
var APPCUES_APP_ID = '<%- APPCUES_APP_ID %>';
if (APPCUES_APP_ID) {
(function (d, t) {
var a = d.createElement(t);
a.async = 1;
a.src = '//fast.appcues.com/' + APPCUES_APP_ID + '.js';
var s = d.getElementsByTagName(t)[0];
s.parentNode.insertBefore(a, s);
})(document, 'script');
}
</script>
<link rel="stylesheet" href="/css/uPlot.min.css" />
<script type="module" src="./src/index.tsx"></script>
</body>
</html>

View File

@@ -17,25 +17,26 @@ const config: Config.InitialOptions = {
'^hooks/useSafeNavigate$': USE_SAFE_NAVIGATE_MOCK_PATH,
'^src/hooks/useSafeNavigate$': USE_SAFE_NAVIGATE_MOCK_PATH,
'^.*/useSafeNavigate$': USE_SAFE_NAVIGATE_MOCK_PATH,
'^constants/env$': '<rootDir>/__mocks__/env.ts',
'^src/constants/env$': '<rootDir>/__mocks__/env.ts',
},
globals: {
extensionsToTreatAsEsm: ['.ts'],
'ts-jest': {
useESM: true,
isolatedModules: true,
tsconfig: '<rootDir>/tsconfig.jest.json',
},
},
extensionsToTreatAsEsm: ['.ts'],
testMatch: ['<rootDir>/src/**/*?(*.)(test).(ts|js)?(x)'],
preset: 'ts-jest/presets/js-with-ts-esm',
transform: {
'^.+\\.(ts|tsx)?$': 'ts-jest',
'^.+\\.(ts|tsx)?$': [
'ts-jest',
{
useESM: true,
tsconfig: '<rootDir>/tsconfig.jest.json',
},
],
'^.+\\.(js|jsx)$': 'babel-jest',
},
transformIgnorePatterns: [
'node_modules/(?!(lodash-es|react-dnd|core-dnd|@react-dnd|dnd-core|react-dnd-html5-backend|axios|@signozhq/design-tokens|@signozhq/table|@signozhq/calendar|@signozhq/input|@signozhq/popover|@signozhq/button|@signozhq/sonner|@signozhq/*|date-fns|d3-interpolate|d3-color|api|@codemirror|@lezer|@marijn)/)',
'node_modules/(?!(lodash-es|react-dnd|core-dnd|@react-dnd|dnd-core|react-dnd-html5-backend|axios|@signozhq/design-tokens|@signozhq/table|@signozhq/calendar|@signozhq/input|@signozhq/popover|@signozhq/button|@signozhq/sonner|@signozhq/*|date-fns|d3-interpolate|d3-color|api|@codemirror|@lezer|@marijn|@grafana)/)',
],
setupFilesAfterEnv: ['<rootDir>jest.setup.ts'],
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
testPathIgnorePatterns: ['/node_modules/', '/public/'],
moduleDirectories: ['node_modules', 'src'],
testEnvironment: 'jest-environment-jsdom',

View File

@@ -1,287 +1,275 @@
{
"name": "frontend",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"i18n:generate-hash": "node ./i18-generate-hash.js",
"dev": "cross-env NODE_ENV=development webpack serve --progress",
"build": "webpack --config=webpack.config.prod.js --progress",
"prettify": "prettier --write .",
"fmt": "prettier --check .",
"lint": "eslint ./src",
"lint:fix": "eslint ./src --fix",
"jest": "jest",
"jest:coverage": "jest --coverage",
"jest:watch": "jest --watch",
"postinstall": "yarn i18n:generate-hash && (is-ci || yarn husky:configure) && node scripts/update-registry.js",
"husky:configure": "cd .. && husky install frontend/.husky && cd frontend && chmod ug+x .husky/*",
"commitlint": "commitlint --edit $1",
"test": "jest",
"test:changedsince": "jest --changedSince=main --coverage --silent",
"generate:api": "orval --config ./orval.config.ts && sh scripts/post-types-generation.sh && prettier --write src/api/generated && (eslint --fix src/api/generated || true)"
},
"engines": {
"node": ">=16.15.0"
},
"author": "",
"license": "ISC",
"dependencies": {
"@ant-design/colors": "6.0.0",
"@ant-design/icons": "4.8.0",
"@codemirror/autocomplete": "6.18.6",
"@codemirror/lang-javascript": "6.2.3",
"@dnd-kit/core": "6.1.0",
"@dnd-kit/modifiers": "7.0.0",
"@dnd-kit/sortable": "8.0.0",
"@dnd-kit/utilities": "3.2.2",
"@grafana/data": "^11.2.3",
"@mdx-js/loader": "2.3.0",
"@mdx-js/react": "2.3.0",
"@monaco-editor/react": "^4.3.1",
"@playwright/test": "1.55.1",
"@radix-ui/react-tabs": "1.0.4",
"@radix-ui/react-tooltip": "1.0.7",
"@sentry/react": "8.41.0",
"@sentry/webpack-plugin": "2.22.6",
"@signozhq/badge": "0.0.2",
"@signozhq/button": "0.0.2",
"@signozhq/calendar": "0.0.0",
"@signozhq/callout": "0.0.2",
"@signozhq/checkbox": "0.0.2",
"@signozhq/combobox": "0.0.2",
"@signozhq/command": "0.0.0",
"@signozhq/design-tokens": "1.1.4",
"@signozhq/input": "0.0.2",
"@signozhq/popover": "0.0.0",
"@signozhq/resizable": "0.0.0",
"@signozhq/sonner": "0.1.0",
"@signozhq/table": "0.3.7",
"@signozhq/tooltip": "0.0.2",
"@tanstack/react-table": "8.20.6",
"@tanstack/react-virtual": "3.11.2",
"@uiw/codemirror-theme-copilot": "4.23.11",
"@uiw/codemirror-theme-github": "4.24.1",
"@uiw/react-codemirror": "4.23.10",
"@uiw/react-md-editor": "3.23.5",
"@visx/group": "3.3.0",
"@visx/hierarchy": "3.12.0",
"@visx/shape": "3.5.0",
"@visx/tooltip": "3.3.0",
"@xstate/react": "^3.0.0",
"ansi-to-html": "0.7.2",
"antd": "5.11.0",
"antd-table-saveas-excel": "2.2.1",
"antlr4": "4.13.2",
"axios": "1.12.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^29.6.4",
"babel-loader": "9.1.3",
"babel-plugin-named-asset-import": "^0.3.7",
"babel-preset-minify": "^0.5.1",
"babel-preset-react-app": "^10.0.1",
"chart.js": "3.9.1",
"chartjs-adapter-date-fns": "^2.0.0",
"chartjs-plugin-annotation": "^1.4.0",
"classnames": "2.3.2",
"color": "^4.2.1",
"color-alpha": "1.1.3",
"cross-env": "^7.0.3",
"crypto-js": "4.2.0",
"css-loader": "5.0.0",
"css-minimizer-webpack-plugin": "5.0.1",
"d3-hierarchy": "3.1.2",
"dayjs": "^1.10.7",
"dompurify": "3.2.4",
"dotenv": "8.2.0",
"event-source-polyfill": "1.0.31",
"eventemitter3": "5.0.1",
"file-loader": "6.1.1",
"fontfaceobserver": "2.3.0",
"history": "4.10.1",
"html-webpack-plugin": "5.5.0",
"http-proxy-middleware": "3.0.5",
"http-status-codes": "2.3.0",
"i18next": "^21.6.12",
"i18next-browser-languagedetector": "^6.1.3",
"i18next-http-backend": "^1.3.2",
"immer": "11.1.3",
"jest": "^27.5.1",
"js-base64": "^3.7.2",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"lodash-es": "^4.17.21",
"lucide-react": "0.498.0",
"mini-css-extract-plugin": "2.4.5",
"motion": "12.4.13",
"overlayscrollbars": "^2.8.1",
"overlayscrollbars-react": "^0.5.6",
"papaparse": "5.4.1",
"posthog-js": "1.298.0",
"rc-tween-one": "3.0.6",
"react": "18.2.0",
"react-addons-update": "15.6.3",
"react-beautiful-dnd": "13.1.1",
"react-dnd": "16.0.1",
"react-dnd-html5-backend": "16.0.1",
"react-dom": "18.2.0",
"react-drag-listview": "2.0.0",
"react-error-boundary": "4.0.11",
"react-force-graph": "^1.43.0",
"react-full-screen": "1.1.1",
"react-grid-layout": "^1.3.4",
"react-helmet-async": "1.3.0",
"react-i18next": "^11.16.1",
"react-lottie": "1.2.10",
"react-markdown": "8.0.7",
"react-query": "3.39.3",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"react-router-dom-v5-compat": "6.27.0",
"react-syntax-highlighter": "15.5.0",
"react-use": "^17.3.2",
"react-virtuoso": "4.0.3",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"rehype-raw": "7.0.0",
"rrule": "2.8.1",
"stream": "^0.0.2",
"style-loader": "1.3.0",
"styled-components": "^5.3.11",
"terser-webpack-plugin": "^5.2.5",
"timestamp-nano": "^1.0.0",
"ts-node": "^10.2.1",
"tsconfig-paths-webpack-plugin": "^3.5.1",
"typescript": "^4.0.5",
"uplot": "1.6.31",
"uuid": "^8.3.2",
"web-vitals": "^0.2.4",
"webpack": "5.94.0",
"webpack-dev-server": "^5.2.1",
"webpack-retry-chunk-load-plugin": "3.1.1",
"xstate": "^4.31.0"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@babel/core": "^7.22.11",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-syntax-jsx": "^7.12.13",
"@babel/preset-env": "^7.22.14",
"@babel/preset-react": "^7.12.13",
"@babel/preset-typescript": "^7.21.4",
"@commitlint/cli": "^16.3.0",
"@commitlint/config-conventional": "^16.2.4",
"@faker-js/faker": "9.3.0",
"@jest/globals": "^27.5.1",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "13.4.0",
"@testing-library/user-event": "14.4.3",
"@types/color": "^3.0.3",
"@types/compression-webpack-plugin": "^9.0.0",
"@types/copy-webpack-plugin": "^8.0.1",
"@types/crypto-js": "4.2.2",
"@types/dompurify": "^2.4.0",
"@types/event-source-polyfill": "^1.0.0",
"@types/fontfaceobserver": "2.1.0",
"@types/jest": "^27.5.1",
"@types/lodash-es": "^4.17.4",
"@types/mini-css-extract-plugin": "^2.5.1",
"@types/node": "^16.10.3",
"@types/papaparse": "5.3.7",
"@types/react": "18.0.26",
"@types/react-addons-update": "0.14.21",
"@types/react-beautiful-dnd": "13.1.8",
"@types/react-dom": "18.0.10",
"@types/react-grid-layout": "^1.1.2",
"@types/react-helmet-async": "1.0.3",
"@types/react-lottie": "1.2.10",
"@types/react-redux": "^7.1.11",
"@types/react-resizable": "3.0.3",
"@types/react-router-dom": "^5.1.6",
"@types/react-syntax-highlighter": "15.5.7",
"@types/redux-mock-store": "1.0.4",
"@types/styled-components": "^5.1.4",
"@types/uuid": "^8.3.1",
"@types/webpack": "^5.28.0",
"@types/webpack-dev-server": "^4.7.2",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"autoprefixer": "10.4.19",
"babel-plugin-styled-components": "^1.12.0",
"compression-webpack-plugin": "9.0.0",
"copy-webpack-plugin": "^11.0.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jest": "^26.9.0",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.3.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"eslint-plugin-sonarjs": "^0.12.0",
"husky": "^7.0.4",
"image-minimizer-webpack-plugin": "^4.0.0",
"imagemin": "^8.0.1",
"imagemin-svgo": "^10.0.1",
"is-ci": "^3.0.1",
"jest-styled-components": "^7.0.8",
"lint-staged": "^12.5.0",
"msw": "1.3.2",
"npm-run-all": "latest",
"orval": "7.18.0",
"portfinder-sync": "^0.0.2",
"postcss": "8.4.38",
"prettier": "2.2.1",
"prop-types": "15.8.1",
"raw-loader": "4.0.2",
"react-hooks-testing-library": "0.6.0",
"react-hot-loader": "^4.13.0",
"react-resizable": "3.0.4",
"redux-mock-store": "1.5.4",
"sass": "1.66.1",
"sass-loader": "13.3.2",
"sharp": "^0.33.4",
"ts-jest": "^27.1.5",
"ts-node": "^10.2.1",
"typescript-plugin-css-modules": "5.2.0",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^5.1.4"
},
"lint-staged": {
"*.(js|jsx|ts|tsx)": [
"eslint --fix",
"sh scripts/typecheck-staged.sh"
]
},
"resolutions": {
"@types/react": "18.0.26",
"@types/react-dom": "18.0.10",
"debug": "4.3.4",
"semver": "7.5.4",
"xml2js": "0.5.0",
"phin": "^3.7.1",
"body-parser": "1.20.3",
"http-proxy-middleware": "3.0.5",
"cross-spawn": "7.0.5",
"cookie": "^0.7.1",
"serialize-javascript": "6.0.2",
"prismjs": "1.30.0",
"got": "11.8.5",
"form-data": "4.0.4",
"brace-expansion": "^2.0.2",
"on-headers": "^1.1.0",
"tmp": "0.2.4"
}
"name": "frontend",
"version": "1.0.0",
"description": "",
"type": "module",
"scripts": {
"i18n:generate-hash": "node ./i18-generate-hash.cjs",
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"prettify": "prettier --write .",
"fmt": "prettier --check .",
"lint": "eslint ./src",
"lint:fix": "eslint ./src --fix",
"jest": "jest",
"jest:coverage": "jest --coverage",
"jest:watch": "jest --watch",
"postinstall": "yarn i18n:generate-hash && (is-ci || yarn husky:configure) && node scripts/update-registry.cjs",
"husky:configure": "cd .. && husky install frontend/.husky && cd frontend && chmod ug+x .husky/*",
"commitlint": "commitlint --edit $1",
"test": "jest",
"test:changedsince": "jest --changedSince=main --coverage --silent",
"generate:api": "orval --config ./orval.config.ts && sh scripts/post-types-generation.sh && prettier --write src/api/generated && (eslint --fix src/api/generated || true)"
},
"engines": {
"node": ">=16.15.0"
},
"author": "",
"license": "ISC",
"dependencies": {
"@ant-design/colors": "6.0.0",
"@ant-design/icons": "4.8.0",
"@codemirror/autocomplete": "6.18.6",
"@codemirror/lang-javascript": "6.2.3",
"@dnd-kit/core": "6.1.0",
"@dnd-kit/modifiers": "7.0.0",
"@dnd-kit/sortable": "8.0.0",
"@dnd-kit/utilities": "3.2.2",
"@grafana/data": "^11.2.3",
"@mdx-js/loader": "2.3.0",
"@mdx-js/react": "2.3.0",
"@monaco-editor/react": "^4.3.1",
"@playwright/test": "1.55.1",
"@radix-ui/react-tabs": "1.0.4",
"@radix-ui/react-tooltip": "1.0.7",
"@sentry/react": "8.41.0",
"@sentry/vite-plugin": "2.22.6",
"@signozhq/badge": "0.0.2",
"@signozhq/button": "0.0.2",
"@signozhq/calendar": "0.0.0",
"@signozhq/callout": "0.0.2",
"@signozhq/checkbox": "0.0.2",
"@signozhq/combobox": "0.0.2",
"@signozhq/command": "0.0.0",
"@signozhq/design-tokens": "1.1.4",
"@signozhq/input": "0.0.2",
"@signozhq/popover": "0.0.0",
"@signozhq/resizable": "0.0.0",
"@signozhq/sonner": "0.1.0",
"@signozhq/table": "0.3.7",
"@signozhq/tooltip": "0.0.2",
"@tanstack/react-table": "8.20.6",
"@tanstack/react-virtual": "3.11.2",
"@uiw/codemirror-theme-copilot": "4.23.11",
"@uiw/codemirror-theme-github": "4.24.1",
"@uiw/react-codemirror": "4.23.10",
"@uiw/react-md-editor": "3.23.5",
"@visx/group": "3.3.0",
"@visx/hierarchy": "3.12.0",
"@visx/shape": "3.5.0",
"@visx/tooltip": "3.3.0",
"@vitejs/plugin-react": "5.1.4",
"@xstate/react": "^3.0.0",
"ansi-to-html": "0.7.2",
"antd": "5.11.0",
"antd-table-saveas-excel": "2.2.1",
"antlr4": "4.13.2",
"axios": "1.12.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^29.6.4",
"babel-loader": "9.1.3",
"babel-plugin-named-asset-import": "^0.3.7",
"babel-preset-minify": "^0.5.1",
"babel-preset-react-app": "^10.0.1",
"chart.js": "3.9.1",
"chartjs-adapter-date-fns": "^2.0.0",
"chartjs-plugin-annotation": "^1.4.0",
"classnames": "2.3.2",
"color": "^4.2.1",
"color-alpha": "1.1.3",
"cross-env": "^7.0.3",
"crypto-js": "4.2.0",
"d3-hierarchy": "3.1.2",
"dayjs": "^1.10.7",
"dompurify": "3.2.4",
"dotenv": "8.2.0",
"event-source-polyfill": "1.0.31",
"eventemitter3": "5.0.1",
"fontfaceobserver": "2.3.0",
"history": "4.10.1",
"http-proxy-middleware": "3.0.5",
"http-status-codes": "2.3.0",
"i18next": "^21.6.12",
"i18next-browser-languagedetector": "^6.1.3",
"i18next-http-backend": "^1.3.2",
"immer": "11.1.3",
"jest": "^30.2.0",
"js-base64": "^3.7.2",
"lodash-es": "^4.17.21",
"lucide-react": "0.498.0",
"mini-css-extract-plugin": "2.4.5",
"motion": "12.4.13",
"overlayscrollbars": "^2.8.1",
"overlayscrollbars-react": "^0.5.6",
"papaparse": "5.4.1",
"posthog-js": "1.298.0",
"rc-tween-one": "3.0.6",
"react": "18.2.0",
"react-addons-update": "15.6.3",
"react-beautiful-dnd": "13.1.1",
"react-dnd": "16.0.1",
"react-dnd-html5-backend": "16.0.1",
"react-dom": "18.2.0",
"react-drag-listview": "2.0.0",
"react-error-boundary": "4.0.11",
"react-force-graph": "^1.43.0",
"react-full-screen": "1.1.1",
"react-grid-layout": "^1.3.4",
"react-helmet-async": "1.3.0",
"react-i18next": "^11.16.1",
"react-lottie": "1.2.10",
"react-markdown": "8.0.7",
"react-query": "3.39.3",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"react-router-dom-v5-compat": "6.27.0",
"react-syntax-highlighter": "15.5.0",
"react-use": "^17.3.2",
"react-virtuoso": "4.0.3",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"rehype-raw": "7.0.0",
"rollup-plugin-visualizer": "^5.12.0",
"rrule": "2.8.1",
"stream": "^0.0.2",
"styled-components": "^5.3.11",
"timestamp-nano": "^1.0.0",
"ts-node": "^10.2.1",
"typescript": "^5.9.3",
"uplot": "1.6.31",
"uuid": "^8.3.2",
"vite": "npm:rolldown-vite@latest",
"vite-plugin-html": "^3.2.2",
"web-vitals": "^0.2.4",
"xstate": "^4.31.0"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@babel/core": "^7.22.11",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-syntax-jsx": "^7.12.13",
"@babel/preset-env": "^7.22.14",
"@babel/preset-react": "^7.12.13",
"@babel/preset-typescript": "^7.21.4",
"@commitlint/cli": "^20.4.2",
"@commitlint/config-conventional": "^20.4.2",
"@faker-js/faker": "9.3.0",
"@jest/globals": "^30.2.0",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "13.4.0",
"@testing-library/user-event": "14.4.3",
"@types/color": "^3.0.3",
"@types/crypto-js": "4.2.2",
"@types/dompurify": "^2.4.0",
"@types/event-source-polyfill": "^1.0.0",
"@types/fontfaceobserver": "2.1.0",
"@types/jest": "^30.0.0",
"@types/lodash-es": "^4.17.4",
"@types/mini-css-extract-plugin": "^2.5.1",
"@types/node": "^16.10.3",
"@types/papaparse": "5.3.7",
"@types/react": "18.0.26",
"@types/react-addons-update": "0.14.21",
"@types/react-beautiful-dnd": "13.1.8",
"@types/react-dom": "18.0.10",
"@types/react-grid-layout": "^1.1.2",
"@types/react-helmet-async": "1.0.3",
"@types/react-lottie": "1.2.10",
"@types/react-redux": "^7.1.11",
"@types/react-resizable": "3.0.3",
"@types/react-router-dom": "^5.1.6",
"@types/react-syntax-highlighter": "15.5.7",
"@types/redux-mock-store": "1.0.4",
"@types/styled-components": "^5.1.4",
"@types/uuid": "^8.3.1",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"autoprefixer": "10.4.19",
"babel-plugin-styled-components": "^1.12.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jest": "^29.15.0",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.3.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"eslint-plugin-sonarjs": "^0.12.0",
"husky": "^7.0.4",
"imagemin": "^8.0.1",
"imagemin-svgo": "^10.0.1",
"is-ci": "^3.0.1",
"jest-environment-jsdom": "30.2.0",
"jest-styled-components": "^7.2.0",
"lint-staged": "^12.5.0",
"msw": "1.3.2",
"npm-run-all": "latest",
"orval": "7.18.0",
"portfinder-sync": "^0.0.2",
"postcss": "8.5.6",
"prettier": "2.2.1",
"prop-types": "15.8.1",
"react-hooks-testing-library": "0.6.0",
"react-resizable": "3.0.4",
"redux-mock-store": "1.5.4",
"sass": "1.97.3",
"sharp": "0.34.5",
"svgo": "4.0.0",
"ts-api-utils": "2.4.0",
"ts-jest": "^29.4.6",
"ts-node": "^10.2.1",
"typescript-plugin-css-modules": "5.2.0",
"vite-plugin-compression": "0.5.1",
"vite-plugin-image-optimizer": "2.0.3",
"vite-tsconfig-paths": "6.1.1"
},
"lint-staged": {
"*.(js|jsx|ts|tsx)": [
"eslint --fix",
"sh scripts/typecheck-staged.sh"
]
},
"resolutions": {
"@types/react": "18.0.26",
"@types/react-dom": "18.0.10",
"debug": "4.3.4",
"semver": "7.5.4",
"xml2js": "0.5.0",
"phin": "^3.7.1",
"body-parser": "1.20.3",
"http-proxy-middleware": "3.0.5",
"cross-spawn": "7.0.5",
"cookie": "^0.7.1",
"serialize-javascript": "6.0.2",
"prismjs": "1.30.0",
"got": "11.8.5",
"form-data": "4.0.4",
"brace-expansion": "^2.0.2",
"on-headers": "^1.1.0",
"tmp": "0.2.4",
"vite": "npm:rolldown-vite@latest"
}
}

View File

@@ -1,9 +1,12 @@
import { defineConfig, devices } from '@playwright/test';
import dotenv from 'dotenv';
import { fileURLToPath } from 'node:url';
import path from 'path';
// Read from ".env" file.
dotenv.config({ path: path.resolve(__dirname, '.env') });
dotenv.config({
path: path.resolve(path.dirname(fileURLToPath(import.meta.url)), '.env'),
});
/**
* Read environment variables from file.

View File

@@ -1,33 +1,27 @@
/* eslint-disable @typescript-eslint/no-var-requires, import/no-dynamic-require, simple-import-sort/imports, simple-import-sort/exports */
const fs = require('fs');
const path = require('path');
// 1. Define paths
const packageJsonPath = path.resolve(__dirname, '../package.json');
const registryPath = path.resolve(
__dirname,
'../src/auto-import-registry.d.ts',
);
// 2. Read package.json
const packageJson = require(packageJsonPath);
// 3. Combine dependencies and devDependencies
const allDeps = {
...packageJson.dependencies,
...packageJson.devDependencies,
};
// 4. Filter for @signozhq packages
const signozPackages = Object.keys(allDeps).filter((dep) =>
dep.startsWith('@signozhq/'),
);
// 5. Generate file content
const fileContent = `// -------------------------------------------------------------------------
// AUTO-GENERATED FILE
// -------------------------------------------------------------------------
// This file is generated by scripts/update-registry.js automatically
// This file is generated by scripts/update-registry.cjs automatically
// whenever you run 'yarn install' or 'npm install'.
//
// It forces VS Code to index these specific packages to fix auto-import
@@ -39,12 +33,11 @@ const fileContent = `// --------------------------------------------------------
${signozPackages.map((pkg) => `import '${pkg}';`).join('\n')}
`;
// 6. Write the file
try {
fs.writeFileSync(registryPath, fileContent);
console.log(
`Auto-import registry updated with ${signozPackages.length} @signozhq packages.`,
`Auto-import registry updated with ${signozPackages.length} @signozhq packages.`,
);
} catch (err) {
console.error('Failed to update auto-import registry:', err);
console.error('Failed to update auto-import registry:', err);
}

View File

@@ -220,11 +220,11 @@ function App(): JSX.Element {
) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.Pylon('hideChatBubble');
window.Pylon?.('hideChatBubble');
} else {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.Pylon('showChatBubble');
window.Pylon?.('showChatBubble');
}
}, [pathname]);

View File

@@ -1,7 +1,7 @@
// -------------------------------------------------------------------------
// AUTO-GENERATED FILE
// -------------------------------------------------------------------------
// This file is generated by scripts/update-registry.js automatically
// This file is generated by scripts/update-registry.cjs automatically
// whenever you run 'yarn install' or 'npm install'.
//
// It forces VS Code to index these specific packages to fix auto-import

View File

@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`DraggableTableRow Snapshot test should render DraggableTableRow 1`] = `
<DocumentFragment>

View File

@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Editor renders correctly with custom props 1`] = `
<div>

View File

@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`MessageTip custom action 1`] = `
.c0 {

View File

@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Not Found page test should render Not Found page without errors 1`] = `
<DocumentFragment>

View File

@@ -74,7 +74,7 @@ describe('Alert Channels Settings List page', () => {
});
await waitFor(() => {
expect(successNotification).toBeCalledWith({
expect(successNotification).toHaveBeenCalledWith({
message: 'Success',
description: 'channel_delete_success',
});

View File

@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Table panel wrappper tests table should render fine with the query response and column units 1`] = `
.c1 {
@@ -223,7 +223,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
style="overflow-x: auto; overflow-y: hidden;"
>
<table
style="min-width: 100%; table-layout: fixed;"
style="width: max-content; min-width: 100%; table-layout: fixed;"
>
<colgroup>
<col
@@ -274,6 +274,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
demo-app
</div>
@@ -291,6 +292,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
4.35 s
</div>
@@ -312,6 +314,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
customer
</div>
@@ -329,6 +332,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
431.25 ms
</div>
@@ -350,6 +354,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
mysql
</div>
@@ -367,6 +372,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
431.25 ms
</div>
@@ -388,6 +394,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
frontend
</div>
@@ -405,6 +412,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
287.11 ms
</div>
@@ -426,6 +434,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
driver
</div>
@@ -443,6 +452,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
230.02 ms
</div>
@@ -464,6 +474,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
route
</div>
@@ -481,6 +492,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
66.37 ms
</div>
@@ -502,6 +514,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
redis
</div>
@@ -519,6 +532,7 @@ exports[`Table panel wrappper tests table should render fine with the query resp
<div>
<div
class="line-clamped-wrapper__text"
style="-webkit-line-clamp: 3;"
>
31.3 ms
</div>

View File

@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Value panel wrappper tests should render tooltip when there are conflicting thresholds 1`] = `
.c1 {
@@ -50,14 +50,14 @@ exports[`Value panel wrappper tests should render tooltip when there are conflic
<span
class="ant-typography value-graph-text css-dev-only-do-not-override-2i2tap"
data-testid="value-graph-text"
style="color: Blue; font-size: 16px;"
style="color: blue; font-size: 16px;"
>
295.43
</span>
<span
class="ant-typography value-graph-unit css-dev-only-do-not-override-2i2tap"
data-testid="value-graph-suffix-unit"
style="color: Blue; font-size: calc(16px * 0.7);"
style="color: blue; font-size: calc(11.2px);"
>
ms
</span>

View File

@@ -52,7 +52,7 @@ describe('PipelinePage container test', () => {
expect(editButton).toBeInTheDocument();
await userEvent.click(editButton);
expect(logEvent).toBeCalledWith('Logs: Pipelines: Entered Edit Mode', {
expect(logEvent).toHaveBeenCalledWith('Logs: Pipelines: Entered Edit Mode', {
source: 'signoz-ui',
});
});
@@ -77,8 +77,11 @@ describe('PipelinePage container test', () => {
expect(editButton).toBeInTheDocument();
await userEvent.click(editButton);
expect(logEvent).toBeCalledWith('Logs: Pipelines: Clicked Add New Pipeline', {
source: 'signoz-ui',
});
expect(logEvent).toHaveBeenCalledWith(
'Logs: Pipelines: Clicked Add New Pipeline',
{
source: 'signoz-ui',
},
);
});
});

View File

@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`PipelinePage container test should render CreatePipelineButton section 1`] = `
<DocumentFragment>

View File

@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`PipelinePage container test should render PipelinesSearchSection section 1`] = `
<DocumentFragment>

View File

@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`PipelinePage container test should render TableExpandIcon section 1`] = `
<DocumentFragment>

View File

@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`PipelinePage container test should render Tags section 1`] = `
<DocumentFragment>

View File

@@ -52,10 +52,10 @@ describe('ToolbarActions', () => {
expect(queryByTestId('clickhouse-view')).not.toBeInTheDocument();
await userEvent.click(screen.getByTestId('search-view'));
expect(handleChangeSelectedView).toBeCalled();
expect(handleChangeSelectedView).toHaveBeenCalled();
await userEvent.click(screen.getByTestId('query-builder-view'));
expect(handleChangeSelectedView).toBeCalled();
expect(handleChangeSelectedView).toHaveBeenCalled();
});
it('renders - clickhouse view and test view switching', async () => {
@@ -79,14 +79,14 @@ describe('ToolbarActions', () => {
expect(clickHouseView).toBeInTheDocument();
await userEvent.click(clickHouseView as HTMLElement);
expect(handleChangeSelectedView).toBeCalled();
expect(handleChangeSelectedView).toHaveBeenCalled();
// Test that timeseries view is also present and clickable
const timeseriesView = queryByTestId('query-builder-view');
expect(timeseriesView).toBeInTheDocument();
await userEvent.click(timeseriesView as HTMLElement);
expect(handleChangeSelectedView).toBeCalled();
expect(handleChangeSelectedView).toHaveBeenCalled();
});
it('RightToolbarActions - render correctly with props', async () => {
@@ -100,6 +100,6 @@ describe('ToolbarActions', () => {
const runQueryBtn = queryByText('Run Query');
expect(runQueryBtn).toBeInTheDocument();
await userEvent.click(runQueryBtn as HTMLElement);
expect(onStageRunQuery).toBeCalled();
expect(onStageRunQuery).toHaveBeenCalled();
});
});

View File

@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`loads and displays greeting 1`] = `
<DocumentFragment>

View File

@@ -0,0 +1,65 @@
import { generatePath } from 'react-router-dom';
import { TabRoutes } from 'components/RouteTab/types';
import { QueryParams } from 'constants/query';
import ROUTES from 'constants/routes';
import AlertHistory from 'container/AlertHistory';
import { AlertDetailsTab } from 'container/AlertHistory/types';
import useUrlQuery from 'hooks/useUrlQuery';
import { History, Table } from 'lucide-react';
import EditRules from 'pages/EditRules';
import BetaTag from 'periscope/components/BetaTag/BetaTag';
export const useRouteTabUtils = (): { routes: TabRoutes[] } => {
const urlQuery = useUrlQuery();
const getRouteUrl = (tab: AlertDetailsTab): string => {
let route = '';
let params = urlQuery.toString();
const ruleIdKey = QueryParams.ruleId;
const relativeTimeKey = QueryParams.relativeTime;
switch (tab) {
case AlertDetailsTab.OVERVIEW:
route = ROUTES.ALERT_OVERVIEW;
break;
case AlertDetailsTab.HISTORY:
params = `${ruleIdKey}=${urlQuery.get(
ruleIdKey,
)}&${relativeTimeKey}=${urlQuery.get(relativeTimeKey)}`;
route = ROUTES.ALERT_HISTORY;
break;
default:
return '';
}
return `${generatePath(route)}?${params}`;
};
const routes = [
{
Component: EditRules,
name: (
<div className="tab-item">
<Table size={14} />
Overview
</div>
),
route: getRouteUrl(AlertDetailsTab.OVERVIEW),
key: ROUTES.ALERT_OVERVIEW,
},
{
Component: AlertHistory,
name: (
<div className="tab-item">
<History size={14} />
History
<BetaTag />
</div>
),
route: getRouteUrl(AlertDetailsTab.HISTORY),
key: ROUTES.ALERT_HISTORY,
},
];
return { routes };
};

View File

@@ -1,5 +1,5 @@
@import './components/Header/Header.styles.scss';
@import './components/SearchBar/SearchBar.styles.scss';
@use 'components/Header/Header.styles.scss';
@use 'components/SearchBar/SearchBar.styles.scss';
.traces-funnels {
margin-top: 113px;

View File

@@ -1,7 +1,8 @@
@use 'periscope.scss';
@import '@signozhq/design-tokens/dist/style.css';
@import 'overlayscrollbars/overlayscrollbars.css';
@import './periscope.scss';
/* Import fonts from CDN */
@import url('https://fonts.googleapis.com/css2?family=Work+Sans&wght@500&display=swap');

View File

@@ -1,39 +1,39 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`utils/spanToTree should return a single tree on valid trace data 1`] = `
Object {
"missingSpanTree": Array [],
"spanTree": Array [
Object {
"childReferences": Array [
Object {
{
"missingSpanTree": [],
"spanTree": [
{
"childReferences": [
{
"RefType": "CHILD_OF",
"SpanId": "",
"TraceId": "0000000000000000span_1",
},
],
"children": Array [
Object {
"childReferences": Array [
Object {
"children": [
{
"childReferences": [
{
"RefType": "CHILD_OF",
"SpanId": "span_1",
"TraceId": "0000000000000000span_1",
},
],
"children": Array [
Object {
"childReferences": Array [
Object {
"children": [
{
"childReferences": [
{
"RefType": "CHILD_OF",
"SpanId": "span_2",
"TraceId": "0000000000000000span_1",
},
],
"children": Array [],
"event": Array [
Object {
"attributeMap": Object {
"children": [],
"event": [
{
"attributeMap": {
"event": "HTTP request received S3",
"level": "info",
"method": "GET",
@@ -46,15 +46,15 @@ Object {
"id": "span_3",
"isProcessed": true,
"name": "HTTP GET SPAN 3",
"nonChildReferences": Array [],
"nonChildReferences": [],
"serviceColour": "",
"serviceName": "frontend",
"spanKind": "Lorem Ipsum2",
"startTime": 1657275433246,
"statusCodeString": "Unset2",
"statusMessage": "Server2",
"tags": Array [
Object {
"tags": [
{
"key": "host.name.span3",
"value": "span_3",
},
@@ -63,9 +63,9 @@ Object {
"value": 683273000,
},
],
"event": Array [
Object {
"attributeMap": Object {
"event": [
{
"attributeMap": {
"event": "HTTP request received S2",
"level": "info",
"method": "GET",
@@ -78,15 +78,15 @@ Object {
"id": "span_2",
"isProcessed": true,
"name": "HTTP GET SPAN 2",
"nonChildReferences": Array [],
"nonChildReferences": [],
"serviceColour": "",
"serviceName": "frontend",
"spanKind": "Lorem Ipsum1",
"startTime": 1657275433246,
"statusCodeString": "Unset1",
"statusMessage": "Server1",
"tags": Array [
Object {
"tags": [
{
"key": "host.name.span2",
"value": "span_2",
},
@@ -95,9 +95,9 @@ Object {
"value": 683273000,
},
],
"event": Array [
Object {
"attributeMap": Object {
"event": [
{
"attributeMap": {
"event": "HTTP request received S1",
"level": "info",
"method": "GET",
@@ -109,15 +109,15 @@ Object {
"hasError": false,
"id": "span_1",
"name": "HTTP GET SPAN 1",
"nonChildReferences": Array [],
"nonChildReferences": [],
"serviceColour": "",
"serviceName": "frontend",
"spanKind": "Lorem Ipsum",
"startTime": 1657275433246,
"statusCodeString": "Unset",
"statusMessage": "Server",
"tags": Array [
Object {
"tags": [
{
"key": "host.name.span1",
"value": "span_1",
},
@@ -130,22 +130,22 @@ Object {
`;
exports[`utils/spanToTree should return a single tree on valid trace data 2`] = `
Object {
"missingSpanTree": Array [
Object {
"children": Array [
Object {
"childReferences": Array [
Object {
{
"missingSpanTree": [
{
"children": [
{
"childReferences": [
{
"RefType": "CHILD_OF",
"SpanId": "span_2",
"TraceId": "0000000000000000span_1",
},
],
"children": Array [],
"event": Array [
Object {
"attributeMap": Object {
"children": [],
"event": [
{
"attributeMap": {
"event": "HTTP request received S3",
"level": "info",
"method": "GET",
@@ -158,15 +158,15 @@ Object {
"id": "span_3",
"isProcessed": true,
"name": "HTTP GET SPAN 3",
"nonChildReferences": Array [],
"nonChildReferences": [],
"serviceColour": "",
"serviceName": "frontend",
"spanKind": "Lorem Ipsum2",
"startTime": 1657275433246,
"statusCodeString": "Unset2",
"statusMessage": "Server2",
"tags": Array [
Object {
"tags": [
{
"key": "host.name.span3",
"value": "span_3",
},
@@ -184,24 +184,24 @@ Object {
"startTime": null,
"statusCodeString": "",
"statusMessage": "",
"tags": Array [],
"tags": [],
"time": null,
"value": null,
},
],
"spanTree": Array [
Object {
"childReferences": Array [
Object {
"spanTree": [
{
"childReferences": [
{
"RefType": "CHILD_OF",
"SpanId": "",
"TraceId": "0000000000000000span_1",
},
],
"children": Array [],
"event": Array [
Object {
"attributeMap": Object {
"children": [],
"event": [
{
"attributeMap": {
"event": "HTTP request received S1",
"level": "info",
"method": "GET",
@@ -213,15 +213,15 @@ Object {
"hasError": false,
"id": "span_1",
"name": "HTTP GET SPAN 1",
"nonChildReferences": Array [],
"nonChildReferences": [],
"serviceColour": "",
"serviceName": "frontend",
"spanKind": "Lorem Ipsum",
"startTime": 1657275433246,
"statusCodeString": "Unset",
"statusMessage": "Server",
"tags": Array [
Object {
"tags": [
{
"key": "host.name.span1",
"value": "span_1",
},

View File

@@ -1,34 +1,26 @@
import { getLocation } from 'utils/getLocation';
import { buildAbsolutePath } from '../app';
jest.mock('utils/getLocation');
const BASE_PATH = '/some-base-path';
describe('buildAbsolutePath', () => {
const originalLocation = window.location;
afterEach(() => {
Object.defineProperty(window, 'location', {
writable: true,
value: originalLocation,
});
const mockLocation = (pathname: string): void => {
(getLocation as jest.Mock).mockReturnValue({
pathname,
href: `http://localhost:8080${pathname}`,
origin: 'http://localhost:8080',
protocol: 'http:',
host: 'localhost',
hostname: 'localhost',
port: '',
search: '',
hash: '',
});
};
const mockLocation = (pathname: string): void => {
Object.defineProperty(window, 'location', {
writable: true,
value: {
pathname,
href: `http://localhost:8080${pathname}`,
origin: 'http://localhost:8080',
protocol: 'http:',
host: 'localhost',
hostname: 'localhost',
port: '',
search: '',
hash: '',
},
});
};
describe('buildAbsolutePath', () => {
describe('when base path ends with a forward slash', () => {
beforeEach(() => {
mockLocation(`${BASE_PATH}/`);

View File

@@ -2,6 +2,7 @@ import getLocalStorage from 'api/browser/localstorage/get';
import { FeatureKeys } from 'constants/features';
import { SKIP_ONBOARDING } from 'constants/onboarding';
import { get } from 'lodash-es';
import { getLocation } from 'utils/getLocation';
export const isOnboardingSkipped = (): boolean =>
getLocalStorage(SKIP_ONBOARDING) === 'true';
@@ -57,7 +58,7 @@ export function buildAbsolutePath({
relativePath: string;
urlQueryString?: string;
}): string {
const { pathname } = window.location;
const { pathname } = getLocation();
// ensure base path always ends with a forward slash
const basePath = pathname.endsWith('/') ? pathname : `${pathname}/`;

View File

@@ -0,0 +1 @@
export const getLocation = (): Location => window.location;

31
frontend/src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1,31 @@
/// <reference types="vite/client" />
declare module '*.md' {
const content: string;
export default content;
}
declare module '*.md?raw' {
const content: string;
export default content;
}
interface ImportMetaEnv {
readonly VITE_FRONTEND_API_ENDPOINT: string;
readonly VITE_WEBSOCKET_API_ENDPOINT: string;
readonly VITE_PYLON_APP_ID: string;
readonly VITE_PYLON_IDENTITY_SECRET: string;
readonly VITE_APPCUES_APP_ID: string;
readonly VITE_POSTHOG_KEY: string;
readonly VITE_SENTRY_AUTH_TOKEN: string;
readonly VITE_SENTRY_ORG: string;
readonly VITE_SENTRY_PROJECT_ID: string;
readonly VITE_SENTRY_DSN: string;
readonly VITE_TUNNEL_URL: string;
readonly VITE_TUNNEL_DOMAIN: string;
readonly VITE_DOCS_BASE_URL: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}

View File

@@ -1,7 +1,7 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"target": "es6",
"noEmit": false
"noEmit": false,
"isolatedModules": true
}
}
}

View File

@@ -5,7 +5,7 @@
"noImplicitAny": true,
"noImplicitReturns": true,
"module": "esnext",
"target": "es5",
"target": "es2018",
"jsx": "react-jsx",
"allowJs": true,
"strict": true,
@@ -15,13 +15,14 @@
"lib": ["dom", "dom.iterable", "esnext"],
"allowSyntheticDefaultImports": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"baseUrl": "./src",
"paths": {
"@constants/*": ["/container/OnboardingContainer/constants/*"]
"*": ["./*"],
"@constants/*": ["./container/OnboardingContainer/constants/*"]
},
"downlevelIteration": true,
"plugins": [
@@ -29,7 +30,7 @@
"name": "typescript-plugin-css-modules"
}
],
"types": ["node", "jest"]
"types": ["vite/client", "node", "jest"]
},
"exclude": ["node_modules", "src/parser/*.ts", "src/parser/TraceOperatorParser/*.ts", "orval.config.ts"],
"include": [
@@ -37,15 +38,14 @@
"./src/**/*.ts",
"src/**/*.tsx",
"src/**/*.d.ts",
"./babel.config.js",
"babel.config.cjs",
"./jest.config.ts",
"./.eslintrc.js",
"./.eslintrc.cjs",
"./__mocks__",
"./conf/default.conf",
"./public",
"./commitlint.config.ts",
"./webpack.config.js",
"./webpack.config.prod.js",
"./vite.config.ts",
"./jest.setup.ts",
"./tests/**.ts",
"./**/*.d.ts",

129
frontend/vite.config.ts Normal file
View File

@@ -0,0 +1,129 @@
import { sentryVitePlugin } from '@sentry/vite-plugin';
import react from '@vitejs/plugin-react';
import { readFileSync } from 'fs';
import { resolve } from 'path';
import { visualizer } from 'rollup-plugin-visualizer';
import type { Plugin, UserConfig } from 'vite';
import { defineConfig, loadEnv } from 'vite';
import viteCompression from 'vite-plugin-compression';
import { createHtmlPlugin } from 'vite-plugin-html';
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer';
import tsconfigPaths from 'vite-tsconfig-paths';
function rawMarkdownPlugin(): Plugin {
return {
name: 'raw-markdown',
transform(_, id): any {
if (id.endsWith('.md')) {
const content = readFileSync(id, 'utf-8');
return {
code: `export default ${JSON.stringify(content)};`,
map: null,
};
}
return undefined;
},
};
}
export default defineConfig(
({ mode }): UserConfig => {
const env = loadEnv(mode, process.cwd(), '');
const plugins = [
tsconfigPaths(),
rawMarkdownPlugin(),
react(),
createHtmlPlugin({
inject: {
data: {
PYLON_APP_ID: env.VITE_PYLON_APP_ID || '',
APPCUES_APP_ID: env.VITE_APPCUES_APP_ID || '',
},
},
}),
];
if (env.VITE_SENTRY_AUTH_TOKEN) {
plugins.push(
sentryVitePlugin({
authToken: env.VITE_SENTRY_AUTH_TOKEN,
org: env.VITE_SENTRY_ORG,
project: env.VITE_SENTRY_PROJECT_ID,
}),
);
}
if (env.BUNDLE_ANALYSER === 'true') {
plugins.push(
visualizer({
open: true,
gzipSize: true,
brotliSize: true,
}),
);
}
if (env.NODE_ENV === 'production') {
plugins.push(
ViteImageOptimizer({
jpeg: { quality: 80 },
jpg: { quality: 80 },
}),
);
plugins.push(viteCompression());
}
return {
plugins,
resolve: {
alias: {
utils: resolve(__dirname, './src/utils'),
types: resolve(__dirname, './src/types'),
constants: resolve(__dirname, './src/constants'),
parser: resolve(__dirname, './src/parser'),
providers: resolve(__dirname, './src/providers'),
lib: resolve(__dirname, './src/lib'),
},
},
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true,
},
},
},
define: {
'process.env': JSON.stringify({
NODE_ENV: mode,
FRONTEND_API_ENDPOINT: env.VITE_FRONTEND_API_ENDPOINT,
WEBSOCKET_API_ENDPOINT: env.VITE_WEBSOCKET_API_ENDPOINT,
PYLON_APP_ID: env.VITE_PYLON_APP_ID,
PYLON_IDENTITY_SECRET: env.VITE_PYLON_IDENTITY_SECRET,
APPCUES_APP_ID: env.VITE_APPCUES_APP_ID,
POSTHOG_KEY: env.VITE_POSTHOG_KEY,
SENTRY_AUTH_TOKEN: env.VITE_SENTRY_AUTH_TOKEN,
SENTRY_ORG: env.VITE_SENTRY_ORG,
SENTRY_PROJECT_ID: env.VITE_SENTRY_PROJECT_ID,
SENTRY_DSN: env.VITE_SENTRY_DSN,
TUNNEL_URL: env.VITE_TUNNEL_URL,
TUNNEL_DOMAIN: env.VITE_TUNNEL_DOMAIN,
DOCS_BASE_URL: env.VITE_DOCS_BASE_URL,
}),
},
build: {
sourcemap: true,
outDir: 'build',
cssMinify: 'esbuild',
},
server: {
open: true,
port: 3301,
host: true,
},
preview: {
port: 3301,
},
};
},
);

View File

@@ -1,173 +0,0 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// shared config (dev and prod)
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { sentryWebpackPlugin } = require('@sentry/webpack-plugin');
const portFinderSync = require('portfinder-sync');
const dotenv = require('dotenv');
const webpack = require('webpack');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
dotenv.config();
console.log(resolve(__dirname, './src/'));
const cssLoader = 'css-loader';
const sassLoader = 'sass-loader';
const styleLoader = 'style-loader';
const plugins = [
new HtmlWebpackPlugin({
template: 'src/index.html.ejs',
PYLON_APP_ID: process.env.PYLON_APP_ID,
APPCUES_APP_ID: process.env.APPCUES_APP_ID,
POSTHOG_KEY: process.env.POSTHOG_KEY,
SENTRY_AUTH_TOKEN: process.env.SENTRY_AUTH_TOKEN,
SENTRY_ORG: process.env.SENTRY_ORG,
SENTRY_PROJECT_ID: process.env.SENTRY_PROJECT_ID,
SENTRY_DSN: process.env.SENTRY_DSN,
TUNNEL_URL: process.env.TUNNEL_URL,
TUNNEL_DOMAIN: process.env.TUNNEL_DOMAIN,
}),
new webpack.ProvidePlugin({
process: 'process/browser',
}),
new webpack.DefinePlugin({
'process.env': JSON.stringify({
NODE_ENV: process.env.NODE_ENV,
FRONTEND_API_ENDPOINT: process.env.FRONTEND_API_ENDPOINT,
WEBSOCKET_API_ENDPOINT: process.env.WEBSOCKET_API_ENDPOINT,
PYLON_APP_ID: process.env.PYLON_APP_ID,
PYLON_IDENTITY_SECRET: process.env.PYLON_IDENTITY_SECRET,
APPCUES_APP_ID: process.env.APPCUES_APP_ID,
POSTHOG_KEY: process.env.POSTHOG_KEY,
SENTRY_AUTH_TOKEN: process.env.SENTRY_AUTH_TOKEN,
SENTRY_ORG: process.env.SENTRY_ORG,
SENTRY_PROJECT_ID: process.env.SENTRY_PROJECT_ID,
SENTRY_DSN: process.env.SENTRY_DSN,
TUNNEL_URL: process.env.TUNNEL_URL,
TUNNEL_DOMAIN: process.env.TUNNEL_DOMAIN,
DOCS_BASE_URL: process.env.DOCS_BASE_URL,
}),
}),
sentryWebpackPlugin({
authToken: process.env.SENTRY_AUTH_TOKEN,
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT_ID,
}),
];
if (process.env.BUNDLE_ANALYSER === 'true') {
plugins.push(new BundleAnalyzerPlugin({ analyzerMode: 'server' }));
}
/**
* @type {import('webpack').Configuration}
*/
const config = {
mode: 'development',
devtool: 'source-map',
entry: resolve(__dirname, './src/index.tsx'),
devServer: {
historyApiFallback: {
disableDotRule: true,
},
open: true,
hot: true,
liveReload: true,
port: portFinderSync.getPort(3301),
static: {
directory: resolve(__dirname, 'public'),
publicPath: '/',
watch: true,
},
allowedHosts: 'all',
},
target: 'web',
output: {
path: resolve(__dirname, './build'),
publicPath: '/',
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
plugins: [new TsconfigPathsPlugin({})],
fallback: { 'process/browser': require.resolve('process/browser') },
},
module: {
rules: [
{
test: [/\.jsx?$/, /\.tsx?$/],
use: ['babel-loader'],
exclude: /node_modules/,
},
// Add a rule for Markdown files using raw-loader
{
test: /\.md$/,
use: 'raw-loader',
},
{
test: /\.css$/,
use: [
styleLoader,
{
loader: cssLoader,
options: {
modules: true,
},
},
],
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
type: 'asset',
},
{
test: /\.(ttf|eot|woff|woff2)$/,
use: ['file-loader'],
},
{
test: /\.less$/i,
use: [
{
loader: styleLoader,
},
{
loader: cssLoader,
options: {
modules: true,
},
},
{
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true,
},
},
},
],
},
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
styleLoader,
// Translates CSS into CommonJS
cssLoader,
// Compiles Sass to CSS
sassLoader,
],
},
],
},
plugins,
performance: {
hints: false,
},
optimization: {
minimize: false,
},
};
module.exports = config;

View File

@@ -1,256 +0,0 @@
/* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
// shared config (dev and prod)
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const { sentryWebpackPlugin } = require('@sentry/webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const dotenv = require('dotenv');
const webpack = require('webpack');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const { RetryChunkLoadPlugin } = require('webpack-retry-chunk-load-plugin');
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
dotenv.config();
const cssLoader = 'css-loader';
const sassLoader = 'sass-loader';
const styleLoader = 'style-loader';
const plugins = [
new HtmlWebpackPlugin({
template: 'src/index.html.ejs',
PYLON_APP_ID: process.env.PYLON_APP_ID,
APPCUES_APP_ID: process.env.APPCUES_APP_ID,
POSTHOG_KEY: process.env.POSTHOG_KEY,
SENTRY_AUTH_TOKEN: process.env.SENTRY_AUTH_TOKEN,
SENTRY_ORG: process.env.SENTRY_ORG,
SENTRY_PROJECT_ID: process.env.SENTRY_PROJECT_ID,
SENTRY_DSN: process.env.SENTRY_DSN,
TUNNEL_URL: process.env.TUNNEL_URL,
TUNNEL_DOMAIN: process.env.TUNNEL_DOMAIN,
}),
new CompressionPlugin({
exclude: /.map$/,
}),
new CopyPlugin({
patterns: [{ from: resolve(__dirname, 'public/'), to: '.' }],
}),
new webpack.ProvidePlugin({
process: 'process/browser',
}),
new webpack.DefinePlugin({
'process.env': JSON.stringify({
FRONTEND_API_ENDPOINT: process.env.FRONTEND_API_ENDPOINT,
WEBSOCKET_API_ENDPOINT: process.env.WEBSOCKET_API_ENDPOINT,
PYLON_APP_ID: process.env.PYLON_APP_ID,
PYLON_IDENTITY_SECRET: process.env.PYLON_IDENTITY_SECRET,
APPCUES_APP_ID: process.env.APPCUES_APP_ID,
POSTHOG_KEY: process.env.POSTHOG_KEY,
SENTRY_AUTH_TOKEN: process.env.SENTRY_AUTH_TOKEN,
SENTRY_ORG: process.env.SENTRY_ORG,
SENTRY_PROJECT_ID: process.env.SENTRY_PROJECT_ID,
SENTRY_DSN: process.env.SENTRY_DSN,
TUNNEL_URL: process.env.TUNNEL_URL,
TUNNEL_DOMAIN: process.env.TUNNEL_DOMAIN,
DOCS_BASE_URL: process.env.DOCS_BASE_URL,
}),
}),
new MiniCssExtractPlugin(),
sentryWebpackPlugin({
authToken: process.env.SENTRY_AUTH_TOKEN,
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT_ID,
}),
new RetryChunkLoadPlugin({
maxRetries: 2,
}),
];
if (process.env.BUNDLE_ANALYSER === 'true') {
plugins.push(new BundleAnalyzerPlugin({ analyzerMode: 'server' }));
}
const config = {
mode: 'production',
devtool: 'source-map',
entry: resolve(__dirname, './src/index.tsx'),
output: {
path: resolve(__dirname, './build'),
publicPath: '/',
filename: '[name].[contenthash].js',
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
plugins: [new TsconfigPathsPlugin({})],
fallback: { 'process/browser': require.resolve('process/browser') },
},
cache: {
type: 'filesystem',
allowCollectingMemory: true,
cacheDirectory: resolve(__dirname, '.temp_cache'),
buildDependencies: {
// This makes all dependencies of this file - build dependencies
config: [__filename],
// By default webpack and loaders are build dependencies
},
},
module: {
rules: [
{
test: [/\.jsx?$/, /\.tsx?$/],
use: ['babel-loader'],
exclude: /node_modules/,
},
{
test: /\.md$/,
use: 'raw-loader',
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: cssLoader,
options: {
modules: true,
},
},
],
},
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
styleLoader,
// Translates CSS into CommonJS
cssLoader,
// Compiles Sass to CSS
sassLoader,
],
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
type: 'asset',
},
{
test: /\.(ttf|eot|woff|woff2)$/,
use: ['file-loader'],
},
{
test: /\.less$/i,
use: [
{
loader: styleLoader,
},
{
loader: cssLoader,
options: {
modules: true,
},
},
{
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true,
},
},
},
],
},
],
},
plugins,
optimization: {
chunkIds: 'named',
concatenateModules: false,
emitOnErrors: true,
flagIncludedChunks: true,
innerGraph: true, // tells webpack whether to conduct inner graph analysis for unused exports.
mangleWasmImports: true,
mergeDuplicateChunks: true,
minimize: true,
nodeEnv: 'production',
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}`,
},
minimizer: [
new TerserPlugin({
parallel: true,
terserOptions: {
compress: true,
keep_classnames: true,
keep_fnames: false,
sourceMap: false,
safari10: true,
parse: {
html5_comments: false,
},
},
}),
new CssMinimizerPlugin(),
new ImageMinimizerPlugin({
minimizer: [
{
implementation: ImageMinimizerPlugin.sharpMinify,
options: {
encodeOptions: {
jpeg: {
quality: 80,
},
webp: {
lossless: true,
},
avif: {
lossless: true,
},
png: {},
gif: {},
},
},
},
{
implementation: ImageMinimizerPlugin.imageminMinify,
options: {
plugins: [
[
'svgo',
{
plugins: [
{
name: 'preset-default',
params: {
overrides: {
removeViewBox: false,
addAttributesToSVGElement: {
params: {
attributes: [{ xmlns: 'http://www.w3.org/2000/svg' }],
},
},
},
},
},
],
},
],
],
},
},
],
}),
],
},
performance: {
hints: 'warning',
},
};
module.exports = config;

File diff suppressed because it is too large Load Diff