feat: support updating display time

pull/3399/head v0.22.0
Steven 11 months ago
parent b0aad6f694
commit c25c57ab61

@ -277,6 +277,17 @@ func (s *APIV1Service) UpdateMemo(ctx context.Context, request *v1pb.UpdateMemoR
} else if path == "created_ts" {
createdTs := request.Memo.CreateTime.AsTime().Unix()
update.CreatedTs = &createdTs
} else if path == "display_ts" {
displayTs := request.Memo.DisplayTime.AsTime().Unix()
memoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace memo related setting")
}
if memoRelatedSetting.DisplayWithUpdateTime {
update.UpdatedTs = &displayTs
} else {
update.CreatedTs = &displayTs
}
} else if path == "pinned" {
if _, err := s.Store.UpsertMemoOrganizer(ctx, &store.MemoOrganizer{
MemoID: id,

@ -77,10 +77,8 @@ export function generateDialog<T extends DialogProps>(
const cbs: DialogCallback = {
destroy: () => {
document.body.style.removeProperty("overflow");
setTimeout(() => {
dialog.unmount();
tempDiv.remove();
});
dialog.unmount();
tempDiv.remove();
},
};

@ -15,7 +15,7 @@ const ExploreSidebar = (props: Props) => {
)}
>
<SearchBar />
<TagsSection hideTips={true} />
<TagsSection readonly={true} />
</aside>
);
};

@ -14,7 +14,7 @@ import Icon from "../Icon";
import showRenameTagDialog from "../RenameTagDialog";
interface Props {
hideTips?: boolean;
readonly?: boolean;
}
const TagsSection = (props: Props) => {
@ -62,7 +62,7 @@ const TagsSection = (props: Props) => {
<div className="flex flex-col justify-start items-start w-full mt-3 px-1 h-auto shrink-0 flex-nowrap hide-scrollbar">
<div className="group flex flex-row justify-start items-center w-full gap-1 mb-1">
<span className="text-sm leading-6 font-mono text-gray-400 select-none">{t("common.tags")}</span>
{!props.hideTips && (
{!props.readonly && (
<div className={clsx("group-hover:block", tagAmounts.length > 0 ? "hidden" : "")}>
<Tooltip title={"Rebuild"} placement="top">
<Icon.RefreshCcw
@ -80,7 +80,7 @@ const TagsSection = (props: Props) => {
))}
</div>
) : (
!props.hideTips && (
!props.readonly && (
<div className="p-2 border border-dashed dark:border-zinc-800 rounded-md flex flex-row justify-start items-start gap-1 text-gray-400 dark:text-gray-500">
<Icon.Tags />
<p className="mt-0.5 text-sm leading-snug italic">{t("tag.create-tags-guide")}</p>

@ -3,7 +3,7 @@ interface Props {
}
const Code: React.FC<Props> = ({ content }: Props) => {
return <code className="inline break-all px-1 font-mono rounded bg-gray-100 dark:bg-zinc-700">{content}</code>;
return <code className="inline break-all px-1 font-mono text-sm rounded opacity-80 bg-gray-100 dark:bg-zinc-700">{content}</code>;
};
export default Code;

@ -1,6 +1,8 @@
import { IconButton } from "@mui/joy";
import { useEffect } from "react";
import { useTagStore } from "@/store/v1";
import clsx from "clsx";
import { useEffect, useRef, useState } from "react";
import { useMemoStore, useTagStore } from "@/store/v1";
import { Memo } from "@/types/proto/api/v1/memo_service";
import MemoEditor, { Props as MemoEditorProps } from ".";
import { generateDialog } from "../Dialog";
import Icon from "../Icon";
@ -8,7 +10,7 @@ import Icon from "../Icon";
interface Props extends DialogProps, MemoEditorProps {}
const MemoEditorDialog: React.FC<Props> = ({
memoName: memo,
memoName,
parentMemoName,
placeholder,
cacheKey,
@ -17,11 +19,21 @@ const MemoEditorDialog: React.FC<Props> = ({
destroy,
}: Props) => {
const tagStore = useTagStore();
const memoStore = useMemoStore();
const [displayTime, setDisplayTime] = useState<string | undefined>(memoStore.getMemoByName(memoName || "")?.displayTime?.toISOString());
const memoPatchRef = useRef<Partial<Memo>>({
displayTime: memoStore.getMemoByName(memoName || "")?.displayTime,
});
useEffect(() => {
tagStore.fetchTags(undefined, { skipCache: false });
}, []);
const updateDisplayTime = (displayTime: string) => {
setDisplayTime(displayTime);
memoPatchRef.current.displayTime = new Date(displayTime);
};
const handleCloseBtnClick = () => {
destroy();
};
@ -35,10 +47,25 @@ const MemoEditorDialog: React.FC<Props> = ({
return (
<>
<div className="w-full flex flex-row justify-between items-center mb-2">
<div className="flex flex-row justify-start items-center">
<img className="w-6 h-auto rounded-full shadow" src={"/full-logo.webp"} alt="" />
<p className="ml-1 text-lg opacity-80 dark:text-gray-300">Memos</p>
<div className="w-full flex flex-row justify-between items-center">
<div className={clsx("flex flex-row justify-start items-center", !displayTime && "mb-2")}>
{displayTime ? (
<div className="relative">
<span className="cursor-pointer text-gray-500 dark:text-gray-400">{new Date(displayTime).toLocaleString()}</span>
<input
className="inset-0 absolute z-1 opacity-0"
type="datetime-local"
value={displayTime}
onFocus={(e: any) => e.target.showPicker()}
onChange={(e) => updateDisplayTime(e.target.value)}
/>
</div>
) : (
<>
<img className="w-6 h-auto rounded-full shadow" src={"/full-logo.webp"} alt="" />
<p className="ml-1 text-lg opacity-80 dark:text-gray-300">Memos</p>
</>
)}
</div>
<IconButton size="sm" onClick={handleCloseBtnClick}>
<Icon.X className="w-5 h-auto" />
@ -47,11 +74,12 @@ const MemoEditorDialog: React.FC<Props> = ({
<div className="flex flex-col justify-start items-start max-w-full w-[36rem]">
<MemoEditor
className="border-none !p-0 -mb-2"
cacheKey={`memo-editor-${cacheKey || memo}`}
memoName={memo}
cacheKey={`memo-editor-${cacheKey || memoName}`}
memoName={memoName}
parentMemoName={parentMemoName}
placeholder={placeholder}
relationList={relationList}
memoPatchRef={memoPatchRef}
onConfirm={handleConfirm}
autoFocus
/>

@ -9,7 +9,7 @@ import { isValidUrl } from "@/helpers/utils";
import useCurrentUser from "@/hooks/useCurrentUser";
import { useMemoStore, useResourceStore, useUserStore, useWorkspaceSettingStore } from "@/store/v1";
import { MemoRelation, MemoRelation_Type } from "@/types/proto/api/v1/memo_relation_service";
import { Visibility } from "@/types/proto/api/v1/memo_service";
import { Memo, Visibility } from "@/types/proto/api/v1/memo_service";
import { Resource } from "@/types/proto/api/v1/resource_service";
import { UserSetting } from "@/types/proto/api/v1/user_service";
import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_setting_service";
@ -36,8 +36,8 @@ export interface Props {
parentMemoName?: string;
relationList?: MemoRelation[];
autoFocus?: boolean;
memoPatchRef?: React.MutableRefObject<Partial<Memo>>;
onConfirm?: (memoName: string) => void;
onEditPrevious?: () => void;
}
interface State {
@ -159,12 +159,6 @@ const MemoEditor = (props: Props) => {
}
return;
}
if (!!props.onEditPrevious && event.key === "ArrowDown" && !state.isComposing && editorRef.current.getContent() === "") {
event.preventDefault();
props.onEditPrevious();
return;
}
};
const handleMemoVisibilityChange = (visibility: Visibility) => {
@ -293,13 +287,18 @@ const MemoEditor = (props: Props) => {
if (memoName) {
const prevMemo = await memoStore.getOrFetchMemoByName(memoName);
if (prevMemo) {
const updateMask = ["content", "visibility"];
if (props.memoPatchRef?.current?.displayTime) {
updateMask.push("display_ts");
}
const memo = await memoStore.updateMemo(
{
name: prevMemo.name,
content,
visibility: state.memoVisibility,
...props.memoPatchRef?.current,
},
["content", "visibility"],
updateMask,
);
await memoServiceClient.setMemoResources({
name: memo.name,

@ -1,11 +1,10 @@
import { Button } from "@mui/joy";
import clsx from "clsx";
import { useCallback, useEffect, useState } from "react";
import { useEffect, useState } from "react";
import Empty from "@/components/Empty";
import { HomeSidebar, HomeSidebarDrawer } from "@/components/HomeSidebar";
import Icon from "@/components/Icon";
import MemoEditor from "@/components/MemoEditor";
import showMemoEditorDialog from "@/components/MemoEditor/MemoEditorDialog";
import MemoFilter from "@/components/MemoFilter";
import MemoView from "@/components/MemoView";
import MobileHeader from "@/components/MobileHeader";
@ -59,14 +58,6 @@ const Home = () => {
setNextPageToken(response.nextPageToken);
};
const handleEditPrevious = useCallback(() => {
const lastMemo = memoList.value[memoList.value.length - 1];
showMemoEditorDialog({
memoName: lastMemo.name,
cacheKey: `${lastMemo.name}-${lastMemo.displayTime}`,
});
}, [memoList]);
return (
<section className="@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8">
{!md && (
@ -76,7 +67,7 @@ const Home = () => {
)}
<div className={clsx("w-full flex flex-row justify-start items-start px-4 sm:px-6 gap-4")}>
<div className={clsx(md ? "w-[calc(100%-15rem)]" : "w-full")}>
<MemoEditor className="mb-2" cacheKey="home-memo-editor" onEditPrevious={handleEditPrevious} />
<MemoEditor className="mb-2" cacheKey="home-memo-editor" />
<div className="flex flex-col justify-start items-start w-full max-w-full">
<MemoFilter className="px-2 pb-2" />
{sortedMemos.map((memo) => (

Loading…
Cancel
Save