Commit 9972a77d authored by Steven's avatar Steven

refactor: memo service

parent 91c2a4ce
This diff is collapsed.
syntax = "proto3";
package memos.api.v1;
option go_package = "gen/api/v1";
message Reaction {
int32 id = 1;
// The name of the creator.
// Format: users/{user}
string creator = 2;
// The content identifier.
// For memo, it should be the `Memo.name`.
string content_id = 3;
string reaction_type = 4;
}
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc (unknown)
// source: api/v1/reaction_service.proto
package apiv1
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Reaction struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
// The name of the creator.
// Format: users/{user}
Creator string `protobuf:"bytes,2,opt,name=creator,proto3" json:"creator,omitempty"`
// The content identifier.
// For memo, it should be the `Memo.name`.
ContentId string `protobuf:"bytes,3,opt,name=content_id,json=contentId,proto3" json:"content_id,omitempty"`
ReactionType string `protobuf:"bytes,4,opt,name=reaction_type,json=reactionType,proto3" json:"reaction_type,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Reaction) Reset() {
*x = Reaction{}
mi := &file_api_v1_reaction_service_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Reaction) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Reaction) ProtoMessage() {}
func (x *Reaction) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_reaction_service_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Reaction.ProtoReflect.Descriptor instead.
func (*Reaction) Descriptor() ([]byte, []int) {
return file_api_v1_reaction_service_proto_rawDescGZIP(), []int{0}
}
func (x *Reaction) GetId() int32 {
if x != nil {
return x.Id
}
return 0
}
func (x *Reaction) GetCreator() string {
if x != nil {
return x.Creator
}
return ""
}
func (x *Reaction) GetContentId() string {
if x != nil {
return x.ContentId
}
return ""
}
func (x *Reaction) GetReactionType() string {
if x != nil {
return x.ReactionType
}
return ""
}
var File_api_v1_reaction_service_proto protoreflect.FileDescriptor
const file_api_v1_reaction_service_proto_rawDesc = "" +
"\n" +
"\x1dapi/v1/reaction_service.proto\x12\fmemos.api.v1\"x\n" +
"\bReaction\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x05R\x02id\x12\x18\n" +
"\acreator\x18\x02 \x01(\tR\acreator\x12\x1d\n" +
"\n" +
"content_id\x18\x03 \x01(\tR\tcontentId\x12#\n" +
"\rreaction_type\x18\x04 \x01(\tR\freactionTypeB\xac\x01\n" +
"\x10com.memos.api.v1B\x14ReactionServiceProtoP\x01Z0github.com/usememos/memos/proto/gen/api/v1;apiv1\xa2\x02\x03MAX\xaa\x02\fMemos.Api.V1\xca\x02\fMemos\\Api\\V1\xe2\x02\x18Memos\\Api\\V1\\GPBMetadata\xea\x02\x0eMemos::Api::V1b\x06proto3"
var (
file_api_v1_reaction_service_proto_rawDescOnce sync.Once
file_api_v1_reaction_service_proto_rawDescData []byte
)
func file_api_v1_reaction_service_proto_rawDescGZIP() []byte {
file_api_v1_reaction_service_proto_rawDescOnce.Do(func() {
file_api_v1_reaction_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_api_v1_reaction_service_proto_rawDesc), len(file_api_v1_reaction_service_proto_rawDesc)))
})
return file_api_v1_reaction_service_proto_rawDescData
}
var file_api_v1_reaction_service_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_api_v1_reaction_service_proto_goTypes = []any{
(*Reaction)(nil), // 0: memos.api.v1.Reaction
}
var file_api_v1_reaction_service_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_api_v1_reaction_service_proto_init() }
func file_api_v1_reaction_service_proto_init() {
if File_api_v1_reaction_service_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_v1_reaction_service_proto_rawDesc), len(file_api_v1_reaction_service_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_api_v1_reaction_service_proto_goTypes,
DependencyIndexes: file_api_v1_reaction_service_proto_depIdxs,
MessageInfos: file_api_v1_reaction_service_proto_msgTypes,
}.Build()
File_api_v1_reaction_service_proto = out.File
file_api_v1_reaction_service_proto_goTypes = nil
file_api_v1_reaction_service_proto_depIdxs = nil
}
This diff is collapsed.
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"log/slog" "log/slog"
"strings"
"time" "time"
"unicode/utf8" "unicode/utf8"
...@@ -99,8 +100,12 @@ func (s *APIV1Service) ListMemos(ctx context.Context, request *v1pb.ListMemosReq ...@@ -99,8 +100,12 @@ func (s *APIV1Service) ListMemos(ctx context.Context, request *v1pb.ListMemosReq
// Exclude comments by default. // Exclude comments by default.
ExcludeComments: true, ExcludeComments: true,
} }
if err := s.buildMemoFindWithFilter(ctx, memoFind, request.OldFilter); err != nil { // Handle deprecated old_filter for backward compatibility
return nil, status.Errorf(codes.InvalidArgument, "failed to build find memos with filter: %v", err) if request.OldFilter != "" && request.Filter == "" {
//nolint:staticcheck // SA1019: Using deprecated field for backward compatibility
if err := s.buildMemoFindWithFilter(ctx, memoFind, request.OldFilter); err != nil {
return nil, status.Errorf(codes.InvalidArgument, "failed to build find memos with filter: %v", err)
}
} }
if request.Parent != "" && request.Parent != "users/-" { if request.Parent != "" && request.Parent != "users/-" {
userID, err := ExtractUserIDFromName(request.Parent) userID, err := ExtractUserIDFromName(request.Parent)
...@@ -117,9 +122,17 @@ func (s *APIV1Service) ListMemos(ctx context.Context, request *v1pb.ListMemosReq ...@@ -117,9 +122,17 @@ func (s *APIV1Service) ListMemos(ctx context.Context, request *v1pb.ListMemosReq
state := store.Normal state := store.Normal
memoFind.RowStatus = &state memoFind.RowStatus = &state
} }
if request.Direction == v1pb.Direction_ASC {
memoFind.OrderByTimeAsc = true // Parse order_by field (replaces the old sort and direction fields)
if request.OrderBy != "" {
if err := s.parseMemoOrderBy(request.OrderBy, memoFind); err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid order_by: %v", err)
}
} else {
// Default ordering by display_time desc
memoFind.OrderByTimeAsc = false
} }
if request.Filter != "" { if request.Filter != "" {
if err := s.validateFilter(ctx, request.Filter); err != nil { if err := s.validateFilter(ctx, request.Filter); err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid filter: %v", err) return nil, status.Errorf(codes.InvalidArgument, "invalid filter: %v", err)
...@@ -739,3 +752,38 @@ func substring(s string, length int) string { ...@@ -739,3 +752,38 @@ func substring(s string, length int) string {
return s[:byteIndex] return s[:byteIndex]
} }
// parseMemoOrderBy parses the order_by field and sets the appropriate ordering in memoFind.
func (*APIV1Service) parseMemoOrderBy(orderBy string, memoFind *store.FindMemo) error {
// Parse order_by field like "display_time desc" or "create_time asc"
parts := strings.Fields(strings.TrimSpace(orderBy))
if len(parts) == 0 {
return errors.New("empty order_by")
}
field := parts[0]
direction := "desc" // default
if len(parts) > 1 {
direction = strings.ToLower(parts[1])
if direction != "asc" && direction != "desc" {
return errors.Errorf("invalid order direction: %s, must be 'asc' or 'desc'", parts[1])
}
}
switch field {
case "display_time":
memoFind.OrderByTimeAsc = direction == "asc"
case "create_time":
memoFind.OrderByTimeAsc = direction == "asc"
case "update_time":
memoFind.OrderByUpdatedTs = true
memoFind.OrderByTimeAsc = direction == "asc"
case "name":
// For ordering by memo name/id - not commonly used but supported
memoFind.OrderByTimeAsc = direction == "asc"
default:
return errors.Errorf("unsupported order field: %s, supported fields are: display_time, create_time, update_time, name", field)
}
return nil
}
...@@ -3,10 +3,12 @@ package v1 ...@@ -3,10 +3,12 @@ package v1
import ( import (
"context" "context"
"fmt" "fmt"
"time"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb" "google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/timestamppb"
v1pb "github.com/usememos/memos/proto/gen/api/v1" v1pb "github.com/usememos/memos/proto/gen/api/v1"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
...@@ -55,8 +57,13 @@ func (s *APIV1Service) UpsertMemoReaction(ctx context.Context, request *v1pb.Ups ...@@ -55,8 +57,13 @@ func (s *APIV1Service) UpsertMemoReaction(ctx context.Context, request *v1pb.Ups
} }
func (s *APIV1Service) DeleteMemoReaction(ctx context.Context, request *v1pb.DeleteMemoReactionRequest) (*emptypb.Empty, error) { func (s *APIV1Service) DeleteMemoReaction(ctx context.Context, request *v1pb.DeleteMemoReactionRequest) (*emptypb.Empty, error) {
reactionID, err := ExtractReactionIDFromName(request.Name)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid reaction name: %v", err)
}
if err := s.Store.DeleteReaction(ctx, &store.DeleteReaction{ if err := s.Store.DeleteReaction(ctx, &store.DeleteReaction{
ID: request.Id, ID: reactionID,
}); err != nil { }); err != nil {
return nil, status.Errorf(codes.Internal, "failed to delete reaction") return nil, status.Errorf(codes.Internal, "failed to delete reaction")
} }
...@@ -71,10 +78,14 @@ func (s *APIV1Service) convertReactionFromStore(ctx context.Context, reaction *s ...@@ -71,10 +78,14 @@ func (s *APIV1Service) convertReactionFromStore(ctx context.Context, reaction *s
if err != nil { if err != nil {
return nil, err return nil, err
} }
reactionUID := fmt.Sprintf("%d", reaction.ID)
return &v1pb.Reaction{ return &v1pb.Reaction{
Id: reaction.ID, Name: fmt.Sprintf("%s%s", ReactionNamePrefix, reactionUID),
Uid: reactionUID,
Creator: fmt.Sprintf("%s%d", UserNamePrefix, creator.ID), Creator: fmt.Sprintf("%s%d", UserNamePrefix, creator.ID),
ContentId: reaction.ContentID, ContentId: reaction.ContentID,
ReactionType: reaction.ReactionType, ReactionType: reaction.ReactionType,
CreateTime: timestamppb.New(time.Unix(reaction.CreatedTs, 0)),
}, nil }, nil
} }
...@@ -14,6 +14,7 @@ const ( ...@@ -14,6 +14,7 @@ const (
UserNamePrefix = "users/" UserNamePrefix = "users/"
MemoNamePrefix = "memos/" MemoNamePrefix = "memos/"
AttachmentNamePrefix = "attachments/" AttachmentNamePrefix = "attachments/"
ReactionNamePrefix = "reactions/"
InboxNamePrefix = "inboxes/" InboxNamePrefix = "inboxes/"
IdentityProviderNamePrefix = "identityProviders/" IdentityProviderNamePrefix = "identityProviders/"
ActivityNamePrefix = "activities/" ActivityNamePrefix = "activities/"
...@@ -93,6 +94,20 @@ func ExtractAttachmentUIDFromName(name string) (string, error) { ...@@ -93,6 +94,20 @@ func ExtractAttachmentUIDFromName(name string) (string, error) {
return id, nil return id, nil
} }
// ExtractReactionIDFromName returns the reaction ID from a resource name.
// e.g., "reactions/123" -> 123.
func ExtractReactionIDFromName(name string) (int32, error) {
tokens, err := GetNameParentTokens(name, ReactionNamePrefix)
if err != nil {
return 0, err
}
id, err := util.ConvertStringToInt32(tokens[0])
if err != nil {
return 0, errors.Errorf("invalid reaction ID %q", tokens[0])
}
return id, nil
}
// ExtractInboxIDFromName returns the inbox ID from a resource name. // ExtractInboxIDFromName returns the inbox ID from a resource name.
func ExtractInboxIDFromName(name string) (int32, error) { func ExtractInboxIDFromName(name string) (int32, error) {
tokens, err := GetNameParentTokens(name, InboxNamePrefix) tokens, err := GetNameParentTokens(name, InboxNamePrefix)
......
...@@ -9,7 +9,6 @@ type Reaction struct { ...@@ -9,7 +9,6 @@ type Reaction struct {
CreatedTs int64 CreatedTs int64
CreatorID int32 CreatorID int32
// ContentID is the id of the content that the reaction is for. // ContentID is the id of the content that the reaction is for.
// This can be a memo. e.g. memos/101
ContentID string ContentID string
ReactionType string ReactionType string
} }
......
...@@ -396,6 +396,10 @@ const MemoEditor = observer((props: Props) => { ...@@ -396,6 +396,10 @@ const MemoEditor = observer((props: Props) => {
relations: state.relationList, relations: state.relationList,
location: state.location, location: state.location,
}), }),
// Optional fields can be omitted
memoId: "",
validateOnly: false,
requestId: "",
}) })
: memoServiceClient : memoServiceClient
.createMemoComment({ .createMemoComment({
......
...@@ -5,7 +5,7 @@ import useCurrentUser from "@/hooks/useCurrentUser"; ...@@ -5,7 +5,7 @@ import useCurrentUser from "@/hooks/useCurrentUser";
import { userStore } from "@/store/v2"; import { userStore } from "@/store/v2";
import { State } from "@/types/proto/api/v1/common"; import { State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { Reaction } from "@/types/proto/api/v1/reaction_service"; import { Reaction } from "@/types/proto/api/v1/memo_service";
import { User } from "@/types/proto/api/v1/user_service"; import { User } from "@/types/proto/api/v1/user_service";
import ReactionSelector from "./ReactionSelector"; import ReactionSelector from "./ReactionSelector";
import ReactionView from "./ReactionView"; import ReactionView from "./ReactionView";
......
...@@ -8,7 +8,7 @@ import { DEFAULT_LIST_MEMOS_PAGE_SIZE } from "@/helpers/consts"; ...@@ -8,7 +8,7 @@ import { DEFAULT_LIST_MEMOS_PAGE_SIZE } from "@/helpers/consts";
import useResponsiveWidth from "@/hooks/useResponsiveWidth"; import useResponsiveWidth from "@/hooks/useResponsiveWidth";
import { Routes } from "@/router"; import { Routes } from "@/router";
import { memoStore, viewStore } from "@/store/v2"; import { memoStore, viewStore } from "@/store/v2";
import { Direction, State } from "@/types/proto/api/v1/common"; import { State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import Empty from "../Empty"; import Empty from "../Empty";
...@@ -20,7 +20,7 @@ interface Props { ...@@ -20,7 +20,7 @@ interface Props {
listSort?: (list: Memo[]) => Memo[]; listSort?: (list: Memo[]) => Memo[];
owner?: string; owner?: string;
state?: State; state?: State;
direction?: Direction; orderBy?: string;
filter?: string; filter?: string;
oldFilter?: string; oldFilter?: string;
pageSize?: number; pageSize?: number;
...@@ -51,7 +51,7 @@ const PagedMemoList = observer((props: Props) => { ...@@ -51,7 +51,7 @@ const PagedMemoList = observer((props: Props) => {
const response = await memoStore.fetchMemos({ const response = await memoStore.fetchMemos({
parent: props.owner || "", parent: props.owner || "",
state: props.state || State.NORMAL, state: props.state || State.NORMAL,
direction: props.direction || Direction.DESC, orderBy: props.orderBy || "display_time desc",
filter: props.filter || "", filter: props.filter || "",
oldFilter: props.oldFilter || "", oldFilter: props.oldFilter || "",
pageSize: props.pageSize || DEFAULT_LIST_MEMOS_PAGE_SIZE, pageSize: props.pageSize || DEFAULT_LIST_MEMOS_PAGE_SIZE,
...@@ -103,7 +103,7 @@ const PagedMemoList = observer((props: Props) => { ...@@ -103,7 +103,7 @@ const PagedMemoList = observer((props: Props) => {
// Initial load and reload when props change // Initial load and reload when props change
useEffect(() => { useEffect(() => {
refreshList(); refreshList();
}, [props.owner, props.state, props.direction, props.filter, props.oldFilter, props.pageSize]); }, [props.owner, props.state, props.orderBy, props.filter, props.oldFilter, props.pageSize]);
// Auto-fetch more content when list changes and page isn't full // Auto-fetch more content when list changes and page isn't full
useEffect(() => { useEffect(() => {
......
...@@ -36,7 +36,7 @@ const ReactionSelector = observer((props: Props) => { ...@@ -36,7 +36,7 @@ const ReactionSelector = observer((props: Props) => {
(reaction) => reaction.reactionType === reactionType && reaction.creator === currentUser.name, (reaction) => reaction.reactionType === reactionType && reaction.creator === currentUser.name,
); );
for (const reaction of reactions) { for (const reaction of reactions) {
await memoServiceClient.deleteMemoReaction({ id: reaction.id }); await memoServiceClient.deleteMemoReaction({ name: reaction.name });
} }
} else { } else {
await memoServiceClient.upsertMemoReaction({ await memoServiceClient.upsertMemoReaction({
......
...@@ -55,7 +55,7 @@ const ReactionView = observer((props: Props) => { ...@@ -55,7 +55,7 @@ const ReactionView = observer((props: Props) => {
(reaction) => reaction.reactionType === reactionType && reaction.creator === currentUser.name, (reaction) => reaction.reactionType === reactionType && reaction.creator === currentUser.name,
); );
for (const reaction of reactions) { for (const reaction of reactions) {
await memoServiceClient.deleteMemoReaction({ id: reaction.id }); await memoServiceClient.deleteMemoReaction({ name: reaction.name });
} }
} }
} catch { } catch {
......
...@@ -6,7 +6,7 @@ import PagedMemoList from "@/components/PagedMemoList"; ...@@ -6,7 +6,7 @@ import PagedMemoList from "@/components/PagedMemoList";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
import { viewStore } from "@/store/v2"; import { viewStore } from "@/store/v2";
import memoFilterStore from "@/store/v2/memoFilter"; import memoFilterStore from "@/store/v2/memoFilter";
import { Direction, State } from "@/types/proto/api/v1/common"; import { State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
const Archived = observer(() => { const Archived = observer(() => {
...@@ -46,7 +46,7 @@ const Archived = observer(() => { ...@@ -46,7 +46,7 @@ const Archived = observer(() => {
} }
owner={user.name} owner={user.name}
state={State.ARCHIVED} state={State.ARCHIVED}
direction={viewStore.state.orderByTimeAsc ? Direction.ASC : Direction.DESC} orderBy={viewStore.state.orderByTimeAsc ? "display_time asc" : "display_time desc"}
oldFilter={memoListFilter} oldFilter={memoListFilter}
/> />
); );
......
...@@ -5,7 +5,7 @@ import MobileHeader from "@/components/MobileHeader"; ...@@ -5,7 +5,7 @@ import MobileHeader from "@/components/MobileHeader";
import PagedMemoList from "@/components/PagedMemoList"; import PagedMemoList from "@/components/PagedMemoList";
import useResponsiveWidth from "@/hooks/useResponsiveWidth"; import useResponsiveWidth from "@/hooks/useResponsiveWidth";
import { viewStore } from "@/store/v2"; import { viewStore } from "@/store/v2";
import { Direction, State } from "@/types/proto/api/v1/common"; import { State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
const Explore = observer(() => { const Explore = observer(() => {
...@@ -26,7 +26,7 @@ const Explore = observer(() => { ...@@ -26,7 +26,7 @@ const Explore = observer(() => {
: dayjs(b.displayTime).unix() - dayjs(a.displayTime).unix(), : dayjs(b.displayTime).unix() - dayjs(a.displayTime).unix(),
) )
} }
direction={viewStore.state.orderByTimeAsc ? Direction.ASC : Direction.DESC} orderBy={viewStore.state.orderByTimeAsc ? "display_time asc" : "display_time desc"}
/> />
</div> </div>
</section> </section>
......
...@@ -6,7 +6,7 @@ import PagedMemoList from "@/components/PagedMemoList"; ...@@ -6,7 +6,7 @@ import PagedMemoList from "@/components/PagedMemoList";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
import { viewStore, userStore } from "@/store/v2"; import { viewStore, userStore } from "@/store/v2";
import memoFilterStore from "@/store/v2/memoFilter"; import memoFilterStore from "@/store/v2/memoFilter";
import { Direction, State } from "@/types/proto/api/v1/common"; import { State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
// Helper function to extract shortcut ID from resource name // Helper function to extract shortcut ID from resource name
...@@ -68,7 +68,7 @@ const Home = observer(() => { ...@@ -68,7 +68,7 @@ const Home = observer(() => {
.sort((a, b) => Number(b.pinned) - Number(a.pinned)) .sort((a, b) => Number(b.pinned) - Number(a.pinned))
} }
owner={user.name} owner={user.name}
direction={viewStore.state.orderByTimeAsc ? Direction.ASC : Direction.DESC} orderBy={viewStore.state.orderByTimeAsc ? "display_time asc" : "display_time desc"}
filter={selectedShortcut?.filter || ""} filter={selectedShortcut?.filter || ""}
oldFilter={memoListFilter} oldFilter={memoListFilter}
/> />
......
...@@ -12,7 +12,7 @@ import UserAvatar from "@/components/UserAvatar"; ...@@ -12,7 +12,7 @@ import UserAvatar from "@/components/UserAvatar";
import useLoading from "@/hooks/useLoading"; import useLoading from "@/hooks/useLoading";
import { viewStore, userStore } from "@/store/v2"; import { viewStore, userStore } from "@/store/v2";
import memoFilterStore from "@/store/v2/memoFilter"; import memoFilterStore from "@/store/v2/memoFilter";
import { Direction, State } from "@/types/proto/api/v1/common"; import { State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { User } from "@/types/proto/api/v1/user_service"; import { User } from "@/types/proto/api/v1/user_service";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
...@@ -112,7 +112,7 @@ const UserProfile = observer(() => { ...@@ -112,7 +112,7 @@ const UserProfile = observer(() => {
.sort((a, b) => Number(b.pinned) - Number(a.pinned)) .sort((a, b) => Number(b.pinned) - Number(a.pinned))
} }
owner={user.name} owner={user.name}
direction={viewStore.state.orderByTimeAsc ? Direction.ASC : Direction.DESC} orderBy={viewStore.state.orderByTimeAsc ? "display_time asc" : "display_time desc"}
oldFilter={memoListFilter} oldFilter={memoListFilter}
/> />
</> </>
......
This diff is collapsed.
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.6.1
// protoc unknown
// source: api/v1/reaction_service.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
export const protobufPackage = "memos.api.v1";
export interface Reaction {
id: number;
/**
* The name of the creator.
* Format: users/{user}
*/
creator: string;
/**
* The content identifier.
* For memo, it should be the `Memo.name`.
*/
contentId: string;
reactionType: string;
}
function createBaseReaction(): Reaction {
return { id: 0, creator: "", contentId: "", reactionType: "" };
}
export const Reaction: MessageFns<Reaction> = {
encode(message: Reaction, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.id !== 0) {
writer.uint32(8).int32(message.id);
}
if (message.creator !== "") {
writer.uint32(18).string(message.creator);
}
if (message.contentId !== "") {
writer.uint32(26).string(message.contentId);
}
if (message.reactionType !== "") {
writer.uint32(34).string(message.reactionType);
}
return writer;
},
decode(input: BinaryReader | Uint8Array, length?: number): Reaction {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseReaction();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1: {
if (tag !== 8) {
break;
}
message.id = reader.int32();
continue;
}
case 2: {
if (tag !== 18) {
break;
}
message.creator = reader.string();
continue;
}
case 3: {
if (tag !== 26) {
break;
}
message.contentId = reader.string();
continue;
}
case 4: {
if (tag !== 34) {
break;
}
message.reactionType = reader.string();
continue;
}
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skip(tag & 7);
}
return message;
},
create(base?: DeepPartial<Reaction>): Reaction {
return Reaction.fromPartial(base ?? {});
},
fromPartial(object: DeepPartial<Reaction>): Reaction {
const message = createBaseReaction();
message.id = object.id ?? 0;
message.creator = object.creator ?? "";
message.contentId = object.contentId ?? "";
message.reactionType = object.reactionType ?? "";
return message;
},
};
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
export type DeepPartial<T> = T extends Builtin ? T
: T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>>
: T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
: T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
create(base?: DeepPartial<T>): T;
fromPartial(object: DeepPartial<T>): T;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment