Merge branch 'main' of github.com:SaraVieira/memos into fix-ordered-padding

pull/4992/head
SaraVieira 2 months ago
commit ee1481dd1e
No known key found for this signature in database
GPG Key ID: D31B9EE2FD5463CC

@ -122,7 +122,7 @@ func (c *CommonSQLConverter) handleComparisonOperator(ctx *ConvertContext, callE
return err return err
} }
if !slices.Contains([]string{"creator_id", "created_ts", "updated_ts", "visibility", "content", "has_task_list", "has_link", "has_code", "has_incomplete_tasks"}, identifier) { if !slices.Contains([]string{"creator_id", "created_ts", "updated_ts", "visibility", "content", "pinned", "has_task_list", "has_link", "has_code", "has_incomplete_tasks"}, identifier) {
return errors.Errorf("invalid identifier for %s", callExpr.Function) return errors.Errorf("invalid identifier for %s", callExpr.Function)
} }
@ -140,6 +140,8 @@ func (c *CommonSQLConverter) handleComparisonOperator(ctx *ConvertContext, callE
return c.handleStringComparison(ctx, identifier, operator, value) return c.handleStringComparison(ctx, identifier, operator, value)
case "creator_id": case "creator_id":
return c.handleIntComparison(ctx, identifier, operator, value) return c.handleIntComparison(ctx, identifier, operator, value)
case "pinned":
return c.handlePinnedComparison(ctx, operator, value)
case "has_task_list", "has_link", "has_code", "has_incomplete_tasks": case "has_task_list", "has_link", "has_code", "has_incomplete_tasks":
return c.handleBooleanComparison(ctx, identifier, operator, value) return c.handleBooleanComparison(ctx, identifier, operator, value)
} }
@ -491,6 +493,35 @@ func (c *CommonSQLConverter) handleIntComparison(ctx *ConvertContext, field, ope
return nil return nil
} }
func (c *CommonSQLConverter) handlePinnedComparison(ctx *ConvertContext, operator string, value interface{}) error {
if operator != "=" && operator != "!=" {
return errors.Errorf("invalid operator for pinned field")
}
valueBool, ok := value.(bool)
if !ok {
return errors.New("invalid boolean value for pinned field")
}
tablePrefix := c.dialect.GetTablePrefix("memo")
var sqlExpr string
if _, ok := c.dialect.(*PostgreSQLDialect); ok {
sqlExpr = fmt.Sprintf("%s.pinned %s %s", tablePrefix, operator, c.dialect.GetParameterPlaceholder(c.paramIndex))
} else {
sqlExpr = fmt.Sprintf("%s.`pinned` %s %s", tablePrefix, operator, c.dialect.GetParameterPlaceholder(c.paramIndex))
}
if _, err := ctx.Buffer.WriteString(sqlExpr); err != nil {
return err
}
ctx.Args = append(ctx.Args, c.dialect.GetBooleanValue(valueBool))
c.paramIndex++
return nil
}
func (c *CommonSQLConverter) handleBooleanComparison(ctx *ConvertContext, field, operator string, value interface{}) error { func (c *CommonSQLConverter) handleBooleanComparison(ctx *ConvertContext, field, operator string, value interface{}) error {
if operator != "=" && operator != "!=" { if operator != "=" && operator != "!=" {
return errors.Errorf("invalid operator for %s", field) return errors.Errorf("invalid operator for %s", field)
@ -574,7 +605,7 @@ func (c *CommonSQLConverter) handleBooleanComparison(ctx *ConvertContext, field,
// Handle PostgreSQL differently - it uses the raw operator // Handle PostgreSQL differently - it uses the raw operator
if _, ok := c.dialect.(*PostgreSQLDialect); ok { if _, ok := c.dialect.(*PostgreSQLDialect); ok {
var jsonExtract = c.dialect.GetJSONExtract(jsonPath) jsonExtract := c.dialect.GetJSONExtract(jsonPath)
sqlExpr := fmt.Sprintf("(%s)::boolean %s %s", sqlExpr := fmt.Sprintf("(%s)::boolean %s %s",
jsonExtract, jsonExtract,

@ -186,15 +186,17 @@ func (s *APIV1Service) ListMemos(ctx context.Context, request *v1pb.ListMemosReq
memoNames = append(memoNames, fmt.Sprintf("'%s/%s'", MemoNamePrefix, m.UID)) memoNames = append(memoNames, fmt.Sprintf("'%s/%s'", MemoNamePrefix, m.UID))
} }
reactions, err := s.Store.ListReactions(ctx, &store.FindReaction{ if len(memoNames) > 0 {
Filters: []string{fmt.Sprintf("content_id in [%s]", strings.Join(memoNames, ", "))}, reactions, err := s.Store.ListReactions(ctx, &store.FindReaction{
}) Filters: []string{fmt.Sprintf("content_id in [%s]", strings.Join(memoNames, ", "))},
if err != nil { })
return nil, status.Errorf(codes.Internal, "failed to list reactions") if err != nil {
} return nil, status.Errorf(codes.Internal, "failed to list reactions")
}
for _, reaction := range reactions { for _, reaction := range reactions {
reactionMap[reaction.ContentID] = append(reactionMap[reaction.ContentID], reaction) reactionMap[reaction.ContentID] = append(reactionMap[reaction.ContentID], reaction)
}
} }
for _, memo := range memos { for _, memo := range memos {

@ -1,5 +1,5 @@
import { Attachment } from "@/types/proto/api/v1/attachment_service"; import { Attachment } from "@/types/proto/api/v1/attachment_service";
import { getAttachmentUrl } from "@/utils/attachment"; import { getAttachmentUrl, isMidiFile } from "@/utils/attachment";
import AttachmentIcon from "./AttachmentIcon"; import AttachmentIcon from "./AttachmentIcon";
interface Props { interface Props {
@ -19,7 +19,7 @@ const MemoAttachment: React.FC<Props> = (props: Props) => {
<div <div
className={`w-auto flex flex-row justify-start items-center text-muted-foreground hover:text-foreground hover:bg-accent rounded px-2 py-1 transition-colors ${className}`} className={`w-auto flex flex-row justify-start items-center text-muted-foreground hover:text-foreground hover:bg-accent rounded px-2 py-1 transition-colors ${className}`}
> >
{attachment.type.startsWith("audio") ? ( {attachment.type.startsWith("audio") && !isMidiFile(attachment.type) ? (
<audio src={attachmentUrl} controls></audio> <audio src={attachmentUrl} controls></audio>
) : ( ) : (
<> <>

@ -13,7 +13,7 @@ export const getAttachmentType = (attachment: Attachment) => {
return "image/*"; return "image/*";
} else if (attachment.type.startsWith("video")) { } else if (attachment.type.startsWith("video")) {
return "video/*"; return "video/*";
} else if (attachment.type.startsWith("audio")) { } else if (attachment.type.startsWith("audio") && !isMidiFile(attachment.type)) {
return "audio/*"; return "audio/*";
} else if (attachment.type.startsWith("text")) { } else if (attachment.type.startsWith("text")) {
return "text/*"; return "text/*";
@ -40,6 +40,11 @@ export const isImage = (t: string) => {
return t.startsWith("image/") && !isPSD(t); return t.startsWith("image/") && !isPSD(t);
}; };
// isMidiFile returns true if the given mime type is a MIDI file.
export const isMidiFile = (mimeType: string): boolean => {
return mimeType === "audio/midi" || mimeType === "audio/mid" || mimeType === "audio/x-midi" || mimeType === "application/x-midi";
};
const isPSD = (t: string) => { const isPSD = (t: string) => {
return t === "image/vnd.adobe.photoshop" || t === "image/x-photoshop" || t === "image/photoshop"; return t === "image/vnd.adobe.photoshop" || t === "image/x-photoshop" || t === "image/photoshop";
}; };

Loading…
Cancel
Save