@oneuptime/common 10.0.29 → 10.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -47,8 +47,10 @@ import {
47
47
  getLogsAttributeColumnId,
48
48
  LogsSavedViewOption,
49
49
  LogsTableColumnOption,
50
+ LogsViewMode,
50
51
  normalizeLogsTableColumns,
51
52
  } from "./types";
53
+ import LogsAnalyticsView from "./components/LogsAnalyticsView";
52
54
  import { queryStringToFilter } from "../../../Types/Log/LogQueryToFilter";
53
55
  import RangeStartAndEndDateTime from "../../../Types/Time/RangeStartAndEndDateTime";
54
56
  import TimeRange from "../../../Types/Time/TimeRange";
@@ -95,11 +97,20 @@ export interface ComponentProps {
95
97
  onEditSavedView?: ((viewId: string) => void) | undefined;
96
98
  onDeleteSavedView?: ((viewId: string) => void) | undefined;
97
99
  onUpdateCurrentSavedView?: (() => void) | undefined;
100
+ viewMode?: LogsViewMode | undefined;
101
+ onViewModeChange?: ((mode: LogsViewMode) => void) | undefined;
102
+ analyticsServiceIds?: Array<string> | undefined;
103
+ analyticsAppliedFacetFilters?: Map<string, Set<string>> | undefined;
98
104
  }
99
105
 
100
106
  export type LogsSortField = LogsTableSortField;
101
107
  export type { LiveLogsOptions } from "./types";
102
- export type { HistogramBucket, FacetData, ActiveFilter } from "./types";
108
+ export type {
109
+ HistogramBucket,
110
+ FacetData,
111
+ ActiveFilter,
112
+ LogsViewMode,
113
+ } from "./types";
103
114
 
104
115
  const DEFAULT_PAGE_SIZE: number = 100;
105
116
  const PAGE_SIZE_OPTIONS: Array<number> = [100, 250, 500, 1000];
@@ -197,6 +208,9 @@ const LogsViewer: FunctionComponent<ComponentProps> = (
197
208
  Array<string>
198
209
  >(DEFAULT_LOGS_TABLE_COLUMNS);
199
210
 
211
+ const [internalViewMode, setInternalViewMode] =
212
+ useState<LogsViewMode>("list");
213
+
200
214
  useEffect(() => {
201
215
  setFilterData(props.filterData);
202
216
  }, [props.filterData]);
@@ -600,10 +614,24 @@ const LogsViewer: FunctionComponent<ComponentProps> = (
600
614
  return <ErrorMessage message={pageError} />;
601
615
  }
602
616
 
617
+ const currentViewMode: LogsViewMode = props.viewMode ?? internalViewMode;
618
+
619
+ const handleViewModeChange: (mode: LogsViewMode) => void = (
620
+ mode: LogsViewMode,
621
+ ): void => {
622
+ if (!props.viewMode) {
623
+ setInternalViewMode(mode);
624
+ }
625
+
626
+ props.onViewModeChange?.(mode);
627
+ };
628
+
603
629
  const toolbarProps: LogsViewerToolbarProps = {
604
630
  resultCount: totalItems,
605
631
  currentPage,
606
632
  totalPages,
633
+ viewMode: currentViewMode,
634
+ onViewModeChange: handleViewModeChange,
607
635
  savedViews: props.savedViews,
608
636
  selectedSavedViewId: props.selectedSavedViewId,
609
637
  onSavedViewSelect: props.onSavedViewSelect,
@@ -673,80 +701,89 @@ const LogsViewer: FunctionComponent<ComponentProps> = (
673
701
  />
674
702
  )}
675
703
 
676
- {/* Main content: sidebar + table */}
677
- <div className="flex gap-3">
678
- {showSidebar && props.facetData && (
679
- <LogsFacetSidebar
680
- facetData={props.facetData}
681
- isLoading={props.facetLoading || false}
682
- serviceMap={serviceMap}
683
- onIncludeFilter={props.onFacetInclude || (() => {})}
684
- onExcludeFilter={props.onFacetExclude || (() => {})}
685
- activeFilters={props.activeFilters}
686
- savedViews={props.savedViews}
687
- selectedSavedViewId={props.selectedSavedViewId}
688
- onSavedViewSelect={props.onSavedViewSelect}
689
- />
690
- )}
691
-
692
- <div className="min-w-0 flex-1">
693
- <div className="overflow-hidden rounded-lg border border-gray-200 bg-white shadow-sm">
694
- {!props.showFilters && (
695
- <div className="border-b border-gray-100 bg-gray-50/50 px-4 py-3">
696
- <LogsViewerToolbar {...toolbarProps} />
697
- </div>
698
- )}
699
-
700
- <LogsTable
701
- logs={displayedLogs}
704
+ {/* Main content: analytics view or sidebar + table */}
705
+ {currentViewMode === "analytics" ? (
706
+ <LogsAnalyticsView
707
+ timeRange={props.timeRange || { range: TimeRange.PAST_ONE_HOUR }}
708
+ serviceIds={props.analyticsServiceIds}
709
+ appliedFacetFilters={props.analyticsAppliedFacetFilters || new Map()}
710
+ logAttributes={logAttributes}
711
+ />
712
+ ) : (
713
+ <div className="flex gap-3">
714
+ {showSidebar && props.facetData && (
715
+ <LogsFacetSidebar
716
+ facetData={props.facetData}
717
+ isLoading={props.facetLoading || false}
702
718
  serviceMap={serviceMap}
703
- isLoading={props.isLoading}
704
- emptyMessage={
705
- props.noLogsMessage ||
706
- getEmptyMessageWithTimeRange(props.timeRange)
707
- }
708
- onRowClick={(_log: Log, rowId: string) => {
709
- setSelectedLogId((currentSelected: string | null) => {
710
- if (currentSelected === rowId) {
711
- return null;
712
- }
713
-
714
- return rowId;
715
- });
716
- }}
717
- selectedLogId={selectedLogId}
718
- sortField={sortField}
719
- sortOrder={sortOrder}
720
- onSortChange={handleSortChange}
721
- selectedColumns={selectedColumns}
722
- renderExpandedContent={(log: Log) => {
723
- return (
724
- <LogDetailsPanel
725
- log={log}
726
- serviceMap={serviceMap}
727
- onClose={() => {
728
- setSelectedLogId(null);
729
- }}
730
- getTraceRoute={props.getTraceRoute}
731
- getSpanRoute={props.getSpanRoute}
732
- variant="embedded"
733
- />
734
- );
735
- }}
736
- />
737
-
738
- <LogsPagination
739
- currentPage={currentPage}
740
- totalItems={totalItems}
741
- pageSize={pageSize}
742
- pageSizeOptions={PAGE_SIZE_OPTIONS}
743
- onPageChange={handlePageChange}
744
- onPageSizeChange={handlePageSizeChange}
745
- isDisabled={props.isLoading || totalItems === 0}
719
+ onIncludeFilter={props.onFacetInclude || (() => {})}
720
+ onExcludeFilter={props.onFacetExclude || (() => {})}
721
+ activeFilters={props.activeFilters}
722
+ savedViews={props.savedViews}
723
+ selectedSavedViewId={props.selectedSavedViewId}
724
+ onSavedViewSelect={props.onSavedViewSelect}
746
725
  />
726
+ )}
727
+
728
+ <div className="min-w-0 flex-1">
729
+ <div className="overflow-hidden rounded-lg border border-gray-200 bg-white shadow-sm">
730
+ {!props.showFilters && (
731
+ <div className="border-b border-gray-100 bg-gray-50/50 px-4 py-3">
732
+ <LogsViewerToolbar {...toolbarProps} />
733
+ </div>
734
+ )}
735
+
736
+ <LogsTable
737
+ logs={displayedLogs}
738
+ serviceMap={serviceMap}
739
+ isLoading={props.isLoading}
740
+ emptyMessage={
741
+ props.noLogsMessage ||
742
+ getEmptyMessageWithTimeRange(props.timeRange)
743
+ }
744
+ onRowClick={(_log: Log, rowId: string) => {
745
+ setSelectedLogId((currentSelected: string | null) => {
746
+ if (currentSelected === rowId) {
747
+ return null;
748
+ }
749
+
750
+ return rowId;
751
+ });
752
+ }}
753
+ selectedLogId={selectedLogId}
754
+ sortField={sortField}
755
+ sortOrder={sortOrder}
756
+ onSortChange={handleSortChange}
757
+ selectedColumns={selectedColumns}
758
+ renderExpandedContent={(log: Log) => {
759
+ return (
760
+ <LogDetailsPanel
761
+ log={log}
762
+ serviceMap={serviceMap}
763
+ onClose={() => {
764
+ setSelectedLogId(null);
765
+ }}
766
+ getTraceRoute={props.getTraceRoute}
767
+ getSpanRoute={props.getSpanRoute}
768
+ variant="embedded"
769
+ />
770
+ );
771
+ }}
772
+ />
773
+
774
+ <LogsPagination
775
+ currentPage={currentPage}
776
+ totalItems={totalItems}
777
+ pageSize={pageSize}
778
+ pageSizeOptions={PAGE_SIZE_OPTIONS}
779
+ onPageChange={handlePageChange}
780
+ onPageSizeChange={handlePageSizeChange}
781
+ isDisabled={props.isLoading || totalItems === 0}
782
+ />
783
+ </div>
747
784
  </div>
748
785
  </div>
749
- </div>
786
+ )}
750
787
  </div>
751
788
  );
752
789
  };