chore: add time filter to timeline

pull/2782/head
Steven 1 year ago
parent 7de3de5610
commit d426f89cf0

@ -105,11 +105,27 @@ func (s *APIV2Service) ListMemos(ctx context.Context, request *apiv2pb.ListMemos
if filter.OrderByPinned { if filter.OrderByPinned {
memoFind.OrderByPinned = filter.OrderByPinned memoFind.OrderByPinned = filter.OrderByPinned
} }
if filter.CreatedTsBefore != nil { if filter.DisplayTimeAfter != nil {
memoFind.CreatedTsBefore = filter.CreatedTsBefore 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 { if filter.DisplayTimeBefore != nil {
memoFind.CreatedTsAfter = filter.CreatedTsAfter 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 { if filter.Creator != nil {
username, err := ExtractUsernameFromName(*filter.Creator) username, err := ExtractUsernameFromName(*filter.Creator)
@ -463,11 +479,27 @@ func (s *APIV2Service) GetUserMemosStats(ctx context.Context, request *apiv2pb.G
if filter.OrderByPinned { if filter.OrderByPinned {
memoFind.OrderByPinned = filter.OrderByPinned memoFind.OrderByPinned = filter.OrderByPinned
} }
if filter.CreatedTsBefore != nil { if filter.DisplayTimeAfter != nil {
memoFind.CreatedTsBefore = filter.CreatedTsBefore 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 { if filter.DisplayTimeBefore != nil {
memoFind.CreatedTsAfter = filter.CreatedTsAfter 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 { if filter.RowStatus != nil {
memoFind.RowStatus = filter.RowStatus memoFind.RowStatus = filter.RowStatus
@ -590,20 +622,20 @@ var ListMemosFilterCELAttributes = []cel.EnvOption{
cel.Variable("content_search", cel.ListType(cel.StringType)), cel.Variable("content_search", cel.ListType(cel.StringType)),
cel.Variable("visibilities", cel.ListType(cel.StringType)), cel.Variable("visibilities", cel.ListType(cel.StringType)),
cel.Variable("order_by_pinned", cel.BoolType), cel.Variable("order_by_pinned", cel.BoolType),
cel.Variable("created_ts_before", cel.IntType), cel.Variable("display_time_before", cel.IntType),
cel.Variable("created_ts_after", cel.IntType), cel.Variable("display_time_after", cel.IntType),
cel.Variable("creator", cel.StringType), cel.Variable("creator", cel.StringType),
cel.Variable("row_status", cel.StringType), cel.Variable("row_status", cel.StringType),
} }
type ListMemosFilter struct { type ListMemosFilter struct {
ContentSearch []string ContentSearch []string
Visibilities []store.Visibility Visibilities []store.Visibility
OrderByPinned bool OrderByPinned bool
CreatedTsBefore *int64 DisplayTimeBefore *int64
CreatedTsAfter *int64 DisplayTimeAfter *int64
Creator *string Creator *string
RowStatus *store.RowStatus RowStatus *store.RowStatus
} }
func parseListMemosFilter(expression string) (*ListMemosFilter, error) { 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" { } else if idExpr.Name == "order_by_pinned" {
value := callExpr.Args[1].GetConstExpr().GetBoolValue() value := callExpr.Args[1].GetConstExpr().GetBoolValue()
filter.OrderByPinned = value filter.OrderByPinned = value
} else if idExpr.Name == "created_ts_before" { } else if idExpr.Name == "display_time_before" {
createdTsBefore := callExpr.Args[1].GetConstExpr().GetInt64Value() displayTimeBefore := callExpr.Args[1].GetConstExpr().GetInt64Value()
filter.CreatedTsBefore = &createdTsBefore filter.DisplayTimeBefore = &displayTimeBefore
} else if idExpr.Name == "created_ts_after" { } else if idExpr.Name == "display_time_after" {
createdTsAfter := callExpr.Args[1].GetConstExpr().GetInt64Value() displayTimeAfter := callExpr.Args[1].GetConstExpr().GetInt64Value()
filter.CreatedTsAfter = &createdTsAfter filter.DisplayTimeAfter = &displayTimeAfter
} else if idExpr.Name == "creator" { } else if idExpr.Name == "creator" {
creator := callExpr.Args[1].GetConstExpr().GetStringValue() creator := callExpr.Args[1].GetConstExpr().GetStringValue()
filter.Creator = &creator filter.Creator = &creator

@ -55,6 +55,12 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
if v := find.CreatedTsAfter; v != nil { if v := find.CreatedTsAfter; v != nil {
where, args = append(where, "UNIX_TIMESTAMP(`memo`.`created_ts`) > ?"), append(args, *v) 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 { if v := find.ContentSearch; len(v) != 0 {
for _, s := range v { for _, s := range v {
where, args = append(where, "`memo`.`content` LIKE ?"), append(args, "%"+s+"%") where, args = append(where, "`memo`.`content` LIKE ?"), append(args, "%"+s+"%")

@ -46,6 +46,12 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
if v := find.CreatedTsAfter; v != nil { if v := find.CreatedTsAfter; v != nil {
where, args = append(where, "memo.created_ts > "+placeholder(len(args)+1)), append(args, *v) 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 { if v := find.ContentSearch; len(v) != 0 {
for _, s := range v { for _, s := range v {
where, args = append(where, "memo.content LIKE "+placeholder(len(args)+1)), append(args, fmt.Sprintf("%%%s%%", s)) where, args = append(where, "memo.content LIKE "+placeholder(len(args)+1)), append(args, fmt.Sprintf("%%%s%%", s))

@ -45,6 +45,12 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
if v := find.CreatedTsAfter; v != nil { if v := find.CreatedTsAfter; v != nil {
where, args = append(where, "memo.created_ts > ?"), append(args, *v) 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 { if v := find.ContentSearch; len(v) != 0 {
for _, s := range v { for _, s := range v {
where, args = append(where, "memo.content LIKE ?"), append(args, fmt.Sprintf("%%%s%%", s)) where, args = append(where, "memo.content LIKE ?"), append(args, fmt.Sprintf("%%%s%%", s))

@ -54,6 +54,8 @@ type FindMemo struct {
CreatorID *int32 CreatorID *int32
CreatedTsAfter *int64 CreatedTsAfter *int64
CreatedTsBefore *int64 CreatedTsBefore *int64
UpdatedTsAfter *int64
UpdatedTsBefore *int64
// Domain specific fields // Domain specific fields
ContentSearch []string ContentSearch []string

@ -6,6 +6,7 @@ interface Props {
// Format: 2021-1 // Format: 2021-1
month: string; month: string;
data: Record<string, number>; data: Record<string, number>;
onClick?: (date: string) => void;
} }
const getBgColor = (count: number, maxCount: number) => { const getBgColor = (count: number, maxCount: number) => {
@ -26,7 +27,7 @@ const getBgColor = (count: number, maxCount: number) => {
}; };
const ActivityCalendar = (props: Props) => { const ActivityCalendar = (props: Props) => {
const { month: monthStr, data } = props; const { month: monthStr, data, onClick } = props;
const year = new Date(monthStr).getFullYear(); const year = new Date(monthStr).getFullYear();
const month = new Date(monthStr).getMonth() + 1; const month = new Date(monthStr).getMonth() + 1;
const dayInMonth = new Date(year, month, 0).getDate(); const dayInMonth = new Date(year, month, 0).getDate();
@ -60,6 +61,7 @@ const ActivityCalendar = (props: Props) => {
getBgColor(count, maxCount), getBgColor(count, maxCount),
isToday && "border-gray-600 dark:!border-gray-400" isToday && "border-gray-600 dark:!border-gray-400"
)} )}
onClick={() => count && onClick && onClick(date)}
></div> ></div>
</Tooltip> </Tooltip>
) : ( ) : (

@ -10,7 +10,7 @@ import MemoFilter from "@/components/MemoFilter";
import MemoView from "@/components/MemoView"; import MemoView from "@/components/MemoView";
import MobileHeader from "@/components/MobileHeader"; import MobileHeader from "@/components/MobileHeader";
import { memoServiceClient } from "@/grpcweb"; 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 { getNormalizedTimeString, getTimeStampByDate } from "@/helpers/datetime";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
import useResponsiveWidth from "@/hooks/useResponsiveWidth"; import useResponsiveWidth from "@/hooks/useResponsiveWidth";
@ -52,6 +52,7 @@ const Timeline = () => {
const memoList = useMemoList(); const memoList = useMemoList();
const filterStore = useFilterStore(); const filterStore = useFilterStore();
const [activityStats, setActivityStats] = useState<Record<string, number>>({}); const [activityStats, setActivityStats] = useState<Record<string, number>>({});
const [selectedDay, setSelectedDay] = useState<string | undefined>();
const [isRequesting, setIsRequesting] = useState(true); const [isRequesting, setIsRequesting] = useState(true);
const [isComplete, setIsComplete] = useState(false); const [isComplete, setIsComplete] = useState(false);
const { tag: tagQuery, text: textQuery } = filterStore.state; const { tag: tagQuery, text: textQuery } = filterStore.state;
@ -61,7 +62,7 @@ const Timeline = () => {
useEffect(() => { useEffect(() => {
memoList.reset(); memoList.reset();
fetchMemos(); fetchMemos();
}, [tagQuery, textQuery]); }, [selectedDay, tagQuery, textQuery]);
useEffect(() => { useEffect(() => {
(async () => { (async () => {
@ -97,6 +98,12 @@ const Timeline = () => {
if (contentSearch.length > 0) { if (contentSearch.length > 0) {
filters.push(`content_search == [${contentSearch.join(", ")}]`); 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); setIsRequesting(true);
const data = await memoStore.fetchMemos({ const data = await memoStore.fetchMemos({
filter: filters.join(" && "), filter: filters.join(" && "),
@ -143,7 +150,7 @@ const Timeline = () => {
<span className="opacity-60">{new Date(group.month).getFullYear()}</span> <span className="opacity-60">{new Date(group.month).getFullYear()}</span>
<span className="text-xs opacity-40">Total: {sum(Object.values(group.data))}</span> <span className="text-xs opacity-40">Total: {sum(Object.values(group.data))}</span>
</div> </div>
<ActivityCalendar month={group.month} data={group.data} /> <ActivityCalendar month={group.month} data={group.data} onClick={(date) => setSelectedDay(date)} />
</div> </div>
<div className={classNames("flex flex-col justify-start items-start", md ? "w-[calc(100%-8rem)]" : "w-full")}> <div className={classNames("flex flex-col justify-start items-start", md ? "w-[calc(100%-8rem)]" : "w-full")}>

Loading…
Cancel
Save