Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui: Add a timezone parameter to Parca context #4549

Merged
merged 4 commits into from
Apr 25, 2024
Merged
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
4 changes: 2 additions & 2 deletions proto/buf.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ deps:
- remote: buf.build
owner: grpc-ecosystem
repository: grpc-gateway
commit: 7dec1bb6f79840c5849dac18f642de9c
digest: shake256:aa37e1bbccaf5793f1c82af9e620e67220f390dc5cbab2b8b3091aa4c030f32d9144be4dbfb8a90d02d44cd6b781875959ab1d454742ebd3d586b1a7806a07ea
commit: ca289928665845a7b2f7285d052c739a
digest: shake256:67b115260e12cb2d6c5d5ce8dbbf3a095c86f0e52b84f9dbd16dec9433b218f8694bc9aadb1d45eb6fd52f5a7029977d460e2d58afb3208ab6c680e7b21c80e4
Comment on lines 9 to +13
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this file was added by precommit automatically after my first commit. not sure why this happened.

2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"dependencies": {
"@parca/react-benchmark": "^5.3.0",
"command-line-args": "^5.2.1",
"date-fns": "2.30.0",
"date-fns": "3.6.0",
"not-a-log": "^1.0.1",
"react": "18.2.0",
"react-dom": "18.2.0",
Expand Down
6 changes: 6 additions & 0 deletions ui/packages/app/web/fork-ts-checker.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
logger: {
log: message => console.log(message),
error: message => console.error(message),
},
};
24 changes: 17 additions & 7 deletions ui/packages/shared/components/src/DateTimePicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {convertLocalToUTCDate, convertUTCToLocalDate} from '@parca/utilities';

import {AbsoluteDate} from '../DateTimeRangePicker/utils';
import Input from '../Input';
import {useParcaContext} from '../ParcaContext';

export const DATE_FORMAT = 'yyyy-MM-DD HH:mm:ss';

Expand All @@ -42,18 +43,19 @@ interface Props {
}

export const DateTimePicker = ({selected, onChange}: Props): JSX.Element => {
const {timezone} = useParcaContext();
const [referenceElement, setReferenceElement] = useState<HTMLDivElement | null>();
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>();
const {styles, attributes} = usePopper(referenceElement, popperElement, {
placement: 'bottom-end',
strategy: 'absolute',
});
const [textInput, setTextInput] = useState<string>(selected.getUIString());
const [textInput, setTextInput] = useState<string>(selected.getUIString(timezone));
const [isTextInputDirty, setIsTextInputDirty] = useState<boolean>(false);

useEffect(() => {
setTextInput(selected.getUIString());
}, [selected]);
setTextInput(selected.getUIString(timezone));
}, [selected, timezone]);

return (
<Popover>
Expand Down Expand Up @@ -83,10 +85,12 @@ export const DateTimePicker = ({selected, onChange}: Props): JSX.Element => {
}
const date = new Date(textInput);
if (isNaN(date.getTime())) {
setTextInput(selected.getUIString());
setTextInput(selected.getUIString(timezone));
return;
}
onChange(new AbsoluteDate(convertLocalToUTCDate(date)));
onChange(
new AbsoluteDate(timezone !== undefined ? date : convertLocalToUTCDate(date))
);
}}
onChange={e => {
setTextInput(e.target.value);
Expand All @@ -101,12 +105,18 @@ export const DateTimePicker = ({selected, onChange}: Props): JSX.Element => {
className="z-10"
>
<ReactDatePicker
selected={convertUTCToLocalDate(selected.getTime())}
selected={
timezone !== undefined
? selected.getTime()
: convertUTCToLocalDate(selected.getTime())
}
onChange={date => {
if (date == null) {
return;
}
onChange(new AbsoluteDate(convertLocalToUTCDate(date)));
onChange(
new AbsoluteDate(timezone !== undefined ? date : convertLocalToUTCDate(date))
);
setIsTextInputDirty(false);
}}
showTimeInput
Expand Down
15 changes: 14 additions & 1 deletion ui/packages/shared/components/src/DateTimeRangePicker/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,15 @@ export class AbsoluteDate implements BaseDate {
return this.value;
}

getUIString(): string {
getUIString(timezone?: string): string {
if (typeof this.value === 'string') {
return this.value;
}

if (timezone !== undefined) {
return getStringForDateInTimezone(this, timezone, DATE_FORMAT);
}

return getUtcStringForDate(this, DATE_FORMAT);
}

Expand Down Expand Up @@ -281,3 +286,11 @@ export const getUtcStringForDate = (date: AbsoluteDate, format = 'lll'): string
.utc()
.format(format);
};

export const getStringForDateInTimezone = (
date: AbsoluteDate,
timezone: string,
format = 'lll'
): string => {
return moment.tz(date.getTime().toISOString(), timezone).format(format);
};
1 change: 1 addition & 0 deletions ui/packages/shared/components/src/ParcaContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ interface Props {
profileViewExternalSubActions?: ReactNode;
sourceViewContextMenuItems?: SourceViewContextMenuItem[];
additionalFlamegraphColorProfiles?: Record<string, ColorConfig>;
timezone?: string;
}

export const defaultValue: Props = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ import type {VirtualElement} from '@popperjs/core';
import {usePopper} from 'react-popper';

import {Label} from '@parca/client';
import {TextWithTooltip} from '@parca/components';
import {formatDate, valueFormatter} from '@parca/utilities';
import {TextWithTooltip, useParcaContext} from '@parca/components';
import {formatDate, timePattern, valueFormatter} from '@parca/utilities';

import {HighlightedSeries} from '../';
import {timeFormat} from '../../';

interface Props {
x: number;
Expand Down Expand Up @@ -69,6 +68,8 @@ const MetricsTooltip = ({
sampleUnit,
delta,
}: Props): JSX.Element => {
const {timezone} = useParcaContext();

const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);

const {styles, attributes, ...popperProps} = usePopper(virtualElement, popperElement, {
Expand Down Expand Up @@ -154,7 +155,13 @@ const MetricsTooltip = ({
)}
<tr>
<td className="w-1/4">At</td>
<td className="w-3/4">{formatDate(highlighted.timestamp, timeFormat)}</td>
<td className="w-3/4">
{formatDate(
highlighted.timestamp,
timePattern(timezone as string),
timezone
)}
</td>
</tr>
</tbody>
</table>
Expand Down
5 changes: 3 additions & 2 deletions ui/packages/shared/profile/src/MetricsGraph/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import throttle from 'lodash.throttle';
import {useContextMenu} from 'react-contexify';

import {Label, MetricsSample, MetricsSeries as MetricsSeriesPb} from '@parca/client';
import {DateTimeRange} from '@parca/components';
import {DateTimeRange, useParcaContext} from '@parca/components';
import {
formatDate,
formatForTimespan,
Expand Down Expand Up @@ -132,6 +132,7 @@ export const RawMetricsGraph = ({
margin = 0,
sampleUnit,
}: Props): JSX.Element => {
const {timezone} = useParcaContext();
const graph = useRef(null);
const [dragging, setDragging] = useState(false);
const [hovering, setHovering] = useState(false);
Expand Down Expand Up @@ -537,7 +538,7 @@ export const RawMetricsGraph = ({
>
<line y2={6} className="stroke-gray-300 dark:stroke-gray-500" />
<text fill="currentColor" dy=".71em" y={9}>
{formatDate(d, formatForTimespan(from, to))}
{formatDate(d, formatForTimespan(from, to), timezone)}
</text>
</g>
<g key={`grid-${i}`}>
Expand Down
26 changes: 11 additions & 15 deletions ui/packages/shared/profile/src/ProfileSource.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ export interface ProfileSource {
QueryRequest: () => QueryRequest;
ProfileType: () => ProfileType;
DiffSelection: () => ProfileDiffSelection;
Describe: () => JSX.Element;
toString: () => string;
toString: (timezone?: string) => string;
}

export interface ProfileSelection {
Expand All @@ -37,8 +36,13 @@ export interface ProfileSelection {
ProfileSource: () => ProfileSource;
Type: () => string;
}
const timeFormat = (timezone?: string): string => {
if (timezone !== undefined) {
return 'yyyy-MM-dd HH:mm:ss';
}

export const timeFormat = "yyyy-MM-dd HH:mm:ss '(UTC)'";
return "yyyy-MM-dd HH:mm:ss '(UTC)'";
};

export function ParamsString(params: {[key: string]: string}): string {
return Object.keys(params)
Expand Down Expand Up @@ -229,25 +233,17 @@ export class MergedProfileSource implements ProfileSource {
return ProfileType.fromString(Query.parse(this.query.toString()).profileName());
}

Describe(): JSX.Element {
return (
<a>
Merge of &quot;{this.query.toString()}&quot; from {formatDate(this.mergeFrom, timeFormat)}{' '}
to {formatDate(this.mergeTo, timeFormat)}
</a>
);
}

stringMatchers(): string[] {
return this.query.matchers
.filter((m: Matcher) => m.key !== '__name__')
.map((m: Matcher) => `${m.key}=${m.value}`);
}

toString(): string {
toString(timezone?: string): string {
return `merged profiles of query "${this.query.toString()}" from ${formatDate(
this.mergeFrom,
timeFormat
)} to ${formatDate(this.mergeTo, timeFormat)}`;
timeFormat(timezone),
timezone
)} to ${formatDate(this.mergeTo, timeFormat(timezone), timezone)}`;
}
}
3 changes: 2 additions & 1 deletion ui/packages/shared/profile/src/ProfileView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export const ProfileView = ({
pprofDownloading,
compare,
}: ProfileViewProps): JSX.Element => {
const {timezone} = useParcaContext();
const {ref, dimensions} = useContainerDimensions();
const [curPath, setCurPath] = useState<string[]>([]);
const [rawDashboardItems = ['icicle'], setDashboardItems] = useURLState({
Expand Down Expand Up @@ -325,7 +326,7 @@ export const ProfileView = ({
};

// TODO: this is just a placeholder, we need to replace with an actually informative and accurate title (cc @metalmatze)
const profileSourceString = profileSource?.toString();
const profileSourceString = profileSource?.toString(timezone);
const hasProfileSource = profileSource !== undefined && profileSourceString !== '';
const headerParts = profileSourceString?.split('"') ?? [];

Expand Down
3 changes: 2 additions & 1 deletion ui/packages/shared/utilities/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"dependencies": {
"@parca/client": "^0.16.107",
"@rehooks/local-storage": "^2.4.4",
"tailwindcss": "3.2.4"
"tailwindcss": "3.2.4",
"date-fns-tz": "^3.1.3"
},
"keywords": [],
"author": "",
Expand Down
21 changes: 18 additions & 3 deletions ui/packages/shared/utilities/src/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import format from 'date-fns/format';
import * as DateFns from 'date-fns';
import {toZonedTime} from 'date-fns-tz';
import intervalToDuration from 'date-fns/intervalToDuration';

import {Duration} from '@parca/client';

export const timePattern = (timezone?: string): string => {
if (timezone !== undefined) {
return 'yyyy-MM-dd HH:mm:ss';
}

return "yyyy-MM-dd HH:mm:ss '(UTC)'";
};

export interface TimeObject {
nanos?: number;
micros?: number;
Expand Down Expand Up @@ -107,13 +116,19 @@ export const formatDuration = (timeObject: TimeObject, to?: number): string => {
return values.join(' ');
};

export const formatDate = (date: number | Date, timeFormat: string): string => {
export const formatDate = (date: number | Date, timeFormat: string, timezone?: string): string => {
if (typeof date === 'number') {
date = new Date(date);
}

const ISOString = date.toISOString().slice(0, -1);
return format(new Date(ISOString), timeFormat);

if (timezone !== undefined) {
const zonedDate = toZonedTime(date, timezone);
return DateFns.format(zonedDate, timeFormat);
}

return DateFns.format(new Date(ISOString), timeFormat);
};

export const formatForTimespan = (from: number, to: number): string => {
Expand Down
27 changes: 22 additions & 5 deletions ui/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1494,13 +1494,20 @@
resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310"
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==

"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.6", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.6", "@babel/runtime@^7.20.7", "@babel/runtime@^7.23.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
version "7.23.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885"
integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==
dependencies:
regenerator-runtime "^0.14.0"

"@babel/runtime@^7.21.0":
version "7.24.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd"
integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==
dependencies:
regenerator-runtime "^0.14.0"

"@babel/template@^7.18.6", "@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3":
version "7.24.0"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50"
Expand Down Expand Up @@ -10981,12 +10988,22 @@ data-view-byte-offset@^1.0.0:
es-errors "^1.3.0"
is-data-view "^1.0.1"

date-fns-tz@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-3.1.3.tgz#643dfc7157008a3873cd717973e4074bb802f962"
integrity sha512-ZfbMu+nbzW0mEzC8VZrLiSWvUIaI3aRHeq33mTe7Y38UctKukgqPR4nTDwcwS4d64Gf8GghnVsroBuMY3eiTeA==

date-fns@2.29.3:
version "2.29.3"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8"
integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==

date-fns@2.30.0, date-fns@^2.0.1, date-fns@^2.30.0:
date-fns@3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-3.6.0.tgz#f20ca4fe94f8b754951b24240676e8618c0206bf"
integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==

date-fns@^2.0.1, date-fns@^2.30.0:
version "2.30.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
Expand Down Expand Up @@ -23457,9 +23474,9 @@ regenerator-runtime@^0.11.0:
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==

regenerator-runtime@^0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45"
integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==
version "0.14.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==

regenerator-transform@^0.15.2:
version "0.15.2"
Expand Down
Loading