mirror of
https://github.com/nocodb/nocodb.git
synced 2026-06-02 01:42:15 +00:00
Merge pull request #13807 from nocodb/nc-feat/timeline-v2
Nc feat/timeline v2
This commit is contained in:
@@ -22,7 +22,6 @@ const [useProvideTimelineViewStore, useTimelineViewStore] = useInjectionState(
|
||||
dateRangeLabel: computed(() => ''),
|
||||
isPublic: ref(false),
|
||||
totalRecordCount: ref(0),
|
||||
recordsWithoutDates: ref(0),
|
||||
updateFormat: computed(() => ''),
|
||||
updateRowProperty: async (..._args: any[]) => {},
|
||||
loadTimelineData: async () => {},
|
||||
|
||||
@@ -679,8 +679,13 @@
|
||||
"day": "Day",
|
||||
"days": "Days",
|
||||
"week": "Week",
|
||||
"twoWeek": "2 Weeks",
|
||||
"month": "Month",
|
||||
"quarter": "Quarter",
|
||||
"sixMonth": "6 Months",
|
||||
"year": "Year",
|
||||
"twoYear": "2 Years",
|
||||
"fiveYear": "5 Years",
|
||||
"workspace": "Workspace",
|
||||
"workspaces": "Workspaces",
|
||||
"document": "Document",
|
||||
|
||||
@@ -1,24 +1,2 @@
|
||||
import type dayjs from 'dayjs'
|
||||
|
||||
export function getVisibleDates(..._args: any[]): dayjs.Dayjs[] {
|
||||
return []
|
||||
}
|
||||
|
||||
export function getBarPosition(..._args: any[]): number {
|
||||
return 0
|
||||
}
|
||||
|
||||
export function getBarWidth(..._args: any[]): number {
|
||||
return 0
|
||||
}
|
||||
|
||||
export function isToday(..._args: any[]): boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
export function isWeekend(..._args: any[]): boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
export const TIMELINE_GROUP_SIDEBAR_WIDTH = 200
|
||||
export const TIMELINE_GROUP_HEADER_HEIGHT = 32
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
GridViewColumn,
|
||||
KanbanView,
|
||||
KanbanViewColumn,
|
||||
TimelineRange,
|
||||
View,
|
||||
} from '~/models';
|
||||
import { MetaTable } from '~/cli';
|
||||
@@ -99,7 +100,7 @@ const getAst = async (
|
||||
};
|
||||
|
||||
let coverImageId;
|
||||
let dependencyFieldsForCalenderView;
|
||||
let dependencyFieldsForRangeView;
|
||||
let kanbanGroupColumnId;
|
||||
let sortColumnIds: string[] = [];
|
||||
let filterColumnIds: string[] = [];
|
||||
@@ -115,7 +116,20 @@ const getAst = async (
|
||||
// coverImageId = calendar.fk_cover_image_col_id;
|
||||
const calenderRanges = await CalendarRange.read(context, view.id);
|
||||
if (calenderRanges) {
|
||||
dependencyFieldsForCalenderView = calenderRanges.ranges
|
||||
dependencyFieldsForRangeView = calenderRanges.ranges
|
||||
.flatMap((obj) =>
|
||||
[obj.fk_from_column_id, (obj as any).fk_to_column_id].filter(Boolean),
|
||||
)
|
||||
.map(String);
|
||||
}
|
||||
} else if (view && view.type === ViewTypes.TIMELINE) {
|
||||
// Timeline date columns (start/end) drive the bar position. They are
|
||||
// typically hidden in the Fields menu, so without explicitly forcing
|
||||
// them through `allowedCols`, the data response would strip the values
|
||||
// and the frontend would treat every record as "without dates".
|
||||
const timelineRanges = await TimelineRange.read(context, view.id);
|
||||
if (timelineRanges) {
|
||||
dependencyFieldsForRangeView = timelineRanges.ranges
|
||||
.flatMap((obj) =>
|
||||
[obj.fk_from_column_id, (obj as any).fk_to_column_id].filter(Boolean),
|
||||
)
|
||||
@@ -192,14 +206,14 @@ const getAst = async (
|
||||
|
||||
if (extractOnlyRangeFields) {
|
||||
const ast: Ast = {
|
||||
...(dependencyFieldsForCalenderView || []).reduce((o, f) => {
|
||||
...(dependencyFieldsForRangeView || []).reduce((o, f) => {
|
||||
const col = model.columns.find((c) => c.id === f);
|
||||
return { ...o, [getFieldKey(col)]: 1 };
|
||||
}, {}),
|
||||
};
|
||||
|
||||
await Promise.all(
|
||||
(dependencyFieldsForCalenderView || []).map((f) =>
|
||||
(dependencyFieldsForRangeView || []).map((f) =>
|
||||
extractDependencies(
|
||||
context,
|
||||
model.columns.find((c) => c.id === f),
|
||||
@@ -244,8 +258,8 @@ const getAst = async (
|
||||
if (coverImageId) {
|
||||
allowedCols[coverImageId] = 1;
|
||||
}
|
||||
if (dependencyFieldsForCalenderView) {
|
||||
dependencyFieldsForCalenderView.forEach((id) => {
|
||||
if (dependencyFieldsForRangeView) {
|
||||
dependencyFieldsForRangeView.forEach((id) => {
|
||||
allowedCols[id] = 1;
|
||||
});
|
||||
}
|
||||
@@ -418,7 +432,7 @@ const getAst = async (
|
||||
(!isSystemColumn(col) ||
|
||||
(!view && isCreatedOrLastModifiedTimeCol(col)) ||
|
||||
view.show_system_fields ||
|
||||
(dependencyFieldsForCalenderView ?? []).includes(col.id) ||
|
||||
(dependencyFieldsForRangeView ?? []).includes(col.id) ||
|
||||
col.pv) &&
|
||||
(!fields?.length || isInFields) &&
|
||||
value;
|
||||
|
||||
@@ -2640,6 +2640,16 @@ export default class View implements ViewType {
|
||||
if (!calendarRangeColumns) break;
|
||||
if (calendarRangeColumns.includes(column.id)) {
|
||||
show = true;
|
||||
} else if (!copyFromView && !column.pv) {
|
||||
// Fresh timeline views default to a minimal visible set:
|
||||
// display value (pv) + the configured range columns. Other
|
||||
// fields stay hidden so the windowed-fetch payload is a few
|
||||
// fields × N records, not the entire row. Users can opt
|
||||
// additional fields into the bar via the Fields menu —
|
||||
// visibility is per-view-column, fully reversible. Skipped
|
||||
// when duplicating a view so the source's column choices
|
||||
// carry over.
|
||||
show = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ import type {
|
||||
LinkToAnotherRecordColumn,
|
||||
LookupColumn,
|
||||
RollupColumn,
|
||||
TimelineRange,
|
||||
TimelineView,
|
||||
} from '~/models';
|
||||
import type { NcContext } from '~/interface/config';
|
||||
import {
|
||||
@@ -74,7 +76,10 @@ export class PublicMetasService {
|
||||
// todo: return only required props
|
||||
view.password = undefined;
|
||||
|
||||
// Required for Calendar Views
|
||||
// Required for Calendar / Timeline views — the date columns that drive
|
||||
// the bar / event positions are usually hidden in the field menu, so the
|
||||
// visibility filter below would drop them from view.model.columns and
|
||||
// leave the shared frontend with no range columns to render.
|
||||
const rangeColumns = [];
|
||||
|
||||
if (view.type === ViewTypes.CALENDAR) {
|
||||
@@ -85,6 +90,14 @@ export class PublicMetasService {
|
||||
rangeColumns.push((c as any).fk_to_column_id);
|
||||
}
|
||||
}
|
||||
} else if (view.type === ViewTypes.TIMELINE) {
|
||||
// Timeline ranges can have both from and to date columns.
|
||||
const timelineRange = ((view.view as TimelineView)?.timeline_range ??
|
||||
[]) as TimelineRange[];
|
||||
for (const c of timelineRange) {
|
||||
if (c.fk_from_column_id) rangeColumns.push(c.fk_from_column_id);
|
||||
if (c.fk_to_column_id) rangeColumns.push(c.fk_to_column_id);
|
||||
}
|
||||
}
|
||||
|
||||
view.model.columns = view.columns
|
||||
|
||||
Reference in New Issue
Block a user