diff --git a/packages/api/src/elastic/types.ts b/packages/api/src/elastic/types.ts index d2257748d..320604c3b 100644 --- a/packages/api/src/elastic/types.ts +++ b/packages/api/src/elastic/types.ts @@ -86,7 +86,7 @@ export interface Label { id: string name: string color: string - description?: string + description?: string | null createdAt?: Date } diff --git a/packages/api/src/entity/label.ts b/packages/api/src/entity/label.ts index 30d145f5d..0088e3319 100644 --- a/packages/api/src/entity/label.ts +++ b/packages/api/src/entity/label.ts @@ -24,7 +24,7 @@ export class Label { color!: string @Column('text', { nullable: true }) - description?: string + description?: string | null @CreateDateColumn() createdAt!: Date diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index e78f0c88f..0b98217dd 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -402,7 +402,7 @@ export enum CreateLabelErrorCode { } export type CreateLabelInput = { - color: Scalars['String']; + color?: InputMaybe; description?: InputMaybe; name: Scalars['String']; }; @@ -2187,6 +2187,7 @@ export type SaveError = { export enum SaveErrorCode { EmbeddedHighlightFailed = 'EMBEDDED_HIGHLIGHT_FAILED', + EmbeddedLabelFailed = 'EMBEDDED_LABEL_FAILED', Unauthorized = 'UNAUTHORIZED', Unknown = 'UNKNOWN' } @@ -2225,7 +2226,7 @@ export type SaveFilterSuccess = { export type SavePageInput = { clientRequestId: Scalars['ID']; - labels?: InputMaybe>>; + labels?: InputMaybe>; originalContent: Scalars['String']; parseResult?: InputMaybe; source: Scalars['String']; diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index e4d52b4d0..4d95ef831 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -350,7 +350,7 @@ enum CreateLabelErrorCode { } input CreateLabelInput { - color: String! + color: String description: String name: String! } @@ -1584,6 +1584,7 @@ type SaveError { enum SaveErrorCode { EMBEDDED_HIGHLIGHT_FAILED + EMBEDDED_LABEL_FAILED UNAUTHORIZED UNKNOWN } @@ -1620,7 +1621,7 @@ type SaveFilterSuccess { input SavePageInput { clientRequestId: ID! - labels: [String] + labels: [CreateLabelInput!] originalContent: String! parseResult: ParseResult source: String! diff --git a/packages/api/src/resolvers/labels/index.ts b/packages/api/src/resolvers/labels/index.ts index 31bf420f8..b27c9bf3b 100644 --- a/packages/api/src/resolvers/labels/index.ts +++ b/packages/api/src/resolvers/labels/index.ts @@ -1,4 +1,4 @@ -import { authorized } from '../../utils/helpers' +import { authorized, generateRandomColor } from '../../utils/helpers' import { CreateLabelError, CreateLabelErrorCode, @@ -114,7 +114,7 @@ export const createLabelResolver = authorized< const label = await getRepository(Label).save({ user, name, - color, + color: color || generateRandomColor(), description: description || '', }) diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index efd434e94..2bfee3e6e 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -513,6 +513,7 @@ const schema = gql` UNKNOWN UNAUTHORIZED EMBEDDED_HIGHLIGHT_FAILED + EMBEDDED_LABEL_FAILED } type SaveError { @@ -555,7 +556,7 @@ const schema = gql` originalContent: String! parseResult: ParseResult state: ArticleSavingRequestStatus - labels: [String] + labels: [CreateLabelInput!] } input SaveUrlInput { @@ -1430,7 +1431,7 @@ const schema = gql` input CreateLabelInput { name: String! @sanitize(maxLength: 64) - color: String! @sanitize(pattern: "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$") + color: String @sanitize(pattern: "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$") description: String @sanitize(maxLength: 100) } diff --git a/packages/api/src/services/labels.ts b/packages/api/src/services/labels.ts index b20baeee2..dd7ffa31d 100644 --- a/packages/api/src/services/labels.ts +++ b/packages/api/src/services/labels.ts @@ -2,7 +2,7 @@ import { Label } from '../entity/label' import { ILike, In } from 'typeorm' import { PageContext } from '../elastic/types' import { User } from '../entity/user' -import { addLabelInPage } from '../elastic/labels' +import { addLabelInPage, updateLabelsInPage } from '../elastic/labels' import { getRepository } from '../entity/utils' import { Link } from '../entity/link' import DataLoader from 'dataloader' @@ -103,3 +103,43 @@ export const createLabel = async ( user: { id: userId }, }) } + +export const addLabelsToNewPage = async ( + ctx: PageContext, + pageId: string, + labels: { + name: string + color?: string | null + description?: string | null + }[] +): Promise => { + const user = await getRepository(User).findOneBy({ + id: ctx.uid, + }) + if (!user) { + console.log('user not found') + return false + } + + const labelEntities = await getRepository(Label).findBy({ + user: { id: user.id }, + name: In(labels.map((l) => l.name)), + }) + + const existingLabels = labelEntities.map((l) => l.name) + const newLabels = labels.filter((l) => !existingLabels.includes(l.name)) + // create new labels + const newLabelEntities = await getRepository(Label).save( + newLabels.map((l) => ({ + ...l, + color: l.color || generateRandomColor(), + user, + })) + ) + // add all labels to page + return updateLabelsInPage( + pageId, + [...newLabelEntities, ...labelEntities], + ctx + ) +} diff --git a/packages/api/src/services/save_page.ts b/packages/api/src/services/save_page.ts index 2066a029e..2215f0761 100644 --- a/packages/api/src/services/save_page.ts +++ b/packages/api/src/services/save_page.ts @@ -22,6 +22,7 @@ import { } from '../utils/helpers' import { parsePreparedContent } from '../utils/parser' import { createPageSaveRequest } from './create_page_save_request' +import { addLabelsToNewPage } from './labels' type SaveContext = { pubsub: PubsubClient @@ -174,21 +175,22 @@ export const savePage = async ( type: HighlightType.Highlight, } - if ( - !(await addHighlightToPage(pageId, highlight, { - pubsub: ctx.pubsub, - uid: ctx.uid, - })) - ) { + if (!(await addHighlightToPage(pageId, highlight, ctx))) { return { errorCodes: [SaveErrorCode.EmbeddedHighlightFailed], message: 'Failed to save highlight', } } } - // TODO: add labels to page - // if (pageId && input.labels) { - // } + // add labels to page + if (pageId && input.labels) { + if (!(await addLabelsToNewPage(ctx, pageId, input.labels))) { + return { + errorCodes: [SaveErrorCode.EmbeddedLabelFailed], + message: 'Failed to save labels', + } + } + } return { clientRequestId: pageId, diff --git a/packages/import-handler/src/index.ts b/packages/import-handler/src/index.ts index f02557156..557a57a4a 100644 --- a/packages/import-handler/src/index.ts +++ b/packages/import-handler/src/index.ts @@ -90,7 +90,9 @@ const importURL = async ( url: url.toString(), saveRequestId: uuid(), state, - labels, + labels: labels?.map((l) => { + return { name: l } + }), }) }