Skip to content

Commit 19bc2c5

Browse files
authored
feat(issue-details): Store stack trace display options (#83552)
this pr allows for the stack trace display options to be remembered so that users previous settings will be remembered, the next time they visit issue details .
1 parent bfc7d27 commit 19bc2c5

File tree

2 files changed

+41
-23
lines changed

2 files changed

+41
-23
lines changed

static/app/components/events/interfaces/threads.spec.tsx

+6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import ConfigStore from 'sentry/stores/configStore';
1515
import ProjectsStore from 'sentry/stores/projectsStore';
1616
import type {Event} from 'sentry/types/event';
1717
import {EntryType, EventOrGroupType} from 'sentry/types/event';
18+
import localStorage from 'sentry/utils/localStorage';
1819

1920
describe('Threads', function () {
2021
const organization = OrganizationFixture();
@@ -39,6 +40,11 @@ describe('Threads', function () {
3940
});
4041
ProjectsStore.loadInitialData([project]);
4142
ConfigStore.set('user', UserFixture());
43+
44+
localStorage.setItem(
45+
`issue-details-stracktrace-display-${organization.slug}-${project.slug}`,
46+
JSON.stringify([])
47+
);
4248
});
4349

4450
describe('non native platform', function () {

static/app/components/events/traceEventDataSection.tsx

+35-23
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type {PlatformKey, Project} from 'sentry/types/project';
1414
import {trackAnalytics} from 'sentry/utils/analytics';
1515
import {isMobilePlatform, isNativePlatform} from 'sentry/utils/platform';
1616
import useApi from 'sentry/utils/useApi';
17+
import {useLocalStorageState} from 'sentry/utils/useLocalStorageState';
1718
import useOrganization from 'sentry/utils/useOrganization';
1819
import {InterimSection} from 'sentry/views/issueDetails/streamline/interimSection';
1920
import {useHasStreamlinedUI} from 'sentry/views/issueDetails/utils';
@@ -32,12 +33,14 @@ export const displayOptions = {
3233
};
3334

3435
type State = {
35-
display: Array<keyof typeof displayOptions>;
3636
fullStackTrace: boolean;
3737
sortBy: keyof typeof sortByOptions;
3838
};
3939

40-
type ChildProps = Omit<State, 'sortBy'> & {recentFirst: boolean};
40+
type ChildProps = Omit<State, 'sortBy'> & {
41+
display: Array<keyof typeof displayOptions>;
42+
recentFirst: boolean;
43+
};
4144

4245
type Props = {
4346
children: (childProps: ChildProps) => React.ReactNode;
@@ -87,9 +90,13 @@ export function TraceEventDataSection({
8790
const [state, setState] = useState<State>({
8891
sortBy: recentFirst ? 'recent-first' : 'recent-last',
8992
fullStackTrace: !hasAppOnlyFrames ? true : fullStackTrace,
90-
display: [],
9193
});
9294

95+
const [display, setDisplay] = useLocalStorageState<Array<keyof typeof displayOptions>>(
96+
`issue-details-stracktrace-display-${organization.slug}-${projectSlug}`,
97+
[]
98+
);
99+
93100
const isMobile = isMobilePlatform(platform);
94101

95102
const handleFilterFramesChange = useCallback(
@@ -144,7 +151,7 @@ export function TraceEventDataSection({
144151
is_mobile: isMobile,
145152
checked: true,
146153
});
147-
} else if (state.display.includes('raw-stack-trace')) {
154+
} else if (display.includes('raw-stack-trace')) {
148155
trackAnalytics('stack-trace.display_option_raw_stack_trace_clicked', {
149156
organization,
150157
project_slug: projectSlug,
@@ -162,7 +169,7 @@ export function TraceEventDataSection({
162169
is_mobile: isMobile,
163170
checked: true,
164171
});
165-
} else if (state.display.includes('absolute-addresses')) {
172+
} else if (display.includes('absolute-addresses')) {
166173
trackAnalytics('stack-trace.display_option_absolute_addresses_clicked', {
167174
organization,
168175
project_slug: projectSlug,
@@ -180,7 +187,7 @@ export function TraceEventDataSection({
180187
is_mobile: isMobile,
181188
checked: true,
182189
});
183-
} else if (state.display.includes('absolute-file-paths')) {
190+
} else if (display.includes('absolute-file-paths')) {
184191
trackAnalytics('stack-trace.display_option_absolute_file_paths_clicked', {
185192
organization,
186193
project_slug: projectSlug,
@@ -203,7 +210,7 @@ export function TraceEventDataSection({
203210
checked: true,
204211
}
205212
);
206-
} else if (state.display.includes('minified')) {
213+
} else if (display.includes('minified')) {
207214
trackAnalytics(
208215
platform.startsWith('javascript')
209216
? 'stack-trace.display_option_minified_clicked'
@@ -226,7 +233,7 @@ export function TraceEventDataSection({
226233
is_mobile: isMobile,
227234
checked: true,
228235
});
229-
} else if (state.display.includes('verbose-function-names')) {
236+
} else if (display.includes('verbose-function-names')) {
230237
trackAnalytics('stack-trace.display_option_verbose_function_names_clicked', {
231238
organization,
232239
project_slug: projectSlug,
@@ -236,9 +243,9 @@ export function TraceEventDataSection({
236243
});
237244
}
238245

239-
setState(currentState => ({...currentState, display: vals}));
246+
setDisplay(vals);
240247
},
241-
[organization, platform, projectSlug, isMobile, state]
248+
[organization, platform, projectSlug, isMobile, display, setDisplay]
242249
);
243250

244251
function getDisplayOptions(): {
@@ -257,8 +264,8 @@ export function TraceEventDataSection({
257264
{
258265
label: displayOptions['absolute-addresses'],
259266
value: 'absolute-addresses',
260-
disabled: state.display.includes('raw-stack-trace') || !hasAbsoluteAddresses,
261-
tooltip: state.display.includes('raw-stack-trace')
267+
disabled: display.includes('raw-stack-trace') || !hasAbsoluteAddresses,
268+
tooltip: display.includes('raw-stack-trace')
262269
? t('Not available on raw stack trace')
263270
: !hasAbsoluteAddresses
264271
? t('Absolute addresses not available')
@@ -267,8 +274,8 @@ export function TraceEventDataSection({
267274
{
268275
label: displayOptions['absolute-file-paths'],
269276
value: 'absolute-file-paths',
270-
disabled: state.display.includes('raw-stack-trace') || !hasAbsoluteFilePaths,
271-
tooltip: state.display.includes('raw-stack-trace')
277+
disabled: display.includes('raw-stack-trace') || !hasAbsoluteFilePaths,
278+
tooltip: display.includes('raw-stack-trace')
272279
? t('Not available on raw stack trace')
273280
: !hasAbsoluteFilePaths
274281
? t('Absolute file paths not available')
@@ -287,8 +294,8 @@ export function TraceEventDataSection({
287294
{
288295
label: displayOptions['verbose-function-names'],
289296
value: 'verbose-function-names',
290-
disabled: state.display.includes('raw-stack-trace') || !hasVerboseFunctionNames,
291-
tooltip: state.display.includes('raw-stack-trace')
297+
disabled: display.includes('raw-stack-trace') || !hasVerboseFunctionNames,
298+
tooltip: display.includes('raw-stack-trace')
292299
? t('Not available on raw stack trace')
293300
: !hasVerboseFunctionNames
294301
? t('Verbose function names not available')
@@ -337,26 +344,31 @@ export function TraceEventDataSection({
337344
}
338345

339346
const nativePlatform = isNativePlatform(platform);
340-
const minified = state.display.includes('minified');
347+
const minified = display.includes('minified');
341348

342349
// Apple crash report endpoint
343350
const appleCrashEndpoint = `/projects/${organization.slug}/${projectSlug}/events/${eventId}/apple-crash-report?minified=${minified}`;
344351
const rawStackTraceDownloadLink = `${api.baseUrl}${appleCrashEndpoint}&download=1`;
345352

346353
const sortByTooltip = !hasNewestFirst
347354
? t('Not available on stack trace with single frame')
348-
: state.display.includes('raw-stack-trace')
355+
: display.includes('raw-stack-trace')
349356
? t('Not available on raw stack trace')
350357
: undefined;
351358

352359
const childProps = {
353360
recentFirst: state.sortBy === 'recent-first',
354-
display: state.display,
361+
display,
355362
fullStackTrace: state.fullStackTrace,
356363
};
357364

358365
const SectionComponent = isNestedSection ? InlineThreadSection : InterimSection;
359366

367+
const optionsToShow = getDisplayOptions();
368+
const displayValues = display.filter(value =>
369+
optionsToShow.some(opt => opt.value === value && !opt.disabled)
370+
);
371+
360372
return (
361373
<SectionComponent
362374
type={type}
@@ -365,7 +377,7 @@ export function TraceEventDataSection({
365377
actions={
366378
!stackTraceNotFound && (
367379
<ButtonBar gap={1}>
368-
{!state.display.includes('raw-stack-trace') && (
380+
{!display.includes('raw-stack-trace') && (
369381
<Tooltip
370382
title={t('Only full version available')}
371383
disabled={hasAppOnlyFrames}
@@ -385,7 +397,7 @@ export function TraceEventDataSection({
385397
</SegmentedControl>
386398
</Tooltip>
387399
)}
388-
{state.display.includes('raw-stack-trace') && nativePlatform && (
400+
{display.includes('raw-stack-trace') && nativePlatform && (
389401
<LinkButton
390402
size="xs"
391403
href={rawStackTraceDownloadLink}
@@ -429,9 +441,9 @@ export function TraceEventDataSection({
429441
multiple
430442
triggerLabel=""
431443
position="bottom-end"
432-
value={state.display}
444+
value={displayValues}
433445
onChange={opts => handleDisplayChange(opts.map(opt => opt.value))}
434-
options={[{label: t('Display'), options: getDisplayOptions()}]}
446+
options={[{label: t('Display'), options: optionsToShow}]}
435447
/>
436448
</ButtonBar>
437449
)

0 commit comments

Comments
 (0)