diff --git a/api/v2/memo_service.go b/api/v2/memo_service.go index d95d4cc2..57dfa4e4 100644 --- a/api/v2/memo_service.go +++ b/api/v2/memo_service.go @@ -105,11 +105,27 @@ func (s *APIV2Service) ListMemos(ctx context.Context, request *apiv2pb.ListMemos if filter.OrderByPinned { memoFind.OrderByPinned = filter.OrderByPinned } - if filter.CreatedTsBefore != nil { - memoFind.CreatedTsBefore = filter.CreatedTsBefore + if filter.DisplayTimeAfter != nil { + displayWithUpdatedTs, err := s.getMemoDisplayWithUpdatedTsSettingValue(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed to get memo display with updated ts setting value") + } + if displayWithUpdatedTs { + memoFind.UpdatedTsAfter = filter.DisplayTimeAfter + } else { + memoFind.CreatedTsAfter = filter.DisplayTimeAfter + } } - if filter.CreatedTsAfter != nil { - memoFind.CreatedTsAfter = filter.CreatedTsAfter + if filter.DisplayTimeBefore != nil { + displayWithUpdatedTs, err := s.getMemoDisplayWithUpdatedTsSettingValue(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed to get memo display with updated ts setting value") + } + if displayWithUpdatedTs { + memoFind.UpdatedTsBefore = filter.DisplayTimeBefore + } else { + memoFind.CreatedTsBefore = filter.DisplayTimeBefore + } } if filter.Creator != nil { username, err := ExtractUsernameFromName(*filter.Creator) @@ -463,11 +479,27 @@ func (s *APIV2Service) GetUserMemosStats(ctx context.Context, request *apiv2pb.G if filter.OrderByPinned { memoFind.OrderByPinned = filter.OrderByPinned } - if filter.CreatedTsBefore != nil { - memoFind.CreatedTsBefore = filter.CreatedTsBefore + if filter.DisplayTimeAfter != nil { + displayWithUpdatedTs, err := s.getMemoDisplayWithUpdatedTsSettingValue(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed to get memo display with updated ts setting value") + } + if displayWithUpdatedTs { + memoFind.UpdatedTsAfter = filter.DisplayTimeAfter + } else { + memoFind.CreatedTsAfter = filter.DisplayTimeAfter + } } - if filter.CreatedTsAfter != nil { - memoFind.CreatedTsAfter = filter.CreatedTsAfter + if filter.DisplayTimeBefore != nil { + displayWithUpdatedTs, err := s.getMemoDisplayWithUpdatedTsSettingValue(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed to get memo display with updated ts setting value") + } + if displayWithUpdatedTs { + memoFind.UpdatedTsBefore = filter.DisplayTimeBefore + } else { + memoFind.CreatedTsBefore = filter.DisplayTimeBefore + } } if filter.RowStatus != nil { memoFind.RowStatus = filter.RowStatus @@ -590,20 +622,20 @@ var ListMemosFilterCELAttributes = []cel.EnvOption{ cel.Variable("content_search", cel.ListType(cel.StringType)), cel.Variable("visibilities", cel.ListType(cel.StringType)), cel.Variable("order_by_pinned", cel.BoolType), - cel.Variable("created_ts_before", cel.IntType), - cel.Variable("created_ts_after", cel.IntType), + cel.Variable("display_time_before", cel.IntType), + cel.Variable("display_time_after", cel.IntType), cel.Variable("creator", cel.StringType), cel.Variable("row_status", cel.StringType), } type ListMemosFilter struct { - ContentSearch []string - Visibilities []store.Visibility - OrderByPinned bool - CreatedTsBefore *int64 - CreatedTsAfter *int64 - Creator *string - RowStatus *store.RowStatus + ContentSearch []string + Visibilities []store.Visibility + OrderByPinned bool + DisplayTimeBefore *int64 + DisplayTimeAfter *int64 + Creator *string + RowStatus *store.RowStatus } func parseListMemosFilter(expression string) (*ListMemosFilter, error) { @@ -646,12 +678,12 @@ func findField(callExpr *expr.Expr_Call, filter *ListMemosFilter) { } else if idExpr.Name == "order_by_pinned" { value := callExpr.Args[1].GetConstExpr().GetBoolValue() filter.OrderByPinned = value - } else if idExpr.Name == "created_ts_before" { - createdTsBefore := callExpr.Args[1].GetConstExpr().GetInt64Value() - filter.CreatedTsBefore = &createdTsBefore - } else if idExpr.Name == "created_ts_after" { - createdTsAfter := callExpr.Args[1].GetConstExpr().GetInt64Value() - filter.CreatedTsAfter = &createdTsAfter + } else if idExpr.Name == "display_time_before" { + displayTimeBefore := callExpr.Args[1].GetConstExpr().GetInt64Value() + filter.DisplayTimeBefore = &displayTimeBefore + } else if idExpr.Name == "display_time_after" { + displayTimeAfter := callExpr.Args[1].GetConstExpr().GetInt64Value() + filter.DisplayTimeAfter = &displayTimeAfter } else if idExpr.Name == "creator" { creator := callExpr.Args[1].GetConstExpr().GetStringValue() filter.Creator = &creator diff --git a/store/db/mysql/memo.go b/store/db/mysql/memo.go index d43c9076..7b14686d 100644 --- a/store/db/mysql/memo.go +++ b/store/db/mysql/memo.go @@ -55,6 +55,12 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo if v := find.CreatedTsAfter; v != nil { where, args = append(where, "UNIX_TIMESTAMP(`memo`.`created_ts`) > ?"), append(args, *v) } + if v := find.UpdatedTsBefore; v != nil { + where, args = append(where, "UNIX_TIMESTAMP(`memo`.`updated_ts`) < ?"), append(args, *v) + } + if v := find.UpdatedTsAfter; v != nil { + where, args = append(where, "UNIX_TIMESTAMP(`memo`.`updated_ts`) > ?"), append(args, *v) + } if v := find.ContentSearch; len(v) != 0 { for _, s := range v { where, args = append(where, "`memo`.`content` LIKE ?"), append(args, "%"+s+"%") diff --git a/store/db/postgres/memo.go b/store/db/postgres/memo.go index bb9e9390..f363818f 100644 --- a/store/db/postgres/memo.go +++ b/store/db/postgres/memo.go @@ -46,6 +46,12 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo if v := find.CreatedTsAfter; v != nil { where, args = append(where, "memo.created_ts > "+placeholder(len(args)+1)), append(args, *v) } + if v := find.UpdatedTsBefore; v != nil { + where, args = append(where, "memo.updated_ts < "+placeholder(len(args)+1)), append(args, *v) + } + if v := find.UpdatedTsAfter; v != nil { + where, args = append(where, "memo.updated_ts > "+placeholder(len(args)+1)), append(args, *v) + } if v := find.ContentSearch; len(v) != 0 { for _, s := range v { where, args = append(where, "memo.content LIKE "+placeholder(len(args)+1)), append(args, fmt.Sprintf("%%%s%%", s)) diff --git a/store/db/sqlite/memo.go b/store/db/sqlite/memo.go index f39f6f17..fb1d8bf6 100644 --- a/store/db/sqlite/memo.go +++ b/store/db/sqlite/memo.go @@ -45,6 +45,12 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo if v := find.CreatedTsAfter; v != nil { where, args = append(where, "memo.created_ts > ?"), append(args, *v) } + if v := find.UpdatedTsBefore; v != nil { + where, args = append(where, "memo.updated_ts < ?"), append(args, *v) + } + if v := find.UpdatedTsAfter; v != nil { + where, args = append(where, "memo.updated_ts > ?"), append(args, *v) + } if v := find.ContentSearch; len(v) != 0 { for _, s := range v { where, args = append(where, "memo.content LIKE ?"), append(args, fmt.Sprintf("%%%s%%", s)) diff --git a/store/memo.go b/store/memo.go index 9307d846..b59ce843 100644 --- a/store/memo.go +++ b/store/memo.go @@ -54,6 +54,8 @@ type FindMemo struct { CreatorID *int32 CreatedTsAfter *int64 CreatedTsBefore *int64 + UpdatedTsAfter *int64 + UpdatedTsBefore *int64 // Domain specific fields ContentSearch []string diff --git a/web/src/components/ActivityCalendar.tsx b/web/src/components/ActivityCalendar.tsx index 6f9d24f8..585259e7 100644 --- a/web/src/components/ActivityCalendar.tsx +++ b/web/src/components/ActivityCalendar.tsx @@ -6,6 +6,7 @@ interface Props { // Format: 2021-1 month: string; data: Record; + onClick?: (date: string) => void; } const getBgColor = (count: number, maxCount: number) => { @@ -26,7 +27,7 @@ const getBgColor = (count: number, maxCount: number) => { }; const ActivityCalendar = (props: Props) => { - const { month: monthStr, data } = props; + const { month: monthStr, data, onClick } = props; const year = new Date(monthStr).getFullYear(); const month = new Date(monthStr).getMonth() + 1; const dayInMonth = new Date(year, month, 0).getDate(); @@ -60,6 +61,7 @@ const ActivityCalendar = (props: Props) => { getBgColor(count, maxCount), isToday && "border-gray-600 dark:!border-gray-400" )} + onClick={() => count && onClick && onClick(date)} > ) : ( diff --git a/web/src/pages/Timeline.tsx b/web/src/pages/Timeline.tsx index a560c3c5..91dc539b 100644 --- a/web/src/pages/Timeline.tsx +++ b/web/src/pages/Timeline.tsx @@ -10,7 +10,7 @@ import MemoFilter from "@/components/MemoFilter"; import MemoView from "@/components/MemoView"; import MobileHeader from "@/components/MobileHeader"; import { memoServiceClient } from "@/grpcweb"; -import { DEFAULT_MEMO_LIMIT } from "@/helpers/consts"; +import { DAILY_TIMESTAMP, DEFAULT_MEMO_LIMIT } from "@/helpers/consts"; import { getNormalizedTimeString, getTimeStampByDate } from "@/helpers/datetime"; import useCurrentUser from "@/hooks/useCurrentUser"; import useResponsiveWidth from "@/hooks/useResponsiveWidth"; @@ -52,6 +52,7 @@ const Timeline = () => { const memoList = useMemoList(); const filterStore = useFilterStore(); const [activityStats, setActivityStats] = useState>({}); + const [selectedDay, setSelectedDay] = useState(); const [isRequesting, setIsRequesting] = useState(true); const [isComplete, setIsComplete] = useState(false); const { tag: tagQuery, text: textQuery } = filterStore.state; @@ -61,7 +62,7 @@ const Timeline = () => { useEffect(() => { memoList.reset(); fetchMemos(); - }, [tagQuery, textQuery]); + }, [selectedDay, tagQuery, textQuery]); useEffect(() => { (async () => { @@ -97,6 +98,12 @@ const Timeline = () => { if (contentSearch.length > 0) { filters.push(`content_search == [${contentSearch.join(", ")}]`); } + if (selectedDay) { + const selectedDateStamp = getTimeStampByDate(selectedDay) + new Date().getTimezoneOffset() * 60 * 1000; + filters.push( + ...[`display_time_after == ${selectedDateStamp / 1000}`, `display_time_before == ${(selectedDateStamp + DAILY_TIMESTAMP) / 1000}`] + ); + } setIsRequesting(true); const data = await memoStore.fetchMemos({ filter: filters.join(" && "), @@ -143,7 +150,7 @@ const Timeline = () => { {new Date(group.month).getFullYear()} Total: {sum(Object.values(group.data))} - + setSelectedDay(date)} />