FrankChen021 commented on code in PR #19051:
URL: https://github.com/apache/druid/pull/19051#discussion_r3234378700
##########
web-console/src/dialogs/supervisor-table-action-dialog/supervisor-table-action-dialog.tsx:
##########
@@ -67,6 +69,16 @@ export const SupervisorTableActionDialog =
React.memo(function SupervisorTableAc
active: activeTab === 'history',
onClick: () => setActiveTab('history'),
},
+ ...(isCompactionSupervisor
Review Comment:
[P3] Hide the timeline tab for non-cascading compaction supervisors
This adds the Timeline tab for every supervisor ID that starts with
`autocompact__`, but the new endpoint returns 400 unless the compaction
supervisor template is `CascadingReindexingTemplate`. Existing inline-config
compaction supervisors also use `autocompact__` IDs, so standard compaction
supervisors now expose a tab that only shows an error. Gate the tab on the
loaded supervisor spec/template type, or render a deliberate unavailable state
instead of adding the tab solely from the ID prefix.
##########
web-console/src/components/reindexing-timeline/reindexing-timeline.tsx:
##########
@@ -0,0 +1,686 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import { Button, Callout, Card, Dialog, Intent, Tag, Tooltip } from
'@blueprintjs/core';
+import { IconNames } from '@blueprintjs/icons';
+import { Duration, Timezone } from 'chronoshift';
+import copy from 'copy-to-clipboard';
+import * as JSONBig from 'json-bigint-native';
+import React, { useState } from 'react';
+import AceEditor from 'react-ace';
+
+import { useQueryManager } from '../../hooks';
+import { Api, AppToaster } from '../../singletons';
+import { downloadFile } from '../../utils';
+import { Loader } from '../loader/loader';
+
+import './reindexing-timeline.scss';
+
+const TIMELINE_INTERVAL_COLORS = [
+ '#5C7080', // gray
+ '#738694', // light gray
+ '#8A9BA8', // lighter gray
+ '#394B59', // dark gray
+ '#4A5568', // medium dark gray
+ '#6B7E91', // medium gray
+ '#2F343C', // darker gray
+];
+
+const SKIPPED_INTERVAL_COLOR = 'rgba(219, 55, 55, 0.15)';
+const JSON_VIEWER_HEIGHT = '500px';
+
+function getIntervalColor(index: number): string {
+ return TIMELINE_INTERVAL_COLORS[index % TIMELINE_INTERVAL_COLORS.length];
+}
+
+interface ReindexingTimelineProps {
+ supervisorId: string;
+}
+
+interface GranularitySpec {
+ segmentGranularity?: string;
+ queryGranularity?: string;
+ rollup?: boolean;
+}
+
+interface CompactionConfig {
+ granularitySpec?: GranularitySpec;
+ metricsSpec?: Record<string, unknown>[];
+ dimensionsSpec?: {
+ dimensions?: Record<string, unknown>[];
+ };
+ projections?: Record<string, unknown>[];
+ transformSpec?: Record<string, unknown>;
+ tuningConfig?: Record<string, unknown>;
+}
+
+interface ReindexingRule {
+ type: string;
+ id?: string;
+ olderThan?: string;
+}
+
+interface IntervalConfig {
+ interval: string;
+ ruleCount: number;
+ config: CompactionConfig;
+ appliedRules: ReindexingRule[];
+}
+
+interface SkipOffsetInfo {
+ type: string;
+ period: string;
+ isApplied: boolean;
+ effectiveEndTime?: string;
+ reason?: string;
+}
+
+interface ValidationError {
+ errorType: string;
+ message: string;
+ olderInterval?: string;
+ olderGranularity?: string;
+ newerInterval?: string;
+ newerGranularity?: string;
+}
+
+interface ReindexingTimelineData {
+ dataSource: string;
+ referenceTime: string;
+ skipOffset?: SkipOffsetInfo;
+ intervals: IntervalConfig[];
+ validationError?: ValidationError;
+}
+
+export const ReindexingTimeline = React.memo(function ReindexingTimeline(
+ props: ReindexingTimelineProps,
+) {
+ const { supervisorId } = props;
+ const [selectedIntervalIndex, setSelectedIntervalIndex] = useState<number |
undefined>();
+ const [queriedMaxTime, setQueriedMaxTime] = useState<string | undefined>();
+ const [queryingMaxTime, setQueryingMaxTime] = useState(false);
+
+ const [timelineState] = useQueryManager<string, ReindexingTimelineData>({
+ query: supervisorId,
+ processQuery: async (supervisorId, signal) => {
+ const resp = await Api.instance.get<ReindexingTimelineData>(
+
`/druid/indexer/v1/supervisor/${Api.encodePath(supervisorId)}/reindexingTimeline`,
+ { signal },
+ );
+ return resp.data;
+ },
+ });
+
+ if (timelineState.loading) {
+ return <Loader />;
+ }
+
+ if (timelineState.error) {
+ return (
+ <div className="reindexing-timeline">
+ <Callout intent={Intent.DANGER} title="Error loading reindexing
timeline">
+ {timelineState.getErrorMessage()}
+ </Callout>
+ </div>
+ );
+ }
+
+ const timelineData = timelineState.data;
+ if (!timelineData) {
+ return null;
+ }
+
+ const { intervals, skipOffset, referenceTime, validationError } =
timelineData;
+
+ const handleQueryMaxTime = async () => {
+ setQueryingMaxTime(true);
+ try {
+ const query = {
+ queryType: 'timeBoundary',
+ dataSource: timelineData.dataSource,
+ };
+ const resp = await Api.instance.post('/druid/v2', query);
Review Comment:
[P2] Compute skipOffsetFromLatest from the supervisor timeline
The `Query latest timestamp` path bases the preview boundary on a broker
timeBoundary `maxTime`, then subtracts the period in the browser. The actual
cascading supervisor path applies `skipOffsetFromLatest` to the segment
timeline end and then truncates to an interval granularity-aligned boundary, so
row maxTime can be earlier than the segment end and straddling intervals are
handled differently. For normal DAY/HOUR segments this can show intervals as
skipped or active at the wrong boundary. Please derive the preview from segment
metadata/server-side timeline logic, or mirror the same segment-end and
granularity-alignment rules.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]