123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- import {useState} from 'react';
- import styled from '@emotion/styled';
- import {Button} from 'sentry/components/button';
- import ButtonBar from 'sentry/components/buttonBar';
- import SelectControl from 'sentry/components/forms/controls/selectControl';
- import InternalStatChart from 'sentry/components/internalStatChart';
- import LoadingError from 'sentry/components/loadingError';
- import LoadingIndicator from 'sentry/components/loadingIndicator';
- import Panel from 'sentry/components/panels/panel';
- import PanelBody from 'sentry/components/panels/panelBody';
- import PanelHeader from 'sentry/components/panels/panelHeader';
- import {t} from 'sentry/locale';
- import {useApiQuery} from 'sentry/utils/queryClient';
- const TIME_WINDOWS = ['1h', '1d', '1w'] as const;
- type TimeWindow = (typeof TIME_WINDOWS)[number];
- type State = {
- activeTask: string;
- resolution: string;
- since: number;
- timeWindow: TimeWindow;
- };
- export default function AdminQueue() {
- const [state, setState] = useState<State>({
- timeWindow: '1w',
- since: new Date().getTime() / 1000 - 3600 * 24 * 7,
- resolution: '1h',
- activeTask: '',
- });
- const {
- data: taskList,
- isLoading,
- isError,
- } = useApiQuery<string[]>(['/internal/queue/tasks/'], {
- staleTime: 0,
- });
- if (isError) {
- return <LoadingError />;
- }
- if (isLoading) {
- return <LoadingIndicator />;
- }
- const changeWindow = (timeWindow: TimeWindow) => {
- let seconds: number;
- if (timeWindow === '1h') {
- seconds = 3600;
- } else if (timeWindow === '1d') {
- seconds = 3600 * 24;
- } else if (timeWindow === '1w') {
- seconds = 3600 * 24 * 7;
- } else {
- throw new Error('Invalid time window');
- }
- setState(prevState => ({
- ...prevState,
- since: new Date().getTime() / 1000 - seconds,
- timeWindow,
- }));
- };
- const changeTask = (value: string) => {
- setState(prevState => ({...prevState, activeTask: value}));
- };
- const {activeTask} = state;
- return (
- <div>
- <Header>
- <h3>t{'Queue Overview'}</h3>
- <ButtonBar merged active={state.timeWindow}>
- {TIME_WINDOWS.map(r => (
- <Button size="sm" barId={r} onClick={() => changeWindow(r)} key={r}>
- {r}
- </Button>
- ))}
- </ButtonBar>
- </Header>
- <Panel>
- <PanelHeader>{t('Global Throughput')}</PanelHeader>
- <PanelBody withPadding>
- <InternalStatChart
- since={state.since}
- resolution={state.resolution}
- stat="jobs.all.started"
- label="jobs started"
- />
- </PanelBody>
- </Panel>
- <h3>t{'Task Details'}</h3>
- <div>
- <div className="m-b-1">
- <label>t{'Show details for task:'}</label>
- <SelectControl
- name="task"
- onChange={({value}) => changeTask(value)}
- value={activeTask}
- clearable
- options={taskList.map(value => ({value, label: value}))}
- />
- </div>
- {activeTask ? (
- <div>
- <Panel key={`jobs.started.${activeTask}`}>
- <PanelHeader>
- {t('Jobs Started')} <small>{activeTask}</small>
- </PanelHeader>
- <PanelBody withPadding>
- <InternalStatChart
- since={state.since}
- resolution={state.resolution}
- stat={`jobs.started.${activeTask}`}
- label="jobs"
- height={100}
- />
- </PanelBody>
- </Panel>
- <Panel key={`jobs.finished.${activeTask}`}>
- <PanelHeader>
- {t('Jobs Finished')} <small>{activeTask}</small>
- </PanelHeader>
- <PanelBody withPadding>
- <InternalStatChart
- since={state.since}
- resolution={state.resolution}
- stat={`jobs.finished.${activeTask}`}
- label="jobs"
- height={100}
- />
- </PanelBody>
- </Panel>
- </div>
- ) : null}
- </div>
- </div>
- );
- }
- const Header = styled('div')`
- display: flex;
- justify-content: space-between;
- align-items: center;
- `;
|