Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gen/proto/go/google/api/http.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions proto/buf.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ deps:
- remote: buf.build
owner: googleapis
repository: googleapis
commit: 004180b77378443887d3b55cabc00384
digest: shake256:d26c7c2fd95f0873761af33ca4a0c0d92c8577122b6feb74eb3b0a57ebe47a98ab24a209a0e91945ac4c77204e9da0c2de0020b2cedc27bdbcdea6c431eec69b
commit: 536964a08a534d51b8f30f2d6751f1f9
digest: shake256:b6d518a50df43704333587967830344b49247ac8cf0953847d710f2d72246f677aeba56593dcd78f9199afff8ae9498f8dd5efe54107e5a09c60fff872456ca9
- remote: buf.build
owner: grpc-ecosystem
repository: grpc-gateway
Expand Down
28 changes: 28 additions & 0 deletions ui/babel.react-compiler.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Shared Babel config for packages that need the React compiler.
// Used by shared packages to compile React components with the compiler plugin.
module.exports = {
ignore: [
'**/*.test.ts',
'**/*.test.tsx',
'**/*.benchmark.ts',
'**/*.benchmark.tsx',
'**/benchdata/**',
'**/testdata/**',
'**/.DS_Store',
'**/*.md',
],
presets: [
['@babel/preset-env', {modules: false}],
['@babel/preset-react', {runtime: 'automatic'}],
'@babel/preset-typescript',
],
plugins: [
[
'babel-plugin-react-compiler',
{
target: '18',
compilationMode: 'infer',
},
],
],
};
7 changes: 6 additions & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@
"tailwindcss": "3.2.4"
},
"devDependencies": {
"@babel/cli": "^7.28.6",
"@babel/core": "7.29.0",
"@babel/node": "7.29.0",
"@babel/plugin-proposal-export-default-from": "7.27.1",
"@babel/plugin-proposal-private-property-in-object": "7.21.11",
"@babel/preset-env": "7.29.2",
"@babel/preset-react": "^7.28.5",
"@babel/preset-typescript": "^7.28.5",
"@chromatic-com/storybook": "1.9.0",
"@ianvs/prettier-plugin-sort-imports": "3.7.2",
"@mdx-js/loader": "2.3.0",
Expand Down Expand Up @@ -65,6 +68,7 @@
"@typescript-eslint/eslint-plugin": "5.62.0",
"@typescript-eslint/parser": "5.62.0",
"arg": "5.0.2",
"babel-plugin-react-compiler": "1.0.0",
"chromatic": "11.29.0",
"css-loader": "6.11.0",
"eslint": "8.45.0",
Expand All @@ -78,7 +82,7 @@
"eslint-plugin-prettier": "5.5.5",
"eslint-plugin-promise": "6.6.0",
"eslint-plugin-react": "7.37.5",
"eslint-plugin-react-hooks": "4.6.2",
"eslint-plugin-react-hooks": "7.0.1",
"eslint-plugin-standard": "5.0.0",
"eslint-plugin-storybook": "0.12.0",
"eslint-plugin-typescript-enum": "2.1.0",
Expand All @@ -98,6 +102,7 @@
"postcss": "8.5.8",
"prettier": "3.8.1",
"prettier-plugin-tailwindcss": "^0.4.0",
"react-compiler-runtime": "1.0.0",
"react-is": "18.3.1",
"react-test-renderer": "18.3.1",
"replace-in-files": "3.0.0",
Expand Down
4 changes: 3 additions & 1 deletion ui/packages/app/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,14 @@
},
"devDependencies": {
"@types/lodash.throttle": "4.1.9",
"@vitejs/plugin-react-swc": "3.11.0",
"@vitejs/plugin-react": "4.7.0",
"babel-plugin-react-compiler": "1.0.0",
"css-loader": "6.11.0",
"eslint-config-prettier": "8.10.2",
"eslint-plugin-import": "2.32.0",
"jest": "29.7.0",
"jest-runtime": "29.7.0",
"react-compiler-runtime": "1.0.0",
"tslint": "6.1.3",
"tslint-config-prettier": "1.18.0",
"tslint-plugin-prettier": "2.3.0",
Expand Down
2 changes: 1 addition & 1 deletion ui/packages/app/web/src/components/ui/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const Navbar = () => {
const compareA = queryParams.get('compare_a');
const compareB = queryParams.get('compare_b');

const queryParamsURL = parseParams(window.location.search);
const queryParamsURL = parseParams(location.search);

/* eslint-disable @typescript-eslint/naming-convention */
const {
Expand Down
7 changes: 6 additions & 1 deletion ui/packages/app/web/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import {useCallback} from 'react';

import {GrpcWebFetchTransport} from '@protobuf-ts/grpcweb-transport';
import {useNavigate} from 'react-router-dom';
import {useLocation, useNavigate} from 'react-router-dom';

import {QueryServiceClient} from '@parca/client';
import {ParcaContextProvider, Spinner, URLStateProvider} from '@parca/components';
Expand All @@ -31,7 +31,12 @@ const queryClient = new QueryServiceClient(
);

const Profiles = () => {
'use no memo';
const navigate = useNavigate();
// useLocation() subscribes to react-router location changes so this component
// re-renders on navigate(). 'use no memo' ensures the re-render propagates to
// URLStateProvider, whose no-deps effect syncs state from window.location.search.
useLocation();
const isDarkMode = useAppSelector(selectDarkMode);

const navigateTo = useCallback(
Expand Down
21 changes: 18 additions & 3 deletions ui/packages/app/web/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,29 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import react from '@vitejs/plugin-react-swc';
import react from '@vitejs/plugin-react';
import {defineConfig} from 'vite';
import svgr from 'vite-plugin-svgr';

// https://vitejs.dev/config/
export default defineConfig({
// @ts-expect-error
plugins: [react(), svgr()],
// cast needed: dual @types/node versions create incompatible vite Plugin types
plugins: [
react({
babel: {
plugins: [
[
'babel-plugin-react-compiler',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if we should do this at the component packages level too? So that the benefits gets passed on to the downstream projects too.

Might have to change the lightweight tsc only build for those packages then.

Copy link
Copy Markdown
Contributor Author

@yomete yomete Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! Currently the shared packages all use tsc for builds, so the compiler only runs at the app level via Vite.

To enable it at the package level, we'd need to add Babel to the build pipeline for the React-heavy packages (components, profile, icons, hooks, dynamicsize).

I'll put up a follow-up PR for this, I want to keep this one focused on enabling the compiler at the app level and fixing the lint violations.

{
target: '18',
compilationMode: 'infer',
},
],
],
},
}),
svgr(),
] as any,
base: './',
server: {
port: 3000,
Expand Down
2 changes: 1 addition & 1 deletion ui/packages/shared/client/src/google/api/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// @generated from protobuf file "google/api/http.proto" (package "google.api", syntax proto3)
// tslint:disable
//
// Copyright 2025 Google LLC
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion ui/packages/shared/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"test": "jest --coverage --config ../../../jest.config.js ./src/*",
"prepublish": "pnpm run build",
"build": "tsc && tailwindcss -o dist/styles.css --minify",
"build": "babel src --out-dir dist --config-file ../../../babel.react-compiler.cjs --extensions .ts,.tsx --copy-files --no-copy-ignored && tsc --emitDeclarationOnly && tailwindcss -o dist/styles.css --minify",
"build-swc": "swc ./src -d dist --copy-files && tailwindcss -o dist/styles.css --minify",
"watch": "tsc-watch --onCompilationComplete 'tailwindcss -o dist/styles.css'"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2022 The Parca Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/* eslint-disable jest-dom/prefer-to-have-value */

import {render} from '@testing-library/react';
import {describe, expect, it, vi} from 'vitest';

import {AbsoluteDate, DateTimeRange} from '../utils';
import AbsoluteDatePicker from './index';

describe('AbsoluteDatePicker', () => {
it('resyncs when an existing DateTimeRange instance is mutated', () => {
const range = new DateTimeRange(
new AbsoluteDate(new Date('2023-12-01T10:00:00Z')),
new AbsoluteDate(new Date('2023-12-01T15:30:00Z'))
);

const {rerender, getAllByRole} = render(
<AbsoluteDatePicker range={range} onChange={vi.fn()} />
);

const [startInput, endInput] = getAllByRole('textbox');
expect((startInput as HTMLInputElement).value).toBe('2023-12-01 10:00:00');
expect((endInput as HTMLInputElement).value).toBe('2023-12-01 15:30:00');

range.from = new AbsoluteDate(new Date('2023-12-02T08:15:00Z'));
range.to = new AbsoluteDate(new Date('2023-12-02T09:45:00Z'));

rerender(<AbsoluteDatePicker range={range} onChange={vi.fn()} />);

expect((startInput as HTMLInputElement).value).toBe('2023-12-02 08:15:00');
expect((endInput as HTMLInputElement).value).toBe('2023-12-02 09:45:00');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import {useEffect, useMemo, useState} from 'react';
import {useState} from 'react';

import {DateTimePicker} from '../../DateTimePicker';
import {AbsoluteDate, DateTimeRange, RelativeDate, getHistoricalDate} from '../utils';
Expand All @@ -22,52 +22,24 @@ interface AbsoluteDatePickerProps {
}

const AbsoluteDatePicker = ({range, onChange}: AbsoluteDatePickerProps): JSX.Element => {
const dateFromInRelative = useMemo(() => range.from as RelativeDate, [range.from]);
const dateToInRelative = useMemo(() => range.to as RelativeDate, [range.to]);

const [from, setFrom] = useState<AbsoluteDate>(
range.from.isRelative()
? new AbsoluteDate(
getHistoricalDate({
unit: dateFromInRelative.unit,
value: dateFromInRelative.value,
})
)
: (range.from as AbsoluteDate)
);
const [to, setTo] = useState<AbsoluteDate>(
range.to.isRelative()
const toAbsolute = (d: RelativeDate | AbsoluteDate): AbsoluteDate =>
d.isRelative()
? new AbsoluteDate(
getHistoricalDate({
unit: dateToInRelative.unit,
value: dateToInRelative.value,
})
getHistoricalDate({unit: (d as RelativeDate).unit, value: (d as RelativeDate).value})
)
: (range.to as AbsoluteDate)
);
: (d as AbsoluteDate);

const [from, setFrom] = useState<AbsoluteDate>(() => toAbsolute(range.from));
const [to, setTo] = useState<AbsoluteDate>(() => toAbsolute(range.to));
const [prevRangeFrom, setPrevRangeFrom] = useState(range.from);
const [prevRangeTo, setPrevRangeTo] = useState(range.to);

useEffect(() => {
setFrom(
range.from.isRelative()
? new AbsoluteDate(
getHistoricalDate({
unit: dateFromInRelative.unit,
value: dateFromInRelative.value,
})
)
: (range.from as AbsoluteDate)
);
setTo(
range.to.isRelative()
? new AbsoluteDate(
getHistoricalDate({
unit: dateToInRelative.unit,
value: dateToInRelative.value,
})
)
: (range.to as AbsoluteDate)
);
}, [dateFromInRelative, dateToInRelative, range.from, range.to]);
if (prevRangeFrom !== range.from || prevRangeTo !== range.to) {
setPrevRangeFrom(range.from);
setPrevRangeTo(range.to);
setFrom(toAbsolute(range.from));
setTo(toAbsolute(range.to));
}

return (
<div className="flex flex-col w-[80%] mx-auto">
Expand Down
3 changes: 3 additions & 0 deletions ui/packages/shared/components/src/ResponsiveSvg/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.

/* eslint-disable react-hooks/set-state-in-effect */

import {Children, useEffect, useState} from 'react';

import {useContainerDimensions} from '@parca/hooks';

interface Props {
children: JSX.Element;
[x: string]: any;

Check warning on line 22 in ui/packages/shared/components/src/ResponsiveSvg/index.tsx

View workflow job for this annotation

GitHub Actions / UI Test and Lint

Unexpected any. Specify a different type
}

const addPropsToChildren = (children: JSX.Element, props: {[x: string]: any}): JSX.Element[] => {

Check warning on line 25 in ui/packages/shared/components/src/ResponsiveSvg/index.tsx

View workflow job for this annotation

GitHub Actions / UI Test and Lint

Unexpected any. Specify a different type
const addProps = (child: JSX.Element): JSX.Element => ({
...child,
props: {
Expand All @@ -33,6 +35,7 @@
};

const ResponsiveSvg = (props: Props): JSX.Element => {
'use no memo';
const {children} = props;
const {ref, dimensions} = useContainerDimensions();
const {width} = dimensions ?? {width: 0};
Expand Down
1 change: 1 addition & 0 deletions ui/packages/shared/components/src/Table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
enableHighlighting,
shouldHighlightRow,
rows,
}: RowRendererProps<any>): JSX.Element => {

Check warning on line 56 in ui/packages/shared/components/src/Table/index.tsx

View workflow job for this annotation

GitHub Actions / UI Test and Lint

Unexpected any. Specify a different type
return (
<tr
key={row.id}
Expand Down Expand Up @@ -139,6 +139,7 @@
scrollToIndex,
estimatedRowHeight = 26,
}: Props<T>): JSX.Element => {
'use no memo';
const [sorting, setSorting] = useState<SortingState>(initialSorting);
const tableContainerRef = useRef<HTMLDivElement>(null);
const scrollingRef = useRef<number>();
Expand Down
2 changes: 1 addition & 1 deletion ui/packages/shared/hooks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"test": "jest --coverage --config ../../../jest.config.js ./src/*",
"prepublish": "pnpm run build",
"build": "tsc",
"build": "babel src --out-dir dist --config-file ../../../babel.react-compiler.cjs --extensions .ts,.tsx --copy-files --no-copy-ignored && tsc --emitDeclarationOnly",
"build-swc": "swc ./src -d dist --copy-files",
"watch": "tsc-watch"
},
Expand Down
2 changes: 1 addition & 1 deletion ui/packages/shared/icons/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"test": "jest --coverage --config ../../../jest.config.js ./src/*",
"watch": "tsc-watch --onCompilationComplete 'pnpm run compileStaticFiles'",
"build-swc": "swc ./src -d dist --copy-files && pnpm run compileStaticFiles",
"build": "tsc && pnpm run compileStaticFiles",
"build": "babel src --out-dir dist --config-file ../../../babel.react-compiler.cjs --extensions .ts,.tsx --copy-files --no-copy-ignored && tsc --emitDeclarationOnly && pnpm run compileStaticFiles",
"compileStaticFiles": "tailwindcss -o dist/styles.css && mkdir -p ./dist/assets && cp ./src/assets/* ./dist/assets/"
},
"keywords": [],
Expand Down
2 changes: 1 addition & 1 deletion ui/packages/shared/profile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"scripts": {
"test": "jest --coverage --config ../../../jest.config.js ./src/*",
"prepublish": "pnpm run build",
"build": "tsc && pnpm run compile:styles",
"build": "babel src --out-dir dist --config-file ../../../babel.react-compiler.cjs --extensions .ts,.tsx --copy-files --no-copy-ignored && tsc --emitDeclarationOnly && pnpm run compile:styles",
"build-swc": "swc ./src -d dist --copy-files && pnpm run compile:styles",
"watch": "tsc-watch --onCompilationComplete 'pnpm run compile:styles'",
"compile:styles": "tailwindcss -o dist/styles.css --minify"
Expand Down
3 changes: 3 additions & 0 deletions ui/packages/shared/profile/src/GraphTooltipArrow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

/* eslint-disable react-hooks/refs */

import React, {useEffect, useState} from 'react';

import {flip, offset, shift, useFloating, type VirtualElement} from '@floating-ui/react';
Expand Down Expand Up @@ -39,6 +41,7 @@ function createPositionedVirtualElement(contextElement: Element, x = 0, y = 0):
}

const GraphTooltip = ({children, contextElement}: GraphTooltipProps): React.JSX.Element => {
'use no memo';
const [isPositioned, setIsPositioned] = useState(false);

const {refs, floatingStyles, update} = useFloating({
Expand Down
Loading
Loading