diff --git a/.github/renovate.json b/.github/renovate.json index c42ac66181..1cf343236f 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -70,6 +70,7 @@ "commitMessageAction": "bump up", "commitMessageTopic": "{{depName}} version", "ignoreDeps": [], + "postUpdateOptions": ["yarnDedupeHighest"], "lockFileMaintenance": { "enabled": true, "extends": ["schedule:weekly"] diff --git a/.husky/pre-commit b/.husky/pre-commit index 3ea16f0a05..bdcffe4918 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - yarn lint-staged && yarn lint:ox diff --git a/package.json b/package.json index a12b80463d..419c88fd6a 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,8 @@ "test:ui": "vitest --ui", "test:coverage": "vitest run --coverage", "typecheck": "tsc -b tsconfig.json --diagnostics", - "postinstall": "node ./scripts/check-version.mjs && yarn i18n-codegen gen && yarn husky install" + "postinstall": "node ./scripts/check-version.mjs && yarn i18n-codegen gen && yarn husky install", + "prepare": "husky" }, "lint-staged": { "*": "prettier --write --ignore-unknown --cache", @@ -88,7 +89,7 @@ "eslint-plugin-vue": "^9.18.1", "fake-indexeddb": "5.0.2", "happy-dom": "^13.0.0", - "husky": "^8.0.3", + "husky": "^9.0.6", "lint-staged": "^15.1.0", "msw": "^2.0.8", "nanoid": "^5.0.3", diff --git a/packages/backend/server/package.json b/packages/backend/server/package.json index 8344b2accd..3996e18f8d 100644 --- a/packages/backend/server/package.json +++ b/packages/backend/server/package.json @@ -20,7 +20,7 @@ "dependencies": { "@apollo/server": "^4.9.5", "@auth/prisma-adapter": "^1.0.7", - "@aws-sdk/client-s3": "^3.454.0", + "@aws-sdk/client-s3": "^3.499.0", "@google-cloud/opentelemetry-cloud-monitoring-exporter": "^0.17.0", "@google-cloud/opentelemetry-cloud-trace-exporter": "^2.1.0", "@google-cloud/opentelemetry-resource-util": "^2.1.0", diff --git a/packages/backend/server/src/core/features/feature.ts b/packages/backend/server/src/core/features/feature.ts index 99c78a4eba..48d89d53b8 100644 --- a/packages/backend/server/src/core/features/feature.ts +++ b/packages/backend/server/src/core/features/feature.ts @@ -50,7 +50,7 @@ export class UnlimitedWorkspaceFeatureConfig extends FeatureConfig { super(data); if (this.config.feature !== FeatureType.UnlimitedWorkspace) { - throw new Error('Invalid feature config: type is not EarlyAccess'); + throw new Error('Invalid feature config: type is not UnlimitedWorkspace'); } } } diff --git a/packages/backend/server/src/core/quota/index.ts b/packages/backend/server/src/core/quota/index.ts index c49462a968..a84d09a367 100644 --- a/packages/backend/server/src/core/quota/index.ts +++ b/packages/backend/server/src/core/quota/index.ts @@ -1,5 +1,6 @@ import { Module } from '@nestjs/common'; +import { FeatureModule } from '../features'; import { StorageModule } from '../storage'; import { PermissionService } from '../workspaces/permission'; import { QuotaService } from './service'; @@ -12,8 +13,7 @@ import { QuotaManagementService } from './storage'; * - quota statistics */ @Module({ - // FIXME: Quota really need to know `Storage`? - imports: [StorageModule], + imports: [FeatureModule, StorageModule], providers: [PermissionService, QuotaService, QuotaManagementService], exports: [QuotaService, QuotaManagementService], }) diff --git a/packages/backend/server/src/core/quota/quota.ts b/packages/backend/server/src/core/quota/quota.ts index 5139dd02c8..0aaf6d1282 100644 --- a/packages/backend/server/src/core/quota/quota.ts +++ b/packages/backend/server/src/core/quota/quota.ts @@ -57,6 +57,12 @@ export class QuotaConfig { return this.config.configs.blobLimit; } + get businessBlobLimit() { + return ( + this.config.configs.businessBlobLimit || this.config.configs.blobLimit + ); + } + get storageQuota() { return this.config.configs.storageQuota; } diff --git a/packages/backend/server/src/core/quota/schema.ts b/packages/backend/server/src/core/quota/schema.ts index a038ff26f3..8b122d6aed 100644 --- a/packages/backend/server/src/core/quota/schema.ts +++ b/packages/backend/server/src/core/quota/schema.ts @@ -71,11 +71,33 @@ export const Quotas: Quota[] = [ memberLimit: 3, }, }, + { + feature: QuotaType.FreePlanV1, + type: FeatureKind.Quota, + version: 3, + configs: { + // quota name + name: 'Free', + // single blob limit 10MB + blobLimit: 10 * OneMB, + // server limit will larger then client to handle a edge case: + // when a user downgrades from pro to free, he can still continue + // to upload previously added files that exceed the free limit + // NOTE: this is a product decision, may change in future + businessBlobLimit: 100 * OneMB, + // total blob limit 10GB + storageQuota: 10 * OneGB, + // history period of validity 7 days + historyPeriod: 7 * OneDay, + // member limit 3 + memberLimit: 3, + }, + }, ]; export const Quota_FreePlanV1_1 = { - feature: Quotas[3].feature, - version: Quotas[3].version, + feature: Quotas[4].feature, + version: Quotas[4].version, }; export const Quota_ProPlanV1 = { diff --git a/packages/backend/server/src/core/quota/storage.ts b/packages/backend/server/src/core/quota/storage.ts index 70199007f3..234c24df5f 100644 --- a/packages/backend/server/src/core/quota/storage.ts +++ b/packages/backend/server/src/core/quota/storage.ts @@ -1,13 +1,18 @@ import { Injectable, NotFoundException } from '@nestjs/common'; +import { FeatureService, FeatureType } from '../features'; import { WorkspaceBlobStorage } from '../storage'; import { PermissionService } from '../workspaces/permission'; +import { OneGB } from './constant'; import { QuotaService } from './service'; -import { QuotaQueryType } from './types'; +import { formatSize, QuotaQueryType } from './types'; + +type QuotaBusinessType = QuotaQueryType & { businessBlobLimit: number }; @Injectable() export class QuotaManagementService { constructor( + private readonly feature: FeatureService, private readonly quota: QuotaService, private readonly permissions: PermissionService, private readonly storage: WorkspaceBlobStorage @@ -22,10 +27,10 @@ export class QuotaManagementService { createAt: quota.createdAt, expiredAt: quota.expiredAt, blobLimit: quota.feature.blobLimit, + businessBlobLimit: quota.feature.businessBlobLimit, storageQuota: quota.feature.storageQuota, historyPeriod: quota.feature.historyPeriod, memberLimit: quota.feature.memberLimit, - humanReadableName: quota.feature.humanReadable.name, }; } @@ -42,16 +47,60 @@ export class QuotaManagementService { // get workspace's owner quota and total size of used // quota was apply to owner's account - async getWorkspaceUsage(workspaceId: string): Promise { + async getWorkspaceUsage(workspaceId: string): Promise { const { user: owner } = await this.permissions.getWorkspaceOwner(workspaceId); if (!owner) throw new NotFoundException('Workspace owner not found'); - const { humanReadableName, storageQuota, blobLimit } = - await this.getUserQuota(owner.id); + const { + feature: { + name, + blobLimit, + businessBlobLimit, + historyPeriod, + memberLimit, + storageQuota, + humanReadable, + }, + } = await this.quota.getUserQuota(owner.id); // get all workspaces size of owner used const usedSize = await this.getUserUsage(owner.id); - return { humanReadableName, storageQuota, usedSize, blobLimit }; + const quota = { + name, + blobLimit, + businessBlobLimit, + historyPeriod, + memberLimit, + storageQuota, + humanReadable, + usedSize, + }; + + // relax restrictions if workspace has unlimited feature + // todo(@darkskygit): need a mechanism to allow feature as a middleware to edit quota + const unlimited = await this.feature.hasWorkspaceFeature( + workspaceId, + FeatureType.UnlimitedWorkspace + ); + if (unlimited) { + return this.mergeUnlimitedQuota(quota); + } + + return quota; + } + + private mergeUnlimitedQuota(orig: QuotaBusinessType) { + return { + ...orig, + storageQuota: 1000 * OneGB, + memberLimit: 1000, + humanReadable: { + ...orig.humanReadable, + name: 'Unlimited', + storageQuota: formatSize(1000 * OneGB), + memberLimit: '1000', + }, + }; } async checkBlobQuota(workspaceId: string, size: number) { diff --git a/packages/backend/server/src/core/quota/types.ts b/packages/backend/server/src/core/quota/types.ts index ab03a83484..888bedb446 100644 --- a/packages/backend/server/src/core/quota/types.ts +++ b/packages/backend/server/src/core/quota/types.ts @@ -7,6 +7,13 @@ import { ByteUnit, OneDay, OneKB } from './constant'; /// ======== quota define ======== +/** + * naming rule: + * we append Vx to the end of the feature name to indicate the version of the feature + * x is a number, start from 1, this number will be change only at the time we change the schema of config + * for example, we change the value of `blobLimit` from 10MB to 100MB, then we will only change `version` field from 1 to 2 + * but if we remove the `blobLimit` field or rename it, then we will change the Vx to Vx+1 + */ export enum QuotaType { FreePlanV1 = 'free_plan_v1', ProPlanV1 = 'pro_plan_v1', @@ -26,6 +33,7 @@ const quotaPlan = z.object({ storageQuota: z.number().positive().int(), historyPeriod: z.number().positive().int(), memberLimit: z.number().positive().int(), + businessBlobLimit: z.number().positive().int().nullish(), }), }); @@ -41,19 +49,46 @@ export type Quota = z.infer; /// ======== query types ======== +@ObjectType() +export class HumanReadableQuotaType { + @Field(() => String) + name!: string; + + @Field(() => String) + blobLimit!: string; + + @Field(() => String) + storageQuota!: string; + + @Field(() => String) + historyPeriod!: string; + + @Field(() => String) + memberLimit!: string; +} + @ObjectType() export class QuotaQueryType { @Field(() => String) - humanReadableName!: string; + name!: string; + + @Field(() => SafeIntResolver) + blobLimit!: number; + + @Field(() => SafeIntResolver) + historyPeriod!: number; + + @Field(() => SafeIntResolver) + memberLimit!: number; @Field(() => SafeIntResolver) storageQuota!: number; - @Field(() => SafeIntResolver) - usedSize!: number; + @Field(() => HumanReadableQuotaType) + humanReadable!: HumanReadableQuotaType; @Field(() => SafeIntResolver) - blobLimit!: number; + usedSize!: number; } /// ======== utils ======== diff --git a/packages/backend/server/src/core/workspaces/management.ts b/packages/backend/server/src/core/workspaces/management.ts index 635c606499..f4e2752290 100644 --- a/packages/backend/server/src/core/workspaces/management.ts +++ b/packages/backend/server/src/core/workspaces/management.ts @@ -119,7 +119,8 @@ export class WorkspaceManagementResolver { async availableFeatures( @CurrentUser() user: UserType ): Promise { - if (await this.feature.canEarlyAccess(user.email)) { + const isEarlyAccessUser = await this.feature.isEarlyAccessUser(user.email); + if (isEarlyAccessUser) { return [FeatureType.Copilot]; } else { return []; diff --git a/packages/backend/server/src/core/workspaces/resolvers/blob.ts b/packages/backend/server/src/core/workspaces/resolvers/blob.ts index 7f3cba8b12..6429956db8 100644 --- a/packages/backend/server/src/core/workspaces/resolvers/blob.ts +++ b/packages/backend/server/src/core/workspaces/resolvers/blob.ts @@ -128,7 +128,7 @@ export class WorkspaceBlobResolver { Permission.Write ); - const { storageQuota, usedSize, blobLimit } = + const { storageQuota, usedSize, businessBlobLimit } = await this.quota.getWorkspaceUsage(workspaceId); const unlimited = await this.feature.hasWorkspaceFeature( @@ -152,8 +152,10 @@ export class WorkspaceBlobResolver { `storage size limit exceeded: ${total} > ${storageQuota}` ); return true; - } else if (recvSize > blobLimit) { - this.logger.log(`blob size limit exceeded: ${recvSize} > ${blobLimit}`); + } else if (recvSize > businessBlobLimit) { + this.logger.log( + `blob size limit exceeded: ${recvSize} > ${businessBlobLimit}` + ); return true; } else { return false; diff --git a/packages/backend/server/src/core/workspaces/resolvers/workspace.ts b/packages/backend/server/src/core/workspaces/resolvers/workspace.ts index 290f9241f3..6edcad2ac4 100644 --- a/packages/backend/server/src/core/workspaces/resolvers/workspace.ts +++ b/packages/backend/server/src/core/workspaces/resolvers/workspace.ts @@ -30,7 +30,6 @@ import { } from '../../../fundamentals'; import { Auth, CurrentUser, Public } from '../../auth'; import { AuthService } from '../../auth/service'; -import { FeatureManagementService, FeatureType } from '../../features'; import { QuotaManagementService, QuotaQueryType } from '../../quota'; import { WorkspaceBlobStorage } from '../../storage'; import { UsersService, UserType } from '../../users'; @@ -60,7 +59,6 @@ export class WorkspaceResolver { private readonly mailer: MailService, private readonly prisma: PrismaService, private readonly permissions: PermissionService, - private readonly feature: FeatureManagementService, private readonly quota: QuotaManagementService, private readonly users: UsersService, private readonly event: EventEmitter, @@ -338,26 +336,20 @@ export class WorkspaceResolver { throw new ForbiddenException('Cannot change owner'); } - const unlimited = await this.feature.hasWorkspaceFeature( - workspaceId, - FeatureType.UnlimitedWorkspace - ); - if (!unlimited) { - // member limit check - const [memberCount, quota] = await Promise.all([ - this.prisma.workspaceUserPermission.count({ - where: { workspaceId }, - }), - this.quota.getUserQuota(user.id), - ]); - if (memberCount >= quota.memberLimit) { - throw new GraphQLError('Workspace member limit reached', { - extensions: { - status: HttpStatus[HttpStatus.PAYLOAD_TOO_LARGE], - code: HttpStatus.PAYLOAD_TOO_LARGE, - }, - }); - } + // member limit check + const [memberCount, quota] = await Promise.all([ + this.prisma.workspaceUserPermission.count({ + where: { workspaceId }, + }), + this.quota.getWorkspaceUsage(workspaceId), + ]); + if (memberCount >= quota.memberLimit) { + throw new GraphQLError('Workspace member limit reached', { + extensions: { + status: HttpStatus[HttpStatus.PAYLOAD_TOO_LARGE], + code: HttpStatus.PAYLOAD_TOO_LARGE, + }, + }); } let target = await this.users.findUserByEmail(email); diff --git a/packages/backend/server/src/data/migrations/1705395933447-new-free-plan.ts b/packages/backend/server/src/data/migrations/1705395933447-new-free-plan.ts index 0bb5c2dcbf..dc6bf27966 100644 --- a/packages/backend/server/src/data/migrations/1705395933447-new-free-plan.ts +++ b/packages/backend/server/src/data/migrations/1705395933447-new-free-plan.ts @@ -1,65 +1,14 @@ import { PrismaClient } from '@prisma/client'; -import { FeatureKind } from '../../core/features'; import { Quotas } from '../../core/quota'; -import { upsertFeature } from './utils/user-features'; +import { upgradeQuotaVersion } from './utils/user-quotas'; export class NewFreePlan1705395933447 { // do the migration static async up(db: PrismaClient) { - // add new free plan - await upsertFeature(db, Quotas[3]); - // migrate all free plan users to new free plan - await db.$transaction(async tx => { - const latestFreePlan = await tx.features.findFirstOrThrow({ - where: { feature: Quotas[3].feature }, - orderBy: { version: 'desc' }, - select: { id: true }, - }); - - // find all users that have old free plan - const userIds = await db.user.findMany({ - where: { - features: { - every: { - feature: { - type: FeatureKind.Quota, - feature: Quotas[3].feature, - version: { lt: Quotas[3].version }, - }, - activated: true, - }, - }, - }, - select: { id: true }, - }); - - // deactivate all old quota for the user - await tx.userFeatures.updateMany({ - where: { - id: undefined, - userId: { - in: userIds.map(({ id }) => id), - }, - feature: { - type: FeatureKind.Quota, - }, - activated: true, - }, - data: { - activated: false, - }, - }); - - await tx.userFeatures.createMany({ - data: userIds.map(({ id: userId }) => ({ - userId, - featureId: latestFreePlan.id, - reason: 'free plan 1.0 migration', - activated: true, - })), - }); - }); + // free plan 1.0 + const quota = Quotas[3]; + await upgradeQuotaVersion(db, quota, 'free plan 1.0 migration'); } // revert the migration diff --git a/packages/backend/server/src/data/migrations/1706513866287-business-blob-limit.ts b/packages/backend/server/src/data/migrations/1706513866287-business-blob-limit.ts new file mode 100644 index 0000000000..f19aec6fd2 --- /dev/null +++ b/packages/backend/server/src/data/migrations/1706513866287-business-blob-limit.ts @@ -0,0 +1,16 @@ +import { PrismaClient } from '@prisma/client'; + +import { Quotas } from '../../core/quota'; +import { upgradeQuotaVersion } from './utils/user-quotas'; + +export class BusinessBlobLimit1706513866287 { + // do the migration + static async up(db: PrismaClient) { + // free plan 1.1 + const quota = Quotas[4]; + await upgradeQuotaVersion(db, quota, 'free plan 1.1 migration'); + } + + // revert the migration + static async down(_db: PrismaClient) {} +} diff --git a/packages/backend/server/src/data/migrations/utils/user-quotas.ts b/packages/backend/server/src/data/migrations/utils/user-quotas.ts new file mode 100644 index 0000000000..45a59e636c --- /dev/null +++ b/packages/backend/server/src/data/migrations/utils/user-quotas.ts @@ -0,0 +1,65 @@ +import { PrismaClient } from '@prisma/client'; + +import { FeatureKind } from '../../../core/features'; +import { Quota } from '../../../core/quota/types'; +import { upsertFeature } from './user-features'; + +export async function upgradeQuotaVersion( + db: PrismaClient, + quota: Quota, + reason: string +) { + // add new quota + await upsertFeature(db, quota); + // migrate all users that using old quota to new quota + await db.$transaction(async tx => { + const latestQuotaVersion = await tx.features.findFirstOrThrow({ + where: { feature: quota.feature }, + orderBy: { version: 'desc' }, + select: { id: true }, + }); + + // find all users that have old free plan + const userIds = await db.user.findMany({ + where: { + features: { + every: { + feature: { + type: FeatureKind.Quota, + feature: quota.feature, + version: { lt: quota.version }, + }, + activated: true, + }, + }, + }, + select: { id: true }, + }); + + // deactivate all old quota for the user + await tx.userFeatures.updateMany({ + where: { + id: undefined, + userId: { + in: userIds.map(({ id }) => id), + }, + feature: { + type: FeatureKind.Quota, + }, + activated: true, + }, + data: { + activated: false, + }, + }); + + await tx.userFeatures.createMany({ + data: userIds.map(({ id: userId }) => ({ + userId, + featureId: latestQuotaVersion.id, + reason, + activated: true, + })), + }); + }); +} diff --git a/packages/backend/server/src/fundamentals/storage/providers/r2.ts b/packages/backend/server/src/fundamentals/storage/providers/r2.ts index 6e2b9cd5b0..3c38ee7064 100644 --- a/packages/backend/server/src/fundamentals/storage/providers/r2.ts +++ b/packages/backend/server/src/fundamentals/storage/providers/r2.ts @@ -10,6 +10,7 @@ export class R2StorageProvider extends S3StorageProvider { super( { ...config, + forcePathStyle: true, endpoint: `https://${config.accountId}.r2.cloudflarestorage.com`, }, bucket diff --git a/packages/backend/server/src/fundamentals/storage/providers/s3.ts b/packages/backend/server/src/fundamentals/storage/providers/s3.ts index 09d8d83cd3..6e34b416ed 100644 --- a/packages/backend/server/src/fundamentals/storage/providers/s3.ts +++ b/packages/backend/server/src/fundamentals/storage/providers/s3.ts @@ -49,7 +49,7 @@ export class S3StorageProvider implements StorageProvider { new PutObjectCommand({ Bucket: this.bucket, Key: key, - Body: body, + Body: blob, // metadata ContentType: metadata.contentType, diff --git a/packages/backend/server/src/schema.gql b/packages/backend/server/src/schema.gql index 5783aaa545..70cca83979 100644 --- a/packages/backend/server/src/schema.gql +++ b/packages/backend/server/src/schema.gql @@ -24,6 +24,14 @@ enum FeatureType { UnlimitedWorkspace } +type HumanReadableQuotaType { + blobLimit: String! + historyPeriod: String! + memberLimit: String! + name: String! + storageQuota: String! +} + type InvitationType { """Invitee information""" invitee: UserType! @@ -191,7 +199,10 @@ type Query { type QuotaQueryType { blobLimit: SafeInt! - humanReadableName: String! + historyPeriod: SafeInt! + humanReadable: HumanReadableQuotaType! + memberLimit: SafeInt! + name: String! storageQuota: SafeInt! usedSize: SafeInt! } diff --git a/packages/backend/server/tests/quota.spec.ts b/packages/backend/server/tests/quota.spec.ts index d82663e0c0..9c01ebc09e 100644 --- a/packages/backend/server/tests/quota.spec.ts +++ b/packages/backend/server/tests/quota.spec.ts @@ -48,7 +48,7 @@ test('should be able to set quota', async t => { const q1 = await quota.getUserQuota(u1.id); t.truthy(q1, 'should have quota'); t.is(q1?.feature.name, QuotaType.FreePlanV1, 'should be free plan'); - t.is(q1?.feature.version, 2, 'should be version 2'); + t.is(q1?.feature.version, 3, 'should be version 2'); await quota.switchUserQuota(u1.id, QuotaType.ProPlanV1); @@ -64,8 +64,8 @@ test('should be able to check storage quota', async t => { const u1 = await auth.signUp('DarkSky', 'darksky@example.org', '123456'); const q1 = await storageQuota.getUserQuota(u1.id); - t.is(q1?.blobLimit, Quotas[3].configs.blobLimit, 'should be free plan'); - t.is(q1?.storageQuota, Quotas[3].configs.storageQuota, 'should be free plan'); + t.is(q1?.blobLimit, Quotas[4].configs.blobLimit, 'should be free plan'); + t.is(q1?.storageQuota, Quotas[4].configs.storageQuota, 'should be free plan'); await quota.switchUserQuota(u1.id, QuotaType.ProPlanV1); const q2 = await storageQuota.getUserQuota(u1.id); @@ -78,8 +78,8 @@ test('should be able revert quota', async t => { const u1 = await auth.signUp('DarkSky', 'darksky@example.org', '123456'); const q1 = await storageQuota.getUserQuota(u1.id); - t.is(q1?.blobLimit, Quotas[3].configs.blobLimit, 'should be free plan'); - t.is(q1?.storageQuota, Quotas[3].configs.storageQuota, 'should be free plan'); + t.is(q1?.blobLimit, Quotas[4].configs.blobLimit, 'should be free plan'); + t.is(q1?.storageQuota, Quotas[4].configs.storageQuota, 'should be free plan'); await quota.switchUserQuota(u1.id, QuotaType.ProPlanV1); const q2 = await storageQuota.getUserQuota(u1.id); @@ -88,7 +88,7 @@ test('should be able revert quota', async t => { await quota.switchUserQuota(u1.id, QuotaType.FreePlanV1); const q3 = await storageQuota.getUserQuota(u1.id); - t.is(q3?.blobLimit, Quotas[3].configs.blobLimit, 'should be free plan'); + t.is(q3?.blobLimit, Quotas[4].configs.blobLimit, 'should be free plan'); const quotas = await quota.getUserQuotas(u1.id); t.is(quotas.length, 3, 'should have 3 quotas'); diff --git a/packages/common/env/package.json b/packages/common/env/package.json index 2a9224dfea..c341580b0e 100644 --- a/packages/common/env/package.json +++ b/packages/common/env/package.json @@ -3,8 +3,8 @@ "private": true, "type": "module", "devDependencies": { - "@blocksuite/global": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/store": "0.12.0-nightly-202401240410-02f373e", + "@blocksuite/global": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/store": "0.12.0-nightly-202401290223-b6302df", "react": "18.2.0", "react-dom": "18.2.0", "vitest": "1.1.3" diff --git a/packages/common/infra/package.json b/packages/common/infra/package.json index 4d0195f325..f64d9baf8b 100644 --- a/packages/common/infra/package.json +++ b/packages/common/infra/package.json @@ -13,9 +13,9 @@ "@affine/debug": "workspace:*", "@affine/env": "workspace:*", "@affine/templates": "workspace:*", - "@blocksuite/blocks": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/global": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/store": "0.12.0-nightly-202401240410-02f373e", + "@blocksuite/blocks": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/global": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/store": "0.12.0-nightly-202401290223-b6302df", "jotai": "^2.5.1", "jotai-effect": "^0.2.3", "nanoid": "^5.0.3", @@ -26,8 +26,8 @@ "devDependencies": { "@affine-test/fixtures": "workspace:*", "@affine/templates": "workspace:*", - "@blocksuite/lit": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/presets": "0.12.0-nightly-202401240410-02f373e", + "@blocksuite/lit": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/presets": "0.12.0-nightly-202401290223-b6302df", "async-call-rpc": "^6.3.1", "react": "^18.2.0", "rxjs": "^7.8.1", diff --git a/packages/common/y-indexeddb/package.json b/packages/common/y-indexeddb/package.json index 0f75a0c5af..5a08062369 100644 --- a/packages/common/y-indexeddb/package.json +++ b/packages/common/y-indexeddb/package.json @@ -32,14 +32,14 @@ } }, "dependencies": { - "@blocksuite/global": "0.12.0-nightly-202401240410-02f373e", + "@blocksuite/global": "0.12.0-nightly-202401290223-b6302df", "idb": "^8.0.0", "nanoid": "^5.0.3", "y-provider": "workspace:*" }, "devDependencies": { - "@blocksuite/blocks": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/store": "0.12.0-nightly-202401240410-02f373e", + "@blocksuite/blocks": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/store": "0.12.0-nightly-202401290223-b6302df", "fake-indexeddb": "^5.0.0", "vite": "^5.0.6", "vite-plugin-dts": "3.7.0", diff --git a/packages/common/y-provider/package.json b/packages/common/y-provider/package.json index dda146ce58..f1709f3cca 100644 --- a/packages/common/y-provider/package.json +++ b/packages/common/y-provider/package.json @@ -24,7 +24,7 @@ "build": "vite build" }, "devDependencies": { - "@blocksuite/store": "0.12.0-nightly-202401240410-02f373e", + "@blocksuite/store": "0.12.0-nightly-202401290223-b6302df", "vite": "^5.0.6", "vite-plugin-dts": "3.7.0", "vitest": "1.1.3", diff --git a/packages/frontend/component/package.json b/packages/frontend/component/package.json index cb56d94843..f57bdac65a 100644 --- a/packages/frontend/component/package.json +++ b/packages/frontend/component/package.json @@ -73,12 +73,12 @@ "uuid": "^9.0.1" }, "devDependencies": { - "@blocksuite/blocks": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/global": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/icons": "2.1.42", - "@blocksuite/lit": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/presets": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/store": "0.12.0-nightly-202401240410-02f373e", + "@blocksuite/blocks": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/global": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/icons": "2.1.44", + "@blocksuite/lit": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/presets": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/store": "0.12.0-nightly-202401290223-b6302df", "@storybook/addon-actions": "^7.5.3", "@storybook/addon-essentials": "^7.5.3", "@storybook/addon-interactions": "^7.5.3", diff --git a/packages/frontend/component/src/ui/date-picker/week-date-picker.tsx b/packages/frontend/component/src/ui/date-picker/week-date-picker.tsx index 68e1f53cc9..9d2714d481 100644 --- a/packages/frontend/component/src/ui/date-picker/week-date-picker.tsx +++ b/packages/frontend/component/src/ui/date-picker/week-date-picker.tsx @@ -8,6 +8,8 @@ import { useCallback, useEffect, useImperativeHandle, + useLayoutEffect, + useMemo, useRef, useState, } from 'react'; @@ -42,49 +44,67 @@ export const WeekDatePicker = memo(function WeekDatePicker({ const weekRef = useRef(null); const [cursor, setCursor] = useState(dayjs(value)); - const [range, setRange] = useState([0, 7]); const [dense, setDense] = useState(false); - const [allDays, setAllDays] = useState([]); const [viewPortSize, setViewPortSize] = useState(7); useImperativeHandle(handleRef, () => ({ setCursor, })); - const displayDays = allDays.slice(...range); - - const updateRange = useCallback( - (newRange: [number, number]) => { - if (range && newRange[0] === range[0] && newRange[1] === range[1]) return; - setRange(newRange); - }, - [range] + const range = useMemo(() => { + if (viewPortSize === 7) return [0, 7]; + const cursorIndex = cursor.day(); + let start = Math.max(0, cursorIndex - Math.floor(viewPortSize / 2)); + const end = Math.min(7, start + viewPortSize); + if (end === 7) start = 7 - viewPortSize; + return [start, end]; + }, [cursor, viewPortSize]); + const allDays = useMemo( + () => + Array.from({ length: 7 }).map((_, index) => + cursor.startOf('week').add(index, 'day').startOf('day') + ), + [cursor] ); + const displayDays = useMemo(() => allDays.slice(...range), [allDays, range]); const onNext = useCallback(() => { - if (viewPortSize === 7) { - setCursor(cursor.add(1, 'week')); - } else if (range[1] === 7) { - setCursor(cursor.add(1, 'week')); - updateRange([0, viewPortSize]); - } else { - const end = Math.min(range[1] + viewPortSize, 7); - const start = Math.min(range[0] + viewPortSize, end - viewPortSize); - updateRange([start, end]); + const viewPortSize = displayDays.length; + if (viewPortSize === 7) setCursor(c => c.add(1, 'week')); + else { + setCursor(c => { + // last day of week is visible, move to next weeks + if ( + displayDays[displayDays.length - 1].isSame(c.endOf('week'), 'day') + ) { + return c + .add(1, 'week') + .startOf('week') + .add(Math.floor(viewPortSize / 2), 'day'); + } + let nextDay = c.add(viewPortSize, 'day'); + if (!nextDay.isSame(c, 'week')) nextDay = c.endOf('week'); + return nextDay; + }); } - }, [cursor, range, updateRange, viewPortSize]); + }, [displayDays]); const onPrev = useCallback(() => { - if (viewPortSize === 7) { - setCursor(cursor.add(-1, 'week')); - } else if (range[0] === 0) { - setCursor(cursor.add(-1, 'week')); - updateRange([7 - viewPortSize, 7]); - } else { - const start = Math.max(range[0] - viewPortSize, 0); - const end = Math.max(range[1] - viewPortSize, start + viewPortSize); - updateRange([start, end]); - } - }, [cursor, range, updateRange, viewPortSize]); + const viewPortSize = displayDays.length; + if (viewPortSize === 7) setCursor(c => c.add(-1, 'week')); + else + setCursor(c => { + // first day of week is visible, move to prev weeks + if (displayDays[0].isSame(c.startOf('week'), 'day')) { + return c + .subtract(1, 'week') + .endOf('week') + .subtract(Math.floor(viewPortSize / 2) - 1, 'day'); + } + let prevDay = c.add(-viewPortSize, 'day'); + if (!prevDay.isSame(c, 'week')) prevDay = c.startOf('week'); + return prevDay; + }); + }, [displayDays]); const onDayClick = useCallback( (day: dayjs.Dayjs) => { onChange?.(day.format(format)); @@ -115,77 +135,36 @@ export const WeekDatePicker = memo(function WeekDatePicker({ }; }, []); - // update allDays when cursor changes - useEffect(() => { - const firstDay = dayjs(cursor).startOf('week'); - if (allDays[0] && firstDay.isSame(allDays[0], 'day')) return; - - setAllDays( - Array.from({ length: 7 }).map((_, index) => - firstDay.add(index, 'day').startOf('day') - ) - ); - }, [allDays, cursor]); - - // when viewPortSize changes, reset range - useEffect(() => { - if (viewPortSize >= 7) updateRange([0, 7]); - else { - const end = Math.min(7, range[0] + viewPortSize); - const start = Math.max(0, end - viewPortSize); - updateRange([start, end]); - } - }, [range, updateRange, viewPortSize]); - // when value changes, reset cursor useEffect(() => { value && setCursor(dayjs(value)); }, [value]); - // TODO: keyboard navigation - useEffect(() => { + const focusCursorCell = useCallback(() => { + if (!weekRef.current) return; + const cursorCell = weekRef.current.querySelector( + 'button[tabIndex="0"]' + ) as HTMLButtonElement; + cursorCell?.focus(); + }, []); + + useLayoutEffect(() => { if (!weekRef.current) return; const el = weekRef.current; const onKeyDown = (e: KeyboardEvent) => { if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return; e.preventDefault(); e.stopPropagation(); - - const focused = document.activeElement as HTMLElement; - if (!focused) return el.querySelector('button')?.focus(); - const day = dayjs(focused.dataset.value); - if ( - (day.day() === 0 && e.key === 'ArrowLeft') || - (e.key === 'ArrowLeft' && !focused.previousElementSibling) - ) { - onPrev(); - requestAnimationFrame(() => { - el.querySelector('button')?.focus(); - }); - } - - if ( - (day.day() === 6 && e.key === 'ArrowRight') || - (e.key === 'ArrowRight' && !focused.nextElementSibling) - ) { - onNext(); - requestAnimationFrame(() => { - (el.querySelector('button:last-child') as HTMLElement)?.focus(); - }); - } - - if (e.key === 'ArrowLeft' && focused.previousElementSibling) { - (focused.previousElementSibling as HTMLElement).focus(); - } - if (e.key === 'ArrowRight' && focused.nextElementSibling) { - (focused.nextElementSibling as HTMLElement).focus(); - } + setCursor(cursor => cursor.add(e.key === 'ArrowLeft' ? -1 : 1, 'day')); + setTimeout(focusCursorCell); }; + el.addEventListener('keydown', onKeyDown); + return () => { el.removeEventListener('keydown', onKeyDown); }; - }, [onNext, onPrev]); + }, [focusCursorCell, onNext, onPrev]); return (
@@ -230,7 +209,7 @@ const Cell = ({ day, dense, value, cursor, onClick }: CellProps) => { return (
); diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/styles.css.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/styles.css.ts index 107beb00d2..b2f61f37d9 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/styles.css.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/styles.css.ts @@ -29,7 +29,7 @@ export const affineDocViewport = style({ export const docContainer = style({ display: 'block', - flexGrow: 1, + paddingBottom: 64, }); const titleTagBasic = style({ diff --git a/packages/frontend/core/src/components/cloud/share-header-right-item/present.tsx b/packages/frontend/core/src/components/cloud/share-header-right-item/present.tsx index f14f21cf88..b49fecb151 100644 --- a/packages/frontend/core/src/components/cloud/share-header-right-item/present.tsx +++ b/packages/frontend/core/src/components/cloud/share-header-right-item/present.tsx @@ -1,6 +1,6 @@ import { Button } from '@affine/component/ui/button'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; -import type { SurfaceService } from '@blocksuite/blocks'; +import type { EdgelessPageService } from '@blocksuite/blocks'; import { PresentationIcon } from '@blocksuite/icons'; import { useCallback, useEffect, useState } from 'react'; @@ -16,11 +16,22 @@ export const PresentButton = () => { if (!editorRoot || isPresent) return; // TODO: use surfaceService subAtom - const surfaceService = editorRoot?.spec.getService( - 'affine:surface' - ) as SurfaceService; + const enterPresentationMode = () => { + const edgelessPageService = editorRoot?.spec.getService( + 'affine:page' + ) as EdgelessPageService; - surfaceService?.setNavigatorMode(true); + if ( + !edgelessPageService || + edgelessPageService.tool.edgelessTool.type === 'frameNavigator' + ) { + return; + } + + edgelessPageService.tool.setEdgelessTool({ type: 'frameNavigator' }); + }; + + enterPresentationMode(); setIsPresent(true); }, [isPresent]); diff --git a/packages/frontend/core/src/components/page-list/collections/collection-list-header.css.ts b/packages/frontend/core/src/components/page-list/collections/collection-list-header.css.ts new file mode 100644 index 0000000000..a9dff28a9c --- /dev/null +++ b/packages/frontend/core/src/components/page-list/collections/collection-list-header.css.ts @@ -0,0 +1,29 @@ +import { style } from '@vanilla-extract/css'; + +export const collectionListHeader = style({ + height: 100, + alignItems: 'center', + padding: '48px 16px 20px 24px', + overflow: 'hidden', + display: 'flex', + justifyContent: 'space-between', + background: 'var(--affine-background-primary-color)', +}); + +export const collectionListHeaderTitle = style({ + fontSize: 'var(--affine-font-h-5)', + fontWeight: 500, + color: 'var(--affine-text-secondary-color)', + display: 'flex', + alignItems: 'center', + gap: 8, +}); + +export const newCollectionButton = style({ + padding: '6px 10px', + borderRadius: '8px', + background: 'var(--affine-background-primary-color)', + fontSize: 'var(--affine-font-sm)', + fontWeight: 600, + height: '32px', +}); diff --git a/packages/frontend/core/src/components/page-list/collections/collection-list-header.tsx b/packages/frontend/core/src/components/page-list/collections/collection-list-header.tsx new file mode 100644 index 0000000000..2cafde00bb --- /dev/null +++ b/packages/frontend/core/src/components/page-list/collections/collection-list-header.tsx @@ -0,0 +1,29 @@ +import { Button } from '@affine/component'; +import { useAFFiNEI18N } from '@affine/i18n/hooks'; +import type { ReactElement } from 'react'; + +import * as styles from './collection-list-header.css'; + +export const CollectionListHeader = ({ + node, + onCreate, +}: { + node: ReactElement | null; + onCreate: () => void; +}) => { + const t = useAFFiNEI18N(); + + return ( + <> +
+
+ {t['com.affine.collections.header']()} +
+ +
+ {node} + + ); +}; diff --git a/packages/frontend/core/src/components/page-list/page-list-item.css.ts b/packages/frontend/core/src/components/page-list/collections/collection-list-item.css.ts similarity index 100% rename from packages/frontend/core/src/components/page-list/page-list-item.css.ts rename to packages/frontend/core/src/components/page-list/collections/collection-list-item.css.ts diff --git a/packages/frontend/core/src/components/page-list/collections/collection-list-item.tsx b/packages/frontend/core/src/components/page-list/collections/collection-list-item.tsx new file mode 100644 index 0000000000..2edea5dc8a --- /dev/null +++ b/packages/frontend/core/src/components/page-list/collections/collection-list-item.tsx @@ -0,0 +1,206 @@ +import { Checkbox } from '@affine/component'; +import { useAFFiNEI18N } from '@affine/i18n/hooks'; +import { useDraggable } from '@dnd-kit/core'; +import { type PropsWithChildren, useCallback, useMemo } from 'react'; +import { Link } from 'react-router-dom'; + +import type { + CollectionListItemProps, + DraggableTitleCellData, + PageListItemProps, +} from '../types'; +import { ColWrapper, stopPropagation } from '../utils'; +import * as styles from './collection-list-item.css'; + +const ListTitleCell = ({ + title, + preview, +}: Pick) => { + const t = useAFFiNEI18N(); + return ( +
+
+ {title || t['Untitled']()} +
+ {preview ? ( +
+ {preview} +
+ ) : null} +
+ ); +}; + +const ListIconCell = ({ icon }: Pick) => { + return ( +
+ {icon} +
+ ); +}; + +const CollectionSelectionCell = ({ + selectable, + onSelectedChange, + selected, +}: Pick< + CollectionListItemProps, + 'selectable' | 'onSelectedChange' | 'selected' +>) => { + const onSelectionChange = useCallback( + (_event: React.ChangeEvent) => { + return onSelectedChange?.(); + }, + [onSelectedChange] + ); + if (!selectable) { + return null; + } + return ( +
+ +
+ ); +}; + +const CollectionListOperationsCell = ({ + operations, +}: Pick) => { + return operations ? ( +
+ {operations} +
+ ) : null; +}; + +export const CollectionListItem = (props: CollectionListItemProps) => { + const collectionTitleElement = useMemo(() => { + return ( +
+
+ + +
+
+ ); + }, [props.icon, props.onSelectedChange, props.selectable, props.selected]); + + // TODO: use getDropItemId + const { setNodeRef, attributes, listeners, isDragging } = useDraggable({ + id: 'collection-list-item-title-' + props.collectionId, + data: { + pageId: props.collectionId, + pageTitle: collectionTitleElement, + } satisfies DraggableTitleCellData, + disabled: !props.draggable, + }); + + return ( + + + +
+ + +
+ +
+ +
+ {props.operations ? ( + + + + ) : null} +
+ ); +}; + +type collectionListWrapperProps = PropsWithChildren< + Pick< + CollectionListItemProps, + 'to' | 'collectionId' | 'onClick' | 'draggable' + > & { + isDragging: boolean; + } +>; + +function CollectionListItemWrapper({ + to, + isDragging, + collectionId, + onClick, + children, + draggable, +}: collectionListWrapperProps) { + const handleClick = useCallback( + (e: React.MouseEvent) => { + if (onClick) { + stopPropagation(e); + onClick(); + } + }, + [onClick] + ); + + const commonProps = useMemo( + () => ({ + 'data-testid': 'collection-list-item', + 'data-collection-id': collectionId, + 'data-draggable': draggable, + className: styles.root, + 'data-clickable': !!onClick || !!to, + 'data-dragging': isDragging, + onClick: handleClick, + }), + [collectionId, draggable, isDragging, onClick, to, handleClick] + ); + + if (to) { + return ( + + {children} + + ); + } else { + return
{children}
; + } +} diff --git a/packages/frontend/core/src/components/page-list/collections/index.ts b/packages/frontend/core/src/components/page-list/collections/index.ts new file mode 100644 index 0000000000..afed0c1444 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/collections/index.ts @@ -0,0 +1,3 @@ +export * from './collection-list-header'; +export * from './collection-list-item'; +export * from './virtualized-collection-list'; diff --git a/packages/frontend/core/src/components/page-list/collections/virtualized-collection-list.tsx b/packages/frontend/core/src/components/page-list/collections/virtualized-collection-list.tsx new file mode 100644 index 0000000000..7ef7d5024f --- /dev/null +++ b/packages/frontend/core/src/components/page-list/collections/virtualized-collection-list.tsx @@ -0,0 +1,151 @@ +import { collectionsCRUDAtom } from '@affine/core/atoms/collections'; +import { useDeleteCollectionInfo } from '@affine/core/hooks/affine/use-delete-collection-info'; +import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace'; +import type { Collection, DeleteCollectionInfo } from '@affine/env/filter'; +import { Trans } from '@affine/i18n'; +import { useAtomValue } from 'jotai'; +import { + type ReactElement, + useCallback, + useMemo, + useRef, + useState, +} from 'react'; + +import { ListFloatingToolbar } from '../components/list-floating-toolbar'; +import { collectionHeaderColsDef } from '../header-col-def'; +import { CollectionOperationCell } from '../operation-cell'; +import { CollectionListItemRenderer } from '../page-group'; +import { ListTableHeader } from '../page-header'; +import type { CollectionMeta, ItemListHandle, ListItem } from '../types'; +import { useCollectionManager } from '../use-collection-manager'; +import type { AllPageListConfig } from '../view'; +import { VirtualizedList } from '../virtualized-list'; +import { CollectionListHeader } from './collection-list-header'; + +const useCollectionOperationsRenderer = ({ + info, + setting, + config, +}: { + info: DeleteCollectionInfo; + config: AllPageListConfig; + setting: ReturnType; +}) => { + const pageOperationsRenderer = useCallback( + (collection: Collection) => { + return ( + + ); + }, + [config, info, setting] + ); + + return pageOperationsRenderer; +}; + +export const VirtualizedCollectionList = ({ + collections, + collectionMetas, + setHideHeaderCreateNewCollection, + node, + handleCreateCollection, + config, +}: { + collections: Collection[]; + collectionMetas: CollectionMeta[]; + config: AllPageListConfig; + node: ReactElement | null; + handleCreateCollection: () => void; + setHideHeaderCreateNewCollection: (hide: boolean) => void; +}) => { + const listRef = useRef(null); + const [showFloatingToolbar, setShowFloatingToolbar] = useState(false); + const [selectedCollectionIds, setSelectedCollectionIds] = useState( + [] + ); + const setting = useCollectionManager(collectionsCRUDAtom); + const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom); + const info = useDeleteCollectionInfo(); + + const collectionOperations = useCollectionOperationsRenderer({ + info, + setting, + config, + }); + + const filteredSelectedCollectionIds = useMemo(() => { + const ids = collections.map(collection => collection.id); + return selectedCollectionIds.filter(id => ids.includes(id)); + }, [collections, selectedCollectionIds]); + + const hideFloatingToolbar = useCallback(() => { + listRef.current?.toggleSelectable(); + }, []); + + const collectionOperationRenderer = useCallback( + (item: ListItem) => { + const collection = item as CollectionMeta; + return collectionOperations(collection); + }, + [collectionOperations] + ); + + const collectionHeaderRenderer = useCallback(() => { + return ; + }, []); + + const collectionItemRenderer = useCallback((item: ListItem) => { + return ; + }, []); + + const handleDelete = useCallback(() => { + return setting.deleteCollection(info, ...selectedCollectionIds); + }, [setting, info, selectedCollectionIds]); + + return ( + <> + + } + selectedIds={filteredSelectedCollectionIds} + onSelectedIdsChange={setSelectedCollectionIds} + items={collectionMetas} + itemRenderer={collectionItemRenderer} + rowAsLink + blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace} + operationsRenderer={collectionOperationRenderer} + headerRenderer={collectionHeaderRenderer} + /> + 0} + content={ + +
+ {{ count: selectedCollectionIds.length } as any} +
+ selected +
+ } + onClose={hideFloatingToolbar} + onDelete={handleDelete} + /> + + ); +}; diff --git a/packages/frontend/core/src/components/page-list/components/floating-toobar.tsx b/packages/frontend/core/src/components/page-list/components/floating-toolbar.tsx similarity index 100% rename from packages/frontend/core/src/components/page-list/components/floating-toobar.tsx rename to packages/frontend/core/src/components/page-list/components/floating-toolbar.tsx diff --git a/packages/frontend/core/src/components/page-list/components/list-floating-toolbar.css.ts b/packages/frontend/core/src/components/page-list/components/list-floating-toolbar.css.ts new file mode 100644 index 0000000000..3f68e4a83e --- /dev/null +++ b/packages/frontend/core/src/components/page-list/components/list-floating-toolbar.css.ts @@ -0,0 +1,8 @@ +import { style } from '@vanilla-extract/css'; + +export const floatingToolbar = style({ + position: 'absolute', + bottom: 26, + width: '100%', + zIndex: 1, +}); diff --git a/packages/frontend/core/src/components/page-list/components/list-floating-toolbar.tsx b/packages/frontend/core/src/components/page-list/components/list-floating-toolbar.tsx new file mode 100644 index 0000000000..98ad6b4b81 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/components/list-floating-toolbar.tsx @@ -0,0 +1,31 @@ +import { CloseIcon, DeleteIcon } from '@blocksuite/icons'; +import type { ReactNode } from 'react'; + +import { FloatingToolbar } from './floating-toolbar'; +import * as styles from './list-floating-toolbar.css'; + +export const ListFloatingToolbar = ({ + content, + onClose, + open, + onDelete, +}: { + open: boolean; + content: ReactNode; + onClose: () => void; + onDelete: () => void; +}) => { + return ( + + {content} + } /> + + } + type="danger" + data-testid="list-toolbar-delete" + /> + + ); +}; diff --git a/packages/frontend/core/src/components/page-list/components/list-header-cell.css.ts b/packages/frontend/core/src/components/page-list/components/list-header-cell.css.ts new file mode 100644 index 0000000000..1edfac3296 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/components/list-header-cell.css.ts @@ -0,0 +1,30 @@ +import { style } from '@vanilla-extract/css'; + +export const headerCell = style({ + padding: '0 8px', + userSelect: 'none', + fontSize: 'var(--affine-font-xs)', + color: 'var(--affine-text-secondary-color)', + selectors: { + '&[data-sorting], &:hover': { + color: 'var(--affine-text-primary-color)', + }, + '&[data-sortable]': { + cursor: 'pointer', + }, + '&:not(:last-child)': { + borderRight: '1px solid var(--affine-hover-color-filled)', + }, + }, + display: 'flex', + alignItems: 'center', + columnGap: '4px', + position: 'relative', + whiteSpace: 'nowrap', +}); + +export const headerCellSortIcon = style({ + display: 'inline-flex', + fontSize: 14, + color: 'var(--affine-icon-color)', +}); diff --git a/packages/frontend/core/src/components/page-list/components/list-header-cell.tsx b/packages/frontend/core/src/components/page-list/components/list-header-cell.tsx new file mode 100644 index 0000000000..1fbde3409f --- /dev/null +++ b/packages/frontend/core/src/components/page-list/components/list-header-cell.tsx @@ -0,0 +1,54 @@ +import { SortDownIcon, SortUpIcon } from '@blocksuite/icons'; +import { useCallback } from 'react'; + +import type { ColWrapperProps, ListItem } from '../types'; +import { ColWrapper } from '../utils'; +import * as styles from './list-header-cell.css'; + +type HeaderCellProps = ColWrapperProps & { + sortKey: keyof ListItem; + sortable?: boolean; + order?: 'asc' | 'desc'; + sorting?: boolean; + onSort?: (sortable?: boolean, sortKey?: keyof ListItem) => void; +}; + +export const ListHeaderCell = ({ + sortKey, + sortable, + order, + sorting, + onSort, + alignment, + flex, + style, + hideInSmallContainer, + children, +}: HeaderCellProps) => { + const handleClick = useCallback(() => { + if (sortable) { + onSort?.(sortable, sortKey); + } + }, [sortable, sortKey, onSort]); + + return ( + + {children} + {sorting ? ( +
+ {order === 'asc' ? : } +
+ ) : null} +
+ ); +}; diff --git a/packages/frontend/core/src/components/page-list/components/new-page-buttton.tsx b/packages/frontend/core/src/components/page-list/components/new-page-button.tsx similarity index 100% rename from packages/frontend/core/src/components/page-list/components/new-page-buttton.tsx rename to packages/frontend/core/src/components/page-list/components/new-page-button.tsx diff --git a/packages/frontend/core/src/components/page-list/docs/index.ts b/packages/frontend/core/src/components/page-list/docs/index.ts new file mode 100644 index 0000000000..a122e4f001 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/docs/index.ts @@ -0,0 +1,5 @@ +export * from './page-list-header'; +export * from './page-list-item'; +export * from './page-list-new-page-button'; +export * from './page-tags'; +export * from './virtualized-page-list'; diff --git a/packages/frontend/core/src/components/page-list/docs/page-list-header.css.ts b/packages/frontend/core/src/components/page-list/docs/page-list-header.css.ts new file mode 100644 index 0000000000..792d1896c2 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/docs/page-list-header.css.ts @@ -0,0 +1,71 @@ +import { style } from '@vanilla-extract/css'; + +export const docListHeader = style({ + height: 100, + alignItems: 'center', + padding: '48px 16px 20px 24px', + overflow: 'hidden', + display: 'flex', + justifyContent: 'space-between', + background: 'var(--affine-background-primary-color)', +}); + +export const docListHeaderTitle = style({ + fontSize: 'var(--affine-font-h-5)', + fontWeight: 500, + color: 'var(--affine-text-secondary-color)', + display: 'flex', + alignItems: 'center', + gap: 8, + height: '28px', +}); + +export const titleIcon = style({ + color: 'var(--affine-icon-color)', + display: 'inline-flex', + alignItems: 'center', +}); + +export const titleCollectionName = style({ + color: 'var(--affine-text-primary-color)', +}); + +export const addPageButton = style({ + padding: '6px 10px', + borderRadius: '8px', + background: 'var(--affine-background-primary-color)', + fontSize: 'var(--affine-font-sm)', + fontWeight: 600, + height: '32px', +}); + +export const tagSticky = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + padding: '1px 8px', + color: 'var(--affine-text-primary-color)', + fontSize: 'var(--affine-font-xs)', + borderRadius: '10px', + columnGap: '4px', + border: '1px solid var(--affine-border-color)', + background: 'var(--affine-background-primary-color)', + maxWidth: '30vw', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + height: '22px', + lineHeight: '1.67em', +}); + +export const tagIndicator = style({ + width: '8px', + height: '8px', + borderRadius: '50%', + flexShrink: 0, +}); + +export const tagLabel = style({ + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', +}); diff --git a/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx b/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx new file mode 100644 index 0000000000..e5ef4836e3 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx @@ -0,0 +1,181 @@ +import { Button } from '@affine/component'; +import { collectionsCRUDAtom } from '@affine/core/atoms/collections'; +import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper'; +import type { Collection, Tag } from '@affine/env/filter'; +import { useAFFiNEI18N } from '@affine/i18n/hooks'; +import { ViewLayersIcon } from '@blocksuite/icons'; +import { nanoid } from 'nanoid'; +import { useCallback, useMemo } from 'react'; + +import { createTagFilter } from '../filter/utils'; +import { + createEmptyCollection, + useCollectionManager, +} from '../use-collection-manager'; +import { tagColorMap } from '../utils'; +import type { AllPageListConfig } from '../view/edit-collection/edit-collection'; +import { + useEditCollection, + useEditCollectionName, +} from '../view/use-edit-collection'; +import * as styles from './page-list-header.css'; +import { PageListNewPageButton } from './page-list-new-page-button'; + +export const PageListHeader = ({ workspaceId }: { workspaceId: string }) => { + const t = useAFFiNEI18N(); + const setting = useCollectionManager(collectionsCRUDAtom); + const { jumpToCollections } = useNavigateHelper(); + + const handleJumpToCollections = useCallback(() => { + jumpToCollections(workspaceId); + }, [jumpToCollections, workspaceId]); + + const title = useMemo(() => { + if (setting.isDefault) { + return t['com.affine.all-pages.header'](); + } + return ( + <> +
+ {t['com.affine.collections.header']()} / +
+
+ +
+
+ {setting.currentCollection.name} +
+ + ); + }, [ + handleJumpToCollections, + setting.currentCollection.name, + setting.isDefault, + t, + ]); + + return ( +
+
{title}
+ + {t['New Page']()} + +
+ ); +}; +export const CollectionPageListHeader = ({ + collection, + workspaceId, + config, +}: { + config: AllPageListConfig; + collection: Collection; + workspaceId: string; +}) => { + const t = useAFFiNEI18N(); + const setting = useCollectionManager(collectionsCRUDAtom); + const { jumpToCollections } = useNavigateHelper(); + + const handleJumpToCollections = useCallback(() => { + jumpToCollections(workspaceId); + }, [jumpToCollections, workspaceId]); + + const { updateCollection } = useCollectionManager(collectionsCRUDAtom); + const { node, open } = useEditCollection(config); + + const handleAddPage = useAsyncCallback(async () => { + const ret = await open({ ...collection }, 'page'); + updateCollection(ret); + }, [collection, open, updateCollection]); + + return ( + <> + {node} +
+
+
+ {t['com.affine.collections.header']()} / +
+
+ +
+
+ {setting.currentCollection.name} +
+
+ +
+ + ); +}; + +export const TagPageListHeader = ({ + tag, + workspaceId, +}: { + tag: Tag; + workspaceId: string; +}) => { + const t = useAFFiNEI18N(); + const { jumpToTags, jumpToCollection } = useNavigateHelper(); + const setting = useCollectionManager(collectionsCRUDAtom); + const { open, node } = useEditCollectionName({ + title: t['com.affine.editCollection.saveCollection'](), + showTips: true, + }); + + const handleJumpToTags = useCallback(() => { + jumpToTags(workspaceId); + }, [jumpToTags, workspaceId]); + + const saveToCollection = useCallback( + (collection: Collection) => { + setting.createCollection({ + ...collection, + filterList: [createTagFilter(tag.id)], + }); + jumpToCollection(workspaceId, collection.id); + }, + [setting, tag.id, jumpToCollection, workspaceId] + ); + const handleClick = useCallback(() => { + open('') + .then(name => { + return saveToCollection(createEmptyCollection(nanoid(), { name })); + }) + .catch(err => { + console.error(err); + }); + }, [open, saveToCollection]); + + return ( + <> + {node} +
+
+
+ {t['Tags']()} / +
+
+
+
{tag.value}
+
+
+ +
+ + ); +}; diff --git a/packages/frontend/core/src/components/page-list/docs/page-list-item.css.ts b/packages/frontend/core/src/components/page-list/docs/page-list-item.css.ts new file mode 100644 index 0000000000..82cd0b6572 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/docs/page-list-item.css.ts @@ -0,0 +1,181 @@ +import { globalStyle, style } from '@vanilla-extract/css'; + +export const root = style({ + display: 'flex', + color: 'var(--affine-text-primary-color)', + height: '54px', // 42 + 12 + flexShrink: 0, + width: '100%', + alignItems: 'stretch', + transition: 'background-color 0.2s, opacity 0.2s', + ':hover': { + backgroundColor: 'var(--affine-hover-color)', + }, + overflow: 'hidden', + cursor: 'default', + willChange: 'opacity', + selectors: { + '&[data-clickable=true]': { + cursor: 'pointer', + }, + }, +}); + +export const dragOverlay = style({ + display: 'flex', + alignItems: 'center', + zIndex: 1001, + cursor: 'grabbing', + maxWidth: '360px', + transition: 'transform 0.2s', + willChange: 'transform', + selectors: { + '&[data-over=true]': { + transform: 'scale(0.8)', + }, + }, +}); +export const dragPageItemOverlay = style({ + height: '54px', + borderRadius: '10px', + display: 'flex', + alignItems: 'center', + background: 'var(--affine-hover-color-filled)', + boxShadow: 'var(--affine-menu-shadow)', + maxWidth: '360px', + minWidth: '260px', +}); + +export const dndCell = style({ + position: 'relative', + marginLeft: -8, + height: '100%', + outline: 'none', + paddingLeft: 8, +}); + +globalStyle(`[data-draggable=true] ${dndCell}:before`, { + content: '""', + position: 'absolute', + top: '50%', + transform: 'translateY(-50%)', + left: 0, + width: 4, + height: 4, + transition: 'height 0.2s, opacity 0.2s', + backgroundColor: 'var(--affine-placeholder-color)', + borderRadius: '2px', + opacity: 0, + willChange: 'height, opacity', +}); + +globalStyle(`[data-draggable=true] ${dndCell}:hover:before`, { + height: 12, + opacity: 1, +}); + +globalStyle(`[data-draggable=true][data-dragging=true] ${dndCell}`, { + opacity: 0.5, +}); + +globalStyle(`[data-draggable=true][data-dragging=true] ${dndCell}:before`, { + height: 32, + width: 2, + opacity: 1, +}); + +// todo: remove global style +globalStyle(`${root} > :first-child`, { + paddingLeft: '16px', +}); + +globalStyle(`${root} > :last-child`, { + paddingRight: '8px', +}); + +export const titleIconsWrapper = style({ + padding: '0 5px', + display: 'flex', + alignItems: 'center', + gap: '10px', +}); + +export const selectionCell = style({ + display: 'flex', + alignItems: 'center', + flexShrink: 0, + fontSize: 'var(--affine-font-h-3)', +}); + +export const titleCell = style({ + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-start', + padding: '0 16px', + maxWidth: 'calc(100% - 64px)', + flex: 1, + whiteSpace: 'nowrap', +}); + +export const titleCellMain = style({ + overflow: 'hidden', + fontSize: 'var(--affine-font-sm)', + fontWeight: 600, + whiteSpace: 'nowrap', + flex: 1, + textOverflow: 'ellipsis', + alignSelf: 'stretch', +}); + +export const titleCellPreview = style({ + overflow: 'hidden', + color: 'var(--affine-text-secondary-color)', + fontSize: 'var(--affine-font-xs)', + flex: 1, + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + alignSelf: 'stretch', +}); + +export const iconCell = style({ + display: 'flex', + alignItems: 'center', + fontSize: 'var(--affine-font-h-3)', + color: 'var(--affine-icon-color)', + flexShrink: 0, +}); + +export const tagsCell = style({ + display: 'flex', + alignItems: 'center', + fontSize: 'var(--affine-font-xs)', + color: 'var(--affine-text-secondary-color)', + padding: '0 8px', + height: '60px', + width: '100%', +}); + +export const dateCell = style({ + display: 'flex', + alignItems: 'center', + fontSize: 'var(--affine-font-xs)', + color: 'var(--affine-text-secondary-color)', + flexShrink: 0, + flexWrap: 'nowrap', + padding: '0 8px', +}); + +export const actionsCellWrapper = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + flexShrink: 0, +}); + +export const operationsCell = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + columnGap: '6px', + flexShrink: 0, +}); diff --git a/packages/frontend/core/src/components/page-list/page-list-item.tsx b/packages/frontend/core/src/components/page-list/docs/page-list-item.tsx similarity index 93% rename from packages/frontend/core/src/components/page-list/page-list-item.tsx rename to packages/frontend/core/src/components/page-list/docs/page-list-item.tsx index 775b86be8d..2b02a63a63 100644 --- a/packages/frontend/core/src/components/page-list/page-list-item.tsx +++ b/packages/frontend/core/src/components/page-list/docs/page-list-item.tsx @@ -4,12 +4,12 @@ import { useDraggable } from '@dnd-kit/core'; import { type PropsWithChildren, useCallback, useMemo } from 'react'; import { Link } from 'react-router-dom'; +import type { DraggableTitleCellData, PageListItemProps } from '../types'; +import { ColWrapper, formatDate, stopPropagation } from '../utils'; import * as styles from './page-list-item.css'; import { PageTags } from './page-tags'; -import type { DraggableTitleCellData, PageListItemProps } from './types'; -import { ColWrapper, formatDate, stopPropagation } from './utils'; -const PageListTitleCell = ({ +const ListTitleCell = ({ title, preview, }: Pick) => { @@ -34,7 +34,7 @@ const PageListTitleCell = ({ ); }; -const PageListIconCell = ({ icon }: Pick) => { +const ListIconCell = ({ icon }: Pick) => { return (
{icon} @@ -128,9 +128,9 @@ export const PageListItem = (props: PageListItemProps) => { selectable={props.selectable} selected={props.selected} /> - +
- +
); }, [ @@ -174,9 +174,9 @@ export const PageListItem = (props: PageListItemProps) => { selectable={props.selectable} selected={props.selected} /> - + - + diff --git a/packages/frontend/core/src/components/page-list/docs/page-list-new-page-button.css.ts b/packages/frontend/core/src/components/page-list/docs/page-list-new-page-button.css.ts new file mode 100644 index 0000000000..ca86af65cf --- /dev/null +++ b/packages/frontend/core/src/components/page-list/docs/page-list-new-page-button.css.ts @@ -0,0 +1,6 @@ +import { style } from '@vanilla-extract/css'; + +export const newPageButtonLabel = style({ + display: 'flex', + alignItems: 'center', +}); diff --git a/packages/frontend/core/src/components/page-list/docs/page-list-new-page-button.tsx b/packages/frontend/core/src/components/page-list/docs/page-list-new-page-button.tsx new file mode 100644 index 0000000000..17e9601ca4 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/docs/page-list-new-page-button.tsx @@ -0,0 +1,35 @@ +import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace'; +import { useAtomValue } from 'jotai'; +import type { PropsWithChildren } from 'react'; + +import { usePageHelper } from '../../blocksuite/block-suite-page-list/utils'; +import { NewPageButton } from '../components/new-page-button'; +import * as styles from './page-list-new-page-button.css'; + +export const PageListNewPageButton = ({ + className, + children, + size, + testId, +}: PropsWithChildren<{ + className?: string; + size?: 'small' | 'default'; + testId?: string; +}>) => { + const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom); + const { importFile, createEdgeless, createPage } = usePageHelper( + currentWorkspace.blockSuiteWorkspace + ); + return ( +
+ +
{children}
+
+
+ ); +}; diff --git a/packages/frontend/core/src/components/page-list/page-tags.css.ts b/packages/frontend/core/src/components/page-list/docs/page-tags.css.ts similarity index 100% rename from packages/frontend/core/src/components/page-list/page-tags.css.ts rename to packages/frontend/core/src/components/page-list/docs/page-tags.css.ts diff --git a/packages/frontend/core/src/components/page-list/page-tags.tsx b/packages/frontend/core/src/components/page-list/docs/page-tags.tsx similarity index 75% rename from packages/frontend/core/src/components/page-list/page-tags.tsx rename to packages/frontend/core/src/components/page-list/docs/page-tags.tsx index 994e91bdf9..6cdf11bf40 100644 --- a/packages/frontend/core/src/components/page-list/page-tags.tsx +++ b/packages/frontend/core/src/components/page-list/docs/page-tags.tsx @@ -5,8 +5,8 @@ import { assignInlineVars } from '@vanilla-extract/dynamic'; import clsx from 'clsx'; import { useMemo } from 'react'; +import { stopPropagation, tagColorMap } from '../utils'; import * as styles from './page-tags.css'; -import { stopPropagation } from './utils'; export interface PageTagsProps { tags: Tag[]; @@ -22,24 +22,7 @@ interface TagItemProps { style?: React.CSSProperties; } -// hack: map var(--affine-tag-xxx) colors to var(--affine-palette-line-xxx) -const tagColorMap = (color: string) => { - const mapping: Record = { - 'var(--affine-tag-red)': 'var(--affine-palette-line-red)', - 'var(--affine-tag-teal)': 'var(--affine-palette-line-green)', - 'var(--affine-tag-blue)': 'var(--affine-palette-line-blue)', - 'var(--affine-tag-yellow)': 'var(--affine-palette-line-yellow)', - 'var(--affine-tag-pink)': 'var(--affine-palette-line-magenta)', - 'var(--affine-tag-white)': 'var(--affine-palette-line-grey)', - 'var(--affine-tag-gray)': 'var(--affine-palette-line-grey)', - 'var(--affine-tag-orange)': 'var(--affine-palette-line-orange)', - 'var(--affine-tag-purple)': 'var(--affine-palette-line-purple)', - 'var(--affine-tag-green)': 'var(--affine-palette-line-green)', - }; - return mapping[color] || color; -}; - -const TagItem = ({ tag, idx, mode, style }: TagItemProps) => { +export const TagItem = ({ tag, idx, mode, style }: TagItemProps) => { return (
{ + const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom); + const { setTrashModal } = useTrashModalHelper( + currentWorkspace.blockSuiteWorkspace + ); + const { toggleFavorite } = useBlockSuiteMetaHelper( + currentWorkspace.blockSuiteWorkspace + ); + const t = useAFFiNEI18N(); + const pageOperationsRenderer = useCallback( + (page: PageMeta) => { + const onDisablePublicSharing = () => { + toast('Successfully disabled', { + portal: document.body, + }); + }; + return ( + + setTrashModal({ + open: true, + pageIds: [page.id], + pageTitles: [page.title], + }) + } + onToggleFavoritePage={() => { + const status = page.favorite; + toggleFavorite(page.id); + toast( + status + ? t['com.affine.toastMessage.removedFavorites']() + : t['com.affine.toastMessage.addedFavorites']() + ); + }} + /> + ); + }, + [currentWorkspace.id, setTrashModal, t, toggleFavorite] + ); + + return pageOperationsRenderer; +}; + +export const VirtualizedPageList = ({ + tag, + collection, + config, + listItem, + setHideHeaderCreateNewPage, +}: { + tag?: Tag; + collection?: Collection; + config?: AllPageListConfig; + listItem?: PageMeta[]; + setHideHeaderCreateNewPage: (hide: boolean) => void; +}) => { + const listRef = useRef(null); + const [showFloatingToolbar, setShowFloatingToolbar] = useState(false); + const [selectedPageIds, setSelectedPageIds] = useState([]); + const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom); + const pageMetas = useBlockSuitePageMeta(currentWorkspace.blockSuiteWorkspace); + const pageOperations = usePageOperationsRenderer(); + const { isPreferredEdgeless } = usePageHelper( + currentWorkspace.blockSuiteWorkspace + ); + + const filteredPageMetas = useFilteredPageMetas( + 'all', + pageMetas, + currentWorkspace.blockSuiteWorkspace + ); + const pageMetasToRender = useMemo(() => { + if (listItem) { + return listItem; + } + return filteredPageMetas; + }, [filteredPageMetas, listItem]); + + const filteredSelectedPageIds = useMemo(() => { + const ids = pageMetasToRender.map(page => page.id); + return selectedPageIds.filter(id => ids.includes(id)); + }, [pageMetasToRender, selectedPageIds]); + + const hideFloatingToolbar = useCallback(() => { + listRef.current?.toggleSelectable(); + }, []); + + const pageOperationRenderer = useCallback( + (item: ListItem) => { + const page = item as PageMeta; + return pageOperations(page); + }, + [pageOperations] + ); + + const pageHeaderRenderer = useCallback(() => { + return ; + }, []); + + const pageItemRenderer = useCallback((item: ListItem) => { + return ; + }, []); + + const heading = useMemo(() => { + if (tag) { + return ; + } + if (collection && config) { + return ( + + ); + } + return ; + }, [collection, config, currentWorkspace.id, tag]); + + const { setTrashModal } = useTrashModalHelper( + currentWorkspace.blockSuiteWorkspace + ); + + const handleMultiDelete = useCallback(() => { + const pageNameMapping = Object.fromEntries( + pageMetas.map(meta => [meta.id, meta.title]) + ); + + const pageNames = filteredSelectedPageIds.map( + id => pageNameMapping[id] ?? '' + ); + setTrashModal({ + open: true, + pageIds: filteredSelectedPageIds, + pageTitles: pageNames, + }); + hideFloatingToolbar(); + }, [filteredSelectedPageIds, hideFloatingToolbar, pageMetas, setTrashModal]); + + return ( + <> + + 0} + onDelete={handleMultiDelete} + onClose={hideFloatingToolbar} + content={ + +
+ {{ count: filteredSelectedPageIds.length } as any} +
+ selected +
+ } + /> + + ); +}; diff --git a/packages/frontend/core/src/components/page-list/header-col-def.tsx b/packages/frontend/core/src/components/page-list/header-col-def.tsx new file mode 100644 index 0000000000..60268b834f --- /dev/null +++ b/packages/frontend/core/src/components/page-list/header-col-def.tsx @@ -0,0 +1,68 @@ +import { Trans } from '@affine/i18n'; + +import { ListHeaderTitleCell } from './page-header'; +import type { HeaderColDef } from './types'; + +export const pageHeaderColsDef: HeaderColDef[] = [ + { + key: 'title', + content: , + flex: 6, + alignment: 'start', + sortable: true, + }, + { + key: 'tags', + content: , + flex: 3, + alignment: 'end', + }, + { + key: 'createDate', + content: , + flex: 1, + sortable: true, + alignment: 'end', + hideInSmallContainer: true, + }, + { + key: 'updatedDate', + content: , + flex: 1, + sortable: true, + alignment: 'end', + hideInSmallContainer: true, + }, + { + key: 'actions', + content: '', + flex: 1, + alignment: 'end', + }, +]; + +export const collectionHeaderColsDef: HeaderColDef[] = [ + { + key: 'title', + content: , + flex: 9, + alignment: 'start', + sortable: true, + }, +]; + +export const tagHeaderColsDef: HeaderColDef[] = [ + { + key: 'title', + content: , + flex: 8, + alignment: 'start', + sortable: true, + }, + { + key: 'actions', + content: '', + flex: 1, + alignment: 'end', + }, +]; diff --git a/packages/frontend/core/src/components/page-list/index.tsx b/packages/frontend/core/src/components/page-list/index.tsx index 6a500cb2a6..cc8887d1e4 100644 --- a/packages/frontend/core/src/components/page-list/index.tsx +++ b/packages/frontend/core/src/components/page-list/index.tsx @@ -1,14 +1,22 @@ +export * from './collections'; export * from './components/favorite-tag'; -export * from './components/floating-toobar'; -export * from './components/new-page-buttton'; +export * from './components/floating-toolbar'; +export * from './components/new-page-button'; +export * from './docs'; +export * from './docs/page-list-item'; +export * from './docs/page-tags'; export * from './filter'; +export * from './header-col-def'; +export * from './list'; export * from './operation-cell'; export * from './operation-menu-items'; -export * from './page-list'; -export * from './page-list-item'; -export * from './page-tags'; +export * from './page-group'; +export * from './page-header'; +export * from './tags'; export * from './types'; export * from './use-collection-manager'; +export * from './use-filtered-page-metas'; +export * from './use-tag-metas'; export * from './utils'; export * from './view'; -export * from './virtualized-page-list'; +export * from './virtualized-list'; diff --git a/packages/frontend/core/src/components/page-list/pages-to-page-group.tsx b/packages/frontend/core/src/components/page-list/items-to-item-group.tsx similarity index 57% rename from packages/frontend/core/src/components/page-list/pages-to-page-group.tsx rename to packages/frontend/core/src/components/page-list/items-to-item-group.tsx index cb272368c5..3e327f83e5 100644 --- a/packages/frontend/core/src/components/page-list/pages-to-page-group.tsx +++ b/packages/frontend/core/src/components/page-list/items-to-item-group.tsx @@ -1,72 +1,77 @@ import { Trans } from '@affine/i18n'; -import type { PageMeta } from '@blocksuite/store'; -import type { PageGroupDefinition, PageGroupProps } from './types'; +import type { ItemGroupDefinition, ItemGroupProps, ListItem } from './types'; import { type DateKey } from './types'; import { betweenDaysAgo, withinDaysAgo } from './utils'; // todo: optimize date matchers -const getDateGroupDefinitions = (key: DateKey): PageGroupDefinition[] => [ +const getDateGroupDefinitions = ( + key: DateKey +): ItemGroupDefinition[] => [ { id: 'today', label: , - match: item => withinDaysAgo(new Date(item[key] ?? item.createDate), 1), + match: item => + withinDaysAgo(new Date(item[key] ?? item.createDate ?? ''), 1), }, { id: 'yesterday', label: , - match: item => betweenDaysAgo(new Date(item[key] ?? item.createDate), 1, 2), + match: item => + betweenDaysAgo(new Date(item[key] ?? item.createDate ?? ''), 1, 2), }, { id: 'last7Days', label: , - match: item => betweenDaysAgo(new Date(item[key] ?? item.createDate), 2, 7), + match: item => + betweenDaysAgo(new Date(item[key] ?? item.createDate ?? ''), 2, 7), }, { id: 'last30Days', label: , match: item => - betweenDaysAgo(new Date(item[key] ?? item.createDate), 7, 30), + betweenDaysAgo(new Date(item[key] ?? item.createDate ?? ''), 7, 30), }, { id: 'moreThan30Days', label: , - match: item => !withinDaysAgo(new Date(item[key] ?? item.createDate), 30), + match: item => + !withinDaysAgo(new Date(item[key] ?? item.createDate ?? ''), 30), }, ]; -const pageGroupDefinitions = { +const itemGroupDefinitions = { createDate: getDateGroupDefinitions('createDate'), updatedDate: getDateGroupDefinitions('updatedDate'), // add more here later // todo: some page group definitions maybe dynamic }; -export function pagesToPageGroups( - pages: PageMeta[], +export function itemsToItemGroups( + items: T[], key?: DateKey -): PageGroupProps[] { +): ItemGroupProps[] { if (!key) { return [ { id: 'all', - items: pages, - allItems: pages, + items: items, + allItems: items, }, ]; } // assume pages are already sorted, we will use the page order to determine the group order - const groupDefs = pageGroupDefinitions[key]; - const groups: PageGroupProps[] = []; + const groupDefs = itemGroupDefinitions[key]; + const groups: ItemGroupProps[] = []; - for (const page of pages) { + for (const item of items) { // for a single page, there could be multiple groups that it belongs to - const matchedGroups = groupDefs.filter(def => def.match(page)); + const matchedGroups = groupDefs.filter(def => def.match(item)); for (const groupDef of matchedGroups) { const group = groups.find(g => g.id === groupDef.id); if (group) { - group.items.push(page); + group.items.push(item); } else { const label = typeof groupDef.label === 'function' @@ -75,8 +80,8 @@ export function pagesToPageGroups( groups.push({ id: groupDef.id, label: label, - items: [page], - allItems: pages, + items: [item], + allItems: items, }); } } diff --git a/packages/frontend/core/src/components/page-list/list.css.ts b/packages/frontend/core/src/components/page-list/list.css.ts new file mode 100644 index 0000000000..568a81ddf3 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/list.css.ts @@ -0,0 +1,69 @@ +import { createContainer, style } from '@vanilla-extract/css'; + +import * as itemStyles from './docs/page-list-item.css'; + +export const listRootContainer = createContainer('list-root-container'); + +export const pageListScrollContainer = style({ + width: '100%', + flex: 1, +}); + +export const root = style({ + width: '100%', + maxWidth: '100%', + containerName: listRootContainer, + containerType: 'inline-size', + background: 'var(--affine-background-primary-color)', +}); + +export const groupsContainer = style({ + display: 'flex', + flexDirection: 'column', + rowGap: '16px', +}); + +export const heading = style({}); + +export const colWrapper = style({ + display: 'flex', + alignItems: 'center', + flexShrink: 0, + overflow: 'hidden', +}); + +export const hideInSmallContainer = style({ + '@container': { + [`${listRootContainer} (max-width: 800px)`]: { + selectors: { + '&[data-hide-item="true"]': { + display: 'none', + }, + }, + }, + }, +}); + +export const favoriteCell = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + flexShrink: 0, + opacity: 0, + selectors: { + [`&[data-favorite], ${itemStyles.root}:hover &`]: { + opacity: 1, + }, + }, +}); + +export const clearLinkStyle = style({ + color: 'inherit', + textDecoration: 'none', + ':visited': { + color: 'inherit', + }, + ':active': { + color: 'inherit', + }, +}); diff --git a/packages/frontend/core/src/components/page-list/page-list.tsx b/packages/frontend/core/src/components/page-list/list.tsx similarity index 70% rename from packages/frontend/core/src/components/page-list/page-list.tsx rename to packages/frontend/core/src/components/page-list/list.tsx index 58420f2593..93c4627f69 100644 --- a/packages/frontend/core/src/components/page-list/page-list.tsx +++ b/packages/frontend/core/src/components/page-list/list.tsx @@ -12,41 +12,42 @@ import { useRef, } from 'react'; -import { PageGroup } from './page-group'; -import { PageListTableHeader } from './page-header'; -import * as styles from './page-list.css'; +import { pageHeaderColsDef } from './header-col-def'; +import * as styles from './list.css'; +import { ItemGroup } from './page-group'; +import { ListTableHeader } from './page-header'; import { - pageGroupsAtom, - pageListPropsAtom, - PageListProvider, + groupsAtom, + listPropsAtom, + ListProvider, selectionStateAtom, useAtom, useAtomValue, useSetAtom, } from './scoped-atoms'; -import type { PageListHandle, PageListProps } from './types'; +import type { ItemListHandle, ListItem, ListProps } from './types'; /** * Given a list of pages, render a list of pages */ -export const PageList = forwardRef( - function PageList(props, ref) { +export const List = forwardRef>( + function List(props, ref) { return ( // push pageListProps to the atom so that downstream components can consume it // this makes sure pageListPropsAtom is always populated // @ts-expect-error fix type issues later - - - - - + + + + + ); } ); // when pressing ESC or double clicking outside of the page list, close the selection mode // todo: use jotai-effect instead but it seems it does not work with jotai-scope? -const usePageSelectionStateEffect = () => { +const useItemSelectionStateEffect = () => { const [selectionState, setSelectionActive] = useAtom(selectionStateAtom); useEffect(() => { if ( @@ -96,23 +97,22 @@ const usePageSelectionStateEffect = () => { ]); }; -export const PageListInnerWrapper = memo( +export const ListInnerWrapper = memo( ({ handleRef, children, onSelectionActiveChange, ...props }: PropsWithChildren< - PageListProps & { handleRef: ForwardedRef } + ListProps & { handleRef: ForwardedRef } >) => { - const setPageListPropsAtom = useSetAtom(pageListPropsAtom); - const [selectionState, setPageListSelectionState] = - useAtom(selectionStateAtom); - usePageSelectionStateEffect(); + const setListPropsAtom = useSetAtom(listPropsAtom); + const [selectionState, setListSelectionState] = useAtom(selectionStateAtom); + useItemSelectionStateEffect(); useEffect(() => { - setPageListPropsAtom(props); - }, [props, setPageListPropsAtom]); + setListPropsAtom(props); + }, [props, setListPropsAtom]); useEffect(() => { onSelectionActiveChange?.(!!selectionState.selectionActive); @@ -123,41 +123,42 @@ export const PageListInnerWrapper = memo( () => { return { toggleSelectable: () => { - setPageListSelectionState(false); + setListSelectionState(false); }, }; }, - [setPageListSelectionState] + [setListSelectionState] ); return children; } ); -PageListInnerWrapper.displayName = 'PageListInnerWrapper'; +ListInnerWrapper.displayName = 'ListInnerWrapper'; + +const ListInner = (props: ListProps) => { + const groups = useAtomValue(groupsAtom); -const PageListInner = (props: PageListProps) => { - const groups = useAtomValue(pageGroupsAtom); const hideHeader = props.hideHeader; return (
- {!hideHeader ? : null} + {!hideHeader ? : null}
{groups.map(group => ( - + ))}
); }; -interface PageListScrollContainerProps { +interface ListScrollContainerProps { className?: string; style?: React.CSSProperties; } -export const PageListScrollContainer = forwardRef< +export const ListScrollContainer = forwardRef< HTMLDivElement, - PropsWithChildren + PropsWithChildren >(({ className, children, style }, ref) => { const containerRef = useRef(null); const hasScrollTop = useHasScrollTop(containerRef); @@ -188,4 +189,4 @@ export const PageListScrollContainer = forwardRef< ); }); -PageListScrollContainer.displayName = 'PageListScrollContainer'; +ListScrollContainer.displayName = 'ListScrollContainer'; diff --git a/packages/frontend/core/src/components/page-list/operation-cell.tsx b/packages/frontend/core/src/components/page-list/operation-cell.tsx index 51aef06492..58a6f32e37 100644 --- a/packages/frontend/core/src/components/page-list/operation-cell.tsx +++ b/packages/frontend/core/src/components/page-list/operation-cell.tsx @@ -6,24 +6,34 @@ import { MenuItem, Tooltip, } from '@affine/component'; +import type { Collection, DeleteCollectionInfo } from '@affine/env/filter'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { + DeleteIcon, DeletePermanentlyIcon, + EditIcon, FavoritedIcon, FavoriteIcon, + FilterIcon, MoreVerticalIcon, OpenInNewIcon, ResetIcon, } from '@blocksuite/icons'; -import { useState } from 'react'; +import { useCallback, useState } from 'react'; import { Link } from 'react-router-dom'; import { FavoriteTag } from './components/favorite-tag'; +import * as styles from './list.css'; import { DisablePublicSharing, MoveToTrash } from './operation-menu-items'; -import * as styles from './page-list.css'; +import type { useCollectionManager } from './use-collection-manager'; import { ColWrapper, stopPropagationWithoutPrevent } from './utils'; +import { + type AllPageListConfig, + useEditCollection, + useEditCollectionName, +} from './view'; -export interface OperationCellProps { +export interface PageOperationCellProps { favorite: boolean; isPublic: boolean; link: string; @@ -32,14 +42,14 @@ export interface OperationCellProps { onDisablePublicSharing: () => void; } -export const OperationCell = ({ +export const PageOperationCell = ({ favorite, isPublic, link, onToggleFavoritePage, onRemoveToTrash, onDisablePublicSharing, -}: OperationCellProps) => { +}: PageOperationCellProps) => { const t = useAFFiNEI18N(); const [openDisableShared, setOpenDisableShared] = useState(false); const OperationMenu = ( @@ -178,3 +188,94 @@ export const TrashOperationCell = ({ ); }; + +export interface CollectionOperationCellProps { + collection: Collection; + info: DeleteCollectionInfo; + config: AllPageListConfig; + setting: ReturnType; +} + +export const CollectionOperationCell = ({ + collection, + config, + setting, + info, +}: CollectionOperationCellProps) => { + const t = useAFFiNEI18N(); + + const { open: openEditCollectionModal, node: editModal } = + useEditCollection(config); + + const { open: openEditCollectionNameModal, node: editNameModal } = + useEditCollectionName({ + title: t['com.affine.editCollection.renameCollection'](), + }); + + const handleEditName = useCallback(() => { + // use openRenameModal if it is in the sidebar collection list + openEditCollectionNameModal(collection.name) + .then(name => { + return setting.updateCollection({ ...collection, name }); + }) + .catch(err => { + console.error(err); + }); + }, [collection, openEditCollectionNameModal, setting]); + + const handleEdit = useCallback(() => { + openEditCollectionModal(collection) + .then(collection => { + return setting.updateCollection(collection); + }) + .catch(err => { + console.error(err); + }); + }, [setting, collection, openEditCollectionModal]); + + const handleDelete = useCallback(() => { + return setting.deleteCollection(info, collection.id); + }, [setting, info, collection]); + + return ( + <> + {editModal} + {editNameModal} + + + + + + + + + + + + + + + + } + type="danger" + > + {t['Delete']()} + + } + contentOptions={{ + align: 'end', + }} + > + + + + + + + ); +}; diff --git a/packages/frontend/core/src/components/page-list/page-group.tsx b/packages/frontend/core/src/components/page-list/page-group.tsx index a3ce3bbf66..417e5c5ef6 100644 --- a/packages/frontend/core/src/components/page-list/page-group.tsx +++ b/packages/frontend/core/src/components/page-list/page-group.tsx @@ -8,6 +8,7 @@ import { PageIcon, TodayIcon, ToggleCollapseIcon, + ViewLayersIcon, } from '@blocksuite/icons'; import type { PageMeta, Workspace } from '@blocksuite/store'; import * as Collapsible from '@radix-ui/react-collapsible'; @@ -15,21 +16,36 @@ import clsx from 'clsx'; import { selectAtom } from 'jotai/utils'; import { type MouseEventHandler, useCallback, useMemo, useState } from 'react'; +import { CollectionListItem } from './collections/collection-list-item'; +import { PageListItem } from './docs/page-list-item'; import { PagePreview } from './page-content-preview'; import * as styles from './page-group.css'; -import { PageListItem } from './page-list-item'; import { - pageGroupCollapseStateAtom, - pageListPropsAtom, + groupCollapseStateAtom, + listPropsAtom, selectionStateAtom, useAtom, useAtomValue, } from './scoped-atoms'; -import type { PageGroupProps, PageListItemProps, PageListProps } from './types'; +import { TagListItem } from './tags/tag-list-item'; +import type { + CollectionListItemProps, + CollectionMeta, + ItemGroupProps, + ListItem, + ListProps, + PageListItemProps, + TagListItemProps, + TagMeta, +} from './types'; import { shallowEqual } from './utils'; -export const PageGroupHeader = ({ id, items, label }: PageGroupProps) => { - const [collapseState, setCollapseState] = useAtom(pageGroupCollapseStateAtom); +export const ItemGroupHeader = ({ + id, + items, + label, +}: ItemGroupProps) => { + const [collapseState, setCollapseState] = useAtom(groupCollapseStateAtom); const collapsed = collapseState[id]; const onExpandedClicked: MouseEventHandler = useCallback( e => { @@ -42,9 +58,9 @@ export const PageGroupHeader = ({ id, items, label }: PageGroupProps) => { const [selectionState, setSelectionActive] = useAtom(selectionStateAtom); const selectedItems = useMemo(() => { - const selectedPageIds = selectionState.selectedPageIds ?? []; - return items.filter(item => selectedPageIds.includes(item.id)); - }, [items, selectionState.selectedPageIds]); + const selectedIds = selectionState.selectedIds ?? []; + return items.filter(item => selectedIds.includes(item.id)); + }, [items, selectionState.selectedIds]); const allSelected = selectedItems.length === items.length; @@ -53,7 +69,7 @@ export const PageGroupHeader = ({ id, items, label }: PageGroupProps) => { setSelectionActive(true); const nonCurrentGroupIds = - selectionState.selectedPageIds?.filter( + selectionState.selectedIds?.filter( id => !items.map(item => item.id).includes(id) ) ?? []; @@ -61,7 +77,7 @@ export const PageGroupHeader = ({ id, items, label }: PageGroupProps) => { ? nonCurrentGroupIds : [...nonCurrentGroupIds, ...items.map(item => item.id)]; - selectionState.onSelectedPageIdsChange?.(newSelectedPageIds); + selectionState.onSelectedIdsChange?.(newSelectedPageIds); }, [setSelectionActive, selectionState, allSelected, items]); const t = useAFFiNEI18N(); @@ -103,7 +119,11 @@ export const PageGroupHeader = ({ id, items, label }: PageGroupProps) => { ) : null; }; -export const PageGroup = ({ id, items, label }: PageGroupProps) => { +export const ItemGroup = ({ + id, + items, + label, +}: ItemGroupProps) => { const [collapsed, setCollapsed] = useState(false); const onExpandedClicked: MouseEventHandler = useCallback(e => { e.stopPropagation(); @@ -112,16 +132,16 @@ export const PageGroup = ({ id, items, label }: PageGroupProps) => { }, []); const selectionState = useAtomValue(selectionStateAtom); const selectedItems = useMemo(() => { - const selectedPageIds = selectionState.selectedPageIds ?? []; - return items.filter(item => selectedPageIds.includes(item.id)); - }, [items, selectionState.selectedPageIds]); + const selectedIds = selectionState.selectedIds ?? []; + return items.filter(item => selectedIds.includes(item.id)); + }, [items, selectionState.selectedIds]); const onSelectAll = useCallback(() => { const nonCurrentGroupIds = - selectionState.selectedPageIds?.filter( + selectionState.selectedIds?.filter( id => !items.map(item => item.id).includes(id) ) ?? []; - selectionState.onSelectedPageIdsChange?.([ + selectionState.onSelectedIdsChange?.([ ...nonCurrentGroupIds, ...items.map(item => item.id), ]); @@ -164,7 +184,7 @@ export const PageGroup = ({ id, items, label }: PageGroupProps) => {
{items.map(item => ( - + ))}
@@ -177,32 +197,64 @@ const requiredPropNames = [ 'blockSuiteWorkspace', 'rowAsLink', 'isPreferredEdgeless', - 'pageOperationsRenderer', - 'selectedPageIds', - 'onSelectedPageIdsChange', + 'operationsRenderer', + 'selectedIds', + 'onSelectedIdsChange', 'draggable', ] as const; -type RequiredProps = Pick & { +type RequiredProps = Pick< + ListProps, + (typeof requiredPropNames)[number] +> & { selectable: boolean; }; -const listPropsAtom = selectAtom( - pageListPropsAtom, +const listsPropsAtom = selectAtom( + listPropsAtom, props => { return Object.fromEntries( requiredPropNames.map(name => [name, props[name]]) - ) as RequiredProps; + ) as RequiredProps; }, shallowEqual ); -export const PageMetaListItemRenderer = (pageMeta: PageMeta) => { - const props = useAtomValue(listPropsAtom); +export const PageListItemRenderer = (item: ListItem) => { + const props = useAtomValue(listsPropsAtom); const { selectionActive } = useAtomValue(selectionStateAtom); + const page = item as PageMeta; return ( + ); +}; + +export const CollectionListItemRenderer = (item: ListItem) => { + const props = useAtomValue(listsPropsAtom); + const { selectionActive } = useAtomValue(selectionStateAtom); + const collection = item as CollectionMeta; + return ( + + ); +}; + +export const TagListItemRenderer = (item: ListItem) => { + const props = useAtomValue(listsPropsAtom); + const { selectionActive } = useAtomValue(selectionStateAtom); + const tag = item as TagMeta; + return ( + boolean; + isPreferredEdgeless?: (id: string) => boolean; }) => { - const isEdgeless = isPreferredEdgeless(id); + const isEdgeless = isPreferredEdgeless ? isPreferredEdgeless(id) : false; const { isJournal } = useJournalInfoHelper(workspace, id); if (isJournal) { return ; @@ -241,61 +293,132 @@ const UnifiedPageIcon = ({ return isEdgeless ? : ; }; -function pageMetaToPageItemProp( - pageMeta: PageMeta, - props: RequiredProps +function pageMetaToListItemProp( + item: PageMeta, + props: RequiredProps ): PageListItemProps { - const toggleSelection = props.onSelectedPageIdsChange + const toggleSelection = props.onSelectedIdsChange ? () => { - assertExists(props.selectedPageIds); - const prevSelected = props.selectedPageIds.includes(pageMeta.id); + assertExists(props.selectedIds); + const prevSelected = props.selectedIds.includes(item.id); const shouldAdd = !prevSelected; const shouldRemove = prevSelected; if (shouldAdd) { - props.onSelectedPageIdsChange?.([ - ...props.selectedPageIds, - pageMeta.id, - ]); + props.onSelectedIdsChange?.([...props.selectedIds, item.id]); } else if (shouldRemove) { - props.onSelectedPageIdsChange?.( - props.selectedPageIds.filter(id => id !== pageMeta.id) + props.onSelectedIdsChange?.( + props.selectedIds.filter(id => id !== item.id) ); } } : undefined; const itemProps: PageListItemProps = { - pageId: pageMeta.id, - title: , + pageId: item.id, + title: , preview: ( - + ), - createDate: new Date(pageMeta.createDate), - updatedDate: pageMeta.updatedDate - ? new Date(pageMeta.updatedDate) - : undefined, + createDate: new Date(item.createDate), + updatedDate: item.updatedDate ? new Date(item.updatedDate) : undefined, to: props.rowAsLink && !props.selectable - ? `/workspace/${props.blockSuiteWorkspace.id}/${pageMeta.id}` + ? `/workspace/${props.blockSuiteWorkspace.id}/${item.id}` : undefined, onClick: props.selectable ? toggleSelection : undefined, icon: ( ), tags: - pageMeta.tags + item.tags ?.map(id => tagIdToTagOption(id, props.blockSuiteWorkspace)) .filter((v): v is Tag => v != null) ?? [], - operations: props.pageOperationsRenderer?.(pageMeta), + operations: props.operationsRenderer?.(item), selectable: props.selectable, - selected: props.selectedPageIds?.includes(pageMeta.id), + selected: props.selectedIds?.includes(item.id), + onSelectedChange: toggleSelection, + draggable: props.draggable, + isPublicPage: !!item.isPublic, + }; + return itemProps; +} + +function collectionMetaToListItemProp( + item: CollectionMeta, + props: RequiredProps +): CollectionListItemProps { + const toggleSelection = props.onSelectedIdsChange + ? () => { + assertExists(props.selectedIds); + const prevSelected = props.selectedIds.includes(item.id); + const shouldAdd = !prevSelected; + const shouldRemove = prevSelected; + + if (shouldAdd) { + props.onSelectedIdsChange?.([...props.selectedIds, item.id]); + } else if (shouldRemove) { + props.onSelectedIdsChange?.( + props.selectedIds.filter(id => id !== item.id) + ); + } + } + : undefined; + const itemProps: CollectionListItemProps = { + collectionId: item.id, + title: item.title, + to: + props.rowAsLink && !props.selectable + ? `/workspace/${props.blockSuiteWorkspace.id}/collection/${item.id}` + : undefined, + onClick: props.selectable ? toggleSelection : undefined, + icon: , + operations: props.operationsRenderer?.(item), + selectable: props.selectable, + selected: props.selectedIds?.includes(item.id), + onSelectedChange: toggleSelection, + draggable: props.draggable, + }; + return itemProps; +} +function tagMetaToListItemProp( + item: TagMeta, + props: RequiredProps +): TagListItemProps { + const toggleSelection = props.onSelectedIdsChange + ? () => { + assertExists(props.selectedIds); + const prevSelected = props.selectedIds.includes(item.id); + const shouldAdd = !prevSelected; + const shouldRemove = prevSelected; + + if (shouldAdd) { + props.onSelectedIdsChange?.([...props.selectedIds, item.id]); + } else if (shouldRemove) { + props.onSelectedIdsChange?.( + props.selectedIds.filter(id => id !== item.id) + ); + } + } + : undefined; + const itemProps: TagListItemProps = { + tagId: item.id, + title: item.title, + to: + props.rowAsLink && !props.selectable + ? `/workspace/${props.blockSuiteWorkspace.id}/tag/${item.id}` + : undefined, + onClick: props.selectable ? toggleSelection : undefined, + color: item.color, + pageCount: item.pageCount, + operations: props.operationsRenderer?.(item), + selectable: props.selectable, + selected: props.selectedIds?.includes(item.id), onSelectedChange: toggleSelection, draggable: props.draggable, - isPublicPage: !!pageMeta.isPublic, }; return itemProps; } diff --git a/packages/frontend/core/src/components/page-list/page-header.css.ts b/packages/frontend/core/src/components/page-list/page-header.css.ts new file mode 100644 index 0000000000..84c31abeae --- /dev/null +++ b/packages/frontend/core/src/components/page-list/page-header.css.ts @@ -0,0 +1,40 @@ +import { globalStyle, style } from '@vanilla-extract/css'; + +export const headerTitleCell = style({ + display: 'flex', + alignItems: 'center', + gap: '8px', +}); + +export const tableHeader = style({ + display: 'flex', + alignItems: 'center', + padding: '10px 6px 10px 16px', + position: 'sticky', + overflow: 'hidden', + zIndex: 1, + top: 0, + left: 0, + background: 'var(--affine-background-primary-color)', + transition: 'box-shadow 0.2s ease-in-out', + transform: 'translateY(-0.5px)', // fix sticky look through issue +}); + +globalStyle(`[data-has-scroll-top=true] ${tableHeader}`, { + boxShadow: '0 1px var(--affine-border-color)', +}); + +export const headerTitleSelectionIconWrapper = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-start', + fontSize: '16px', + selectors: { + [`${tableHeader}[data-selectable=toggle] &`]: { + width: 32, + }, + [`${tableHeader}[data-selection-active=true] &`]: { + width: 24, + }, + }, +}); diff --git a/packages/frontend/core/src/components/page-list/page-header.tsx b/packages/frontend/core/src/components/page-list/page-header.tsx index a1f7e39c75..7822500d58 100644 --- a/packages/frontend/core/src/components/page-list/page-header.tsx +++ b/packages/frontend/core/src/components/page-list/page-header.tsx @@ -1,84 +1,31 @@ import { Checkbox, type CheckboxProps } from '@affine/component'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; -import { MultiSelectIcon, SortDownIcon, SortUpIcon } from '@blocksuite/icons'; -import type { PageMeta } from '@blocksuite/store'; +import { MultiSelectIcon } from '@blocksuite/icons'; import clsx from 'clsx'; import { selectAtom } from 'jotai/utils'; -import { - type MouseEventHandler, - type ReactNode, - useCallback, - useMemo, -} from 'react'; +import { type MouseEventHandler, useCallback } from 'react'; -import * as styles from './page-list.css'; +import { ListHeaderCell } from './components/list-header-cell'; +import * as styles from './page-header.css'; import { - pageListHandlersAtom, - pageListPropsAtom, - pagesAtom, + itemsAtom, + listHandlersAtom, + listPropsAtom, selectionStateAtom, - showOperationsAtom, sorterAtom, useAtom, useAtomValue, } from './scoped-atoms'; -import { ColWrapper, type ColWrapperProps, stopPropagation } from './utils'; - -export const PageListHeaderCell = (props: HeaderCellProps) => { - const [sorter, setSorter] = useAtom(sorterAtom); - const onClick: MouseEventHandler = useCallback(() => { - if (props.sortable && props.sortKey) { - setSorter({ - newSortKey: props.sortKey, - }); - } - }, [props.sortKey, props.sortable, setSorter]); - - const sorting = sorter.key === props.sortKey; - - return ( - - {props.children} - {sorting ? ( -
- {sorter.order === 'asc' ? : } -
- ) : null} -
- ); -}; - -type HeaderColDef = { - key: string; - content: ReactNode; - flex: ColWrapperProps['flex']; - alignment?: ColWrapperProps['alignment']; - sortable?: boolean; - hideInSmallContainer?: boolean; -}; - -type HeaderCellProps = ColWrapperProps & { - sortKey: keyof PageMeta; - sortable?: boolean; -}; +import type { HeaderColDef, ListItem } from './types'; +import { stopPropagation } from './utils'; // the checkbox on the header has three states: // when list selectable = true, the checkbox will be presented // when internal selection state is not enabled, it is a clickable that enables the selection state // when internal selection state is enabled, it is a checkbox that reflects the selection state -const PageListHeaderCheckbox = () => { +const ListHeaderCheckbox = () => { const [selectionState, setSelectionState] = useAtom(selectionStateAtom); - const pages = useAtomValue(pagesAtom); + const items = useAtomValue(itemsAtom); const onActivateSelection: MouseEventHandler = useCallback( e => { stopPropagation(e); @@ -86,13 +33,13 @@ const PageListHeaderCheckbox = () => { }, [setSelectionState] ); - const handlers = useAtomValue(pageListHandlersAtom); + const handlers = useAtomValue(listHandlersAtom); const onChange: NonNullable = useCallback( (e, checked) => { stopPropagation(e); - handlers.onSelectedPageIdsChange?.(checked ? pages.map(p => p.id) : []); + handlers.onSelectedIdsChange?.(checked ? items.map(i => i.id) : []); }, - [handlers, pages] + [handlers, items] ); if (!selectionState.selectable) { @@ -109,11 +56,11 @@ const PageListHeaderCheckbox = () => { ) : ( 0 && - selectionState.selectedPageIds.length < pages.length + selectionState.selectedIds && + selectionState.selectedIds.length > 0 && + selectionState.selectedIds.length < items.length } onChange={onChange} /> @@ -122,64 +69,37 @@ const PageListHeaderCheckbox = () => { ); }; -const PageListHeaderTitleCell = () => { +export const ListHeaderTitleCell = () => { const t = useAFFiNEI18N(); return (
- + {t['Title']()}
); }; -const hideHeaderAtom = selectAtom(pageListPropsAtom, props => props.hideHeader); +const hideHeaderAtom = selectAtom(listPropsAtom, props => props.hideHeader); // the table header for page list -export const PageListTableHeader = () => { - const t = useAFFiNEI18N(); - const showOperations = useAtomValue(showOperationsAtom); +export const ListTableHeader = ({ + headerCols, +}: { + headerCols: HeaderColDef[]; +}) => { + const [sorter, setSorter] = useAtom(sorterAtom); const hideHeader = useAtomValue(hideHeaderAtom); const selectionState = useAtomValue(selectionStateAtom); - const headerCols = useMemo(() => { - const cols: (HeaderColDef | boolean)[] = [ - { - key: 'title', - content: , - flex: 6, - alignment: 'start', - sortable: true, - }, - { - key: 'tags', - content: t['Tags'](), - flex: 3, - alignment: 'end', - }, - { - key: 'createDate', - content: t['Created'](), - flex: 1, - sortable: true, - alignment: 'end', - hideInSmallContainer: true, - }, - { - key: 'updatedDate', - content: t['Updated'](), - flex: 1, - sortable: true, - alignment: 'end', - hideInSmallContainer: true, - }, - showOperations && { - key: 'actions', - content: '', - flex: 1, - alignment: 'end', - }, - ]; - return cols.filter((def): def is HeaderColDef => !!def); - }, [t, showOperations]); + const onSort = useCallback( + (sortable?: boolean, sortKey?: keyof ListItem) => { + if (sortable && sortKey) { + setSorter({ + newSortKey: sortKey, + }); + } + }, + [setSorter] + ); if (hideHeader) { return false; @@ -193,17 +113,20 @@ export const PageListTableHeader = () => { > {headerCols.map(col => { return ( - {col.content} - + ); })}
diff --git a/packages/frontend/core/src/components/page-list/page-list.css.ts b/packages/frontend/core/src/components/page-list/page-list.css.ts deleted file mode 100644 index 2be091713f..0000000000 --- a/packages/frontend/core/src/components/page-list/page-list.css.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { createContainer, globalStyle, style } from '@vanilla-extract/css'; - -import * as itemStyles from './page-list-item.css'; - -export const listRootContainer = createContainer('list-root-container'); - -export const pageListScrollContainer = style({ - width: '100%', - flex: 1, -}); - -export const root = style({ - width: '100%', - maxWidth: '100%', - containerName: listRootContainer, - containerType: 'inline-size', - background: 'var(--affine-background-primary-color)', -}); - -export const groupsContainer = style({ - display: 'flex', - flexDirection: 'column', - rowGap: '16px', -}); - -export const heading = style({}); - -export const tableHeader = style({ - display: 'flex', - alignItems: 'center', - padding: '10px 6px 10px 16px', - position: 'sticky', - overflow: 'hidden', - zIndex: 1, - top: 0, - left: 0, - background: 'var(--affine-background-primary-color)', - transition: 'box-shadow 0.2s ease-in-out', - transform: 'translateY(-0.5px)', // fix sticky look through issue -}); - -globalStyle(`[data-has-scroll-top=true] ${tableHeader}`, { - boxShadow: '0 1px var(--affine-border-color)', -}); - -export const headerCell = style({ - padding: '0 8px', - userSelect: 'none', - fontSize: 'var(--affine-font-xs)', - color: 'var(--affine-text-secondary-color)', - selectors: { - '&[data-sorting], &:hover': { - color: 'var(--affine-text-primary-color)', - }, - '&[data-sortable]': { - cursor: 'pointer', - }, - '&:not(:last-child)': { - borderRight: '1px solid var(--affine-hover-color-filled)', - }, - }, - display: 'flex', - alignItems: 'center', - columnGap: '4px', - position: 'relative', - whiteSpace: 'nowrap', -}); - -export const headerTitleCell = style({ - display: 'flex', - alignItems: 'center', - gap: '8px', -}); - -export const headerTitleSelectionIconWrapper = style({ - display: 'flex', - alignItems: 'center', - justifyContent: 'flex-start', - fontSize: '16px', - selectors: { - [`${tableHeader}[data-selectable=toggle] &`]: { - width: 32, - }, - [`${tableHeader}[data-selection-active=true] &`]: { - width: 24, - }, - }, -}); - -export const headerCellSortIcon = style({ - display: 'inline-flex', - fontSize: 14, - color: 'var(--affine-icon-color)', -}); - -export const colWrapper = style({ - display: 'flex', - alignItems: 'center', - flexShrink: 0, - overflow: 'hidden', -}); - -export const hideInSmallContainer = style({ - '@container': { - [`${listRootContainer} (max-width: 800px)`]: { - display: 'none', - }, - }, -}); - -export const favoriteCell = style({ - display: 'flex', - alignItems: 'center', - justifyContent: 'flex-end', - flexShrink: 0, - opacity: 0, - selectors: { - [`&[data-favorite], ${itemStyles.root}:hover &`]: { - opacity: 1, - }, - }, -}); - -export const clearLinkStyle = style({ - color: 'inherit', - textDecoration: 'none', - ':visited': { - color: 'inherit', - }, - ':active': { - color: 'inherit', - }, -}); diff --git a/packages/frontend/core/src/components/page-list/scoped-atoms.tsx b/packages/frontend/core/src/components/page-list/scoped-atoms.tsx index bed647ba8c..83c1b9ada8 100644 --- a/packages/frontend/core/src/components/page-list/scoped-atoms.tsx +++ b/packages/frontend/core/src/components/page-list/scoped-atoms.tsx @@ -1,22 +1,22 @@ import { DEFAULT_SORT_KEY } from '@affine/env/constant'; -import type { PageMeta } from '@blocksuite/store'; import { atom } from 'jotai'; import { selectAtom } from 'jotai/utils'; import { createIsolation } from 'jotai-scope'; -import { pagesToPageGroups } from './pages-to-page-group'; +import { itemsToItemGroups } from './items-to-item-group'; import type { - PageListProps, - PageMetaRecord, - VirtualizedPageListProps, + ListItem, + ListProps, + MetaRecord, + VirtualizedListProps, } from './types'; import { shallowEqual } from './utils'; // for ease of use in the component tree // note: must use selectAtom to access this atom for efficiency // @ts-expect-error the error is expected but we will assume the default value is always there by using useHydrateAtoms -export const pageListPropsAtom = atom< - PageListProps & Partial +export const listPropsAtom = atom< + ListProps & Partial> >(); // whether or not the table is in selection mode (showing selection checkbox & selection floating bar) @@ -25,13 +25,13 @@ const selectionActiveAtom = atom(false); export const selectionStateAtom = atom( get => { const baseAtom = selectAtom( - pageListPropsAtom, + listPropsAtom, props => { - const { selectable, selectedPageIds, onSelectedPageIdsChange } = props; + const { selectable, selectedIds, onSelectedIdsChange } = props; return { selectable, - selectedPageIds, - onSelectedPageIdsChange, + selectedIds, + onSelectedIdsChange, }; }, shallowEqual @@ -53,50 +53,49 @@ export const selectionStateAtom = atom( // id -> isCollapsed // maybe reset on page on unmount? -export const pageGroupCollapseStateAtom = atom>({}); +export const groupCollapseStateAtom = atom>({}); // get handlers from pageListPropsAtom -export const pageListHandlersAtom = selectAtom( - pageListPropsAtom, +export const listHandlersAtom = selectAtom( + listPropsAtom, props => { - const { onSelectedPageIdsChange } = props; + const { onSelectedIdsChange } = props; return { - onSelectedPageIdsChange, + onSelectedIdsChange, }; }, shallowEqual ); -export const pagesAtom = selectAtom( - pageListPropsAtom, - props => props.pages, +export const itemsAtom = selectAtom( + listPropsAtom, + props => props.items, shallowEqual ); export const showOperationsAtom = selectAtom( - pageListPropsAtom, - props => !!props.pageOperationsRenderer + listPropsAtom, + props => !!props.operationsRenderer ); -type SortingContext = { - key: T; +type SortingContext = { + key: KeyType; order: 'asc' | 'desc'; - fallbackKey?: T; + fallbackKey?: KeyType; }; -type SorterConfig = Record> = - { - key?: keyof T; - order: 'asc' | 'desc'; - sortingFn: (ctx: SortingContext, a: T, b: T) => number; - }; +type SorterConfig = { + key?: keyof T; + order: 'asc' | 'desc'; + sortingFn: (ctx: SortingContext, a: T, b: T) => number; +}; -const defaultSortingFn: SorterConfig['sortingFn'] = ( +const defaultSortingFn: SorterConfig>['sortingFn'] = ( ctx, a, b ) => { - const val = (obj: PageMetaRecord) => { + const val = (obj: MetaRecord) => { let v = obj[ctx.key]; if (v === undefined && ctx.fallbackKey) { v = obj[ctx.fallbackKey]; @@ -134,7 +133,14 @@ const defaultSortingFn: SorterConfig['sortingFn'] = ( return 0; }; -const sorterStateAtom = atom>({ +const validKeys: Array> = [ + 'id', + 'title', + 'createDate', + 'updatedDate', +]; + +const sorterStateAtom = atom>>({ key: DEFAULT_SORT_KEY, order: 'desc', sortingFn: defaultSortingFn, @@ -142,47 +148,45 @@ const sorterStateAtom = atom>({ export const sorterAtom = atom( get => { - let pages = get(pagesAtom); + let items = get(itemsAtom); const sorterState = get(sorterStateAtom); - const sortCtx: SortingContext | null = sorterState.key - ? { - key: sorterState.key, - order: sorterState.order, - } - : null; + const sortCtx: SortingContext> | null = + sorterState.key + ? { + key: sorterState.key, + order: sorterState.order, + } + : null; if (sortCtx) { if (sorterState.key === 'updatedDate') { sortCtx.fallbackKey = 'createDate'; } - const compareFn = (a: PageMetaRecord, b: PageMetaRecord) => + const compareFn = (a: MetaRecord, b: MetaRecord) => sorterState.sortingFn(sortCtx, a, b); - pages = [...pages].sort(compareFn); + items = [...items].sort(compareFn); } return { - pages, + items, ...sortCtx, }; }, - (_get, set, { newSortKey }: { newSortKey: keyof PageMeta }) => { + (_get, set, { newSortKey }: { newSortKey: keyof MetaRecord }) => { set(sorterStateAtom, sorterState => { - if (sorterState.key === newSortKey) { + if (validKeys.includes(newSortKey)) { return { ...sorterState, - order: sorterState.order === 'asc' ? 'desc' : 'asc', - }; - } else { - return { key: newSortKey, - order: 'desc', + order: sorterState.order === 'asc' ? 'desc' : 'asc', sortingFn: sorterState.sortingFn, }; } + return sorterState; }); } ); -export const pageGroupsAtom = atom(get => { - let groupBy = get(selectAtom(pageListPropsAtom, props => props.groupBy)); +export const groupsAtom = atom(get => { + let groupBy = get(selectAtom(listPropsAtom, props => props.groupBy)); const sorter = get(sorterAtom); if (groupBy === false) { @@ -196,11 +200,11 @@ export const pageGroupsAtom = atom(get => { ? DEFAULT_SORT_KEY : undefined; } - return pagesToPageGroups(sorter.pages, groupBy); + return itemsToItemGroups(sorter.items, groupBy); }); export const { - Provider: PageListProvider, + Provider: ListProvider, useAtom, useAtomValue, useSetAtom, diff --git a/packages/frontend/core/src/components/page-list/tags/index.ts b/packages/frontend/core/src/components/page-list/tags/index.ts new file mode 100644 index 0000000000..11a1b31754 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/tags/index.ts @@ -0,0 +1,3 @@ +export * from './tag-list-header'; +export * from './tag-list-item'; +export * from './virtualized-tag-list'; diff --git a/packages/frontend/core/src/components/page-list/tags/tag-list-header.css.ts b/packages/frontend/core/src/components/page-list/tags/tag-list-header.css.ts new file mode 100644 index 0000000000..c475242514 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/tags/tag-list-header.css.ts @@ -0,0 +1,29 @@ +import { style } from '@vanilla-extract/css'; + +export const tagListHeader = style({ + height: 100, + alignItems: 'center', + padding: '48px 16px 20px 24px', + overflow: 'hidden', + display: 'flex', + justifyContent: 'space-between', + background: 'var(--affine-background-primary-color)', +}); + +export const tagListHeaderTitle = style({ + fontSize: 'var(--affine-font-h-5)', + fontWeight: 500, + color: 'var(--affine-text-secondary-color)', + display: 'flex', + alignItems: 'center', + gap: 8, +}); + +export const newTagButton = style({ + padding: '6px 10px', + borderRadius: '8px', + background: 'var(--affine-background-primary-color)', + fontSize: 'var(--affine-font-sm)', + fontWeight: 600, + height: '32px', +}); diff --git a/packages/frontend/core/src/components/page-list/tags/tag-list-header.tsx b/packages/frontend/core/src/components/page-list/tags/tag-list-header.tsx new file mode 100644 index 0000000000..b225853867 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/tags/tag-list-header.tsx @@ -0,0 +1,12 @@ +import { useAFFiNEI18N } from '@affine/i18n/hooks'; + +import * as styles from './tag-list-header.css'; + +export const TagListHeader = () => { + const t = useAFFiNEI18N(); + return ( +
+
{t['Tags']()}
+
+ ); +}; diff --git a/packages/frontend/core/src/components/page-list/tags/tag-list-item.css.ts b/packages/frontend/core/src/components/page-list/tags/tag-list-item.css.ts new file mode 100644 index 0000000000..6cd9fd4c05 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/tags/tag-list-item.css.ts @@ -0,0 +1,187 @@ +import { globalStyle, style } from '@vanilla-extract/css'; + +export const root = style({ + display: 'flex', + color: 'var(--affine-text-primary-color)', + height: '54px', // 42 + 12 + flexShrink: 0, + width: '100%', + alignItems: 'stretch', + transition: 'background-color 0.2s, opacity 0.2s', + ':hover': { + backgroundColor: 'var(--affine-hover-color)', + }, + overflow: 'hidden', + cursor: 'default', + willChange: 'opacity', + selectors: { + '&[data-clickable=true]': { + cursor: 'pointer', + }, + }, +}); + +export const dragOverlay = style({ + display: 'flex', + alignItems: 'center', + zIndex: 1001, + cursor: 'grabbing', + maxWidth: '360px', + transition: 'transform 0.2s', + willChange: 'transform', + selectors: { + '&[data-over=true]': { + transform: 'scale(0.8)', + }, + }, +}); +export const dragPageItemOverlay = style({ + height: '54px', + borderRadius: '10px', + display: 'flex', + alignItems: 'center', + background: 'var(--affine-hover-color-filled)', + boxShadow: 'var(--affine-menu-shadow)', + maxWidth: '360px', + minWidth: '260px', +}); + +export const dndCell = style({ + position: 'relative', + marginLeft: -8, + height: '100%', + outline: 'none', + paddingLeft: 8, +}); + +globalStyle(`[data-draggable=true] ${dndCell}:before`, { + content: '""', + position: 'absolute', + top: '50%', + transform: 'translateY(-50%)', + left: 0, + width: 4, + height: 4, + transition: 'height 0.2s, opacity 0.2s', + backgroundColor: 'var(--affine-placeholder-color)', + borderRadius: '2px', + opacity: 0, + willChange: 'height, opacity', +}); + +globalStyle(`[data-draggable=true] ${dndCell}:hover:before`, { + height: 12, + opacity: 1, +}); + +globalStyle(`[data-draggable=true][data-dragging=true] ${dndCell}`, { + opacity: 0.5, +}); + +globalStyle(`[data-draggable=true][data-dragging=true] ${dndCell}:before`, { + height: 32, + width: 2, + opacity: 1, +}); + +// todo: remove global style +globalStyle(`${root} > :first-child`, { + paddingLeft: '16px', +}); + +globalStyle(`${root} > :last-child`, { + paddingRight: '8px', +}); + +export const titleIconsWrapper = style({ + padding: '0 5px', + display: 'flex', + alignItems: 'center', + gap: '10px', +}); + +export const selectionCell = style({ + display: 'flex', + alignItems: 'center', + flexShrink: 0, + fontSize: 'var(--affine-font-h-3)', +}); + +export const titleCell = style({ + display: 'flex', + alignItems: 'flex-start', + padding: '0 16px', + maxWidth: 'calc(100% - 64px)', + flex: 1, + whiteSpace: 'nowrap', +}); + +export const titleCellMain = style({ + overflow: 'hidden', + fontSize: 'var(--affine-font-sm)', + fontWeight: 600, + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + alignSelf: 'stretch', + paddingRight: '4px', +}); + +export const titleCellPreview = style({ + overflow: 'hidden', + color: 'var(--affine-text-secondary-color)', + fontSize: 'var(--affine-font-base)', + flex: 1, + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + alignSelf: 'stretch', +}); + +export const iconCell = style({ + display: 'flex', + alignItems: 'center', + fontSize: 'var(--affine-font-h-3)', + color: 'var(--affine-icon-color)', + flexShrink: 0, +}); + +export const tagsCell = style({ + display: 'flex', + alignItems: 'center', + fontSize: 'var(--affine-font-xs)', + color: 'var(--affine-text-secondary-color)', + padding: '0 8px', + height: '60px', + width: '100%', +}); + +export const dateCell = style({ + display: 'flex', + alignItems: 'center', + fontSize: 'var(--affine-font-xs)', + color: 'var(--affine-text-secondary-color)', + flexShrink: 0, + flexWrap: 'nowrap', + padding: '0 8px', +}); + +export const actionsCellWrapper = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + flexShrink: 0, +}); + +export const operationsCell = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + columnGap: '6px', + flexShrink: 0, +}); + +export const tagIndicator = style({ + width: '8px', + height: '8px', + borderRadius: '50%', + flexShrink: 0, +}); diff --git a/packages/frontend/core/src/components/page-list/tags/tag-list-item.tsx b/packages/frontend/core/src/components/page-list/tags/tag-list-item.tsx new file mode 100644 index 0000000000..1e2bc739fd --- /dev/null +++ b/packages/frontend/core/src/components/page-list/tags/tag-list-item.tsx @@ -0,0 +1,197 @@ +import { Checkbox } from '@affine/component'; +import { useAFFiNEI18N } from '@affine/i18n/hooks'; +import { useDraggable } from '@dnd-kit/core'; +import { type PropsWithChildren, useCallback, useMemo } from 'react'; +import { Link } from 'react-router-dom'; + +import type { DraggableTitleCellData, TagListItemProps } from '../types'; +import { ColWrapper, stopPropagation, tagColorMap } from '../utils'; +import * as styles from './tag-list-item.css'; + +const TagListTitleCell = ({ + title, + pageCount, +}: Pick) => { + const t = useAFFiNEI18N(); + return ( +
+
+ {title || t['Untitled']()} +
+
+ {`· ${pageCount} doc(s)`} +
+
+ ); +}; + +const ListIconCell = ({ color }: Pick) => { + return ( +
+ ); +}; + +const TagSelectionCell = ({ + selectable, + onSelectedChange, + selected, +}: Pick) => { + const onSelectionChange = useCallback( + (_event: React.ChangeEvent) => { + return onSelectedChange?.(); + }, + [onSelectedChange] + ); + if (!selectable) { + return null; + } + return ( +
+ +
+ ); +}; + +const TagListOperationsCell = ({ + operations, +}: Pick) => { + return operations ? ( +
+ {operations} +
+ ) : null; +}; + +export const TagListItem = (props: TagListItemProps) => { + const tagTitleElement = useMemo(() => { + return ( +
+
+ + +
+
+ ); + }, [props.color, props.onSelectedChange, props.selectable, props.selected]); + + // TODO: use getDropItemId + const { setNodeRef, attributes, listeners, isDragging } = useDraggable({ + id: 'tag-list-item-title-' + props.tagId, + data: { + pageId: props.tagId, + pageTitle: tagTitleElement, + } satisfies DraggableTitleCellData, + disabled: !props.draggable, + }); + + return ( + + + +
+ + +
+ +
+ +
+ {props.operations ? ( + + + + ) : null} +
+ ); +}; + +type TagListWrapperProps = PropsWithChildren< + Pick & { + isDragging: boolean; + } +>; + +function TagListItemWrapper({ + to, + isDragging, + tagId, + onClick, + children, + draggable, +}: TagListWrapperProps) { + const handleClick = useCallback( + (e: React.MouseEvent) => { + if (onClick) { + stopPropagation(e); + onClick(); + } + }, + [onClick] + ); + + const commonProps = useMemo( + () => ({ + 'data-testid': 'tag-list-item', + 'data-tag-id': tagId, + 'data-draggable': draggable, + className: styles.root, + 'data-clickable': !!onClick || !!to, + 'data-dragging': isDragging, + onClick: handleClick, + }), + [tagId, draggable, isDragging, onClick, to, handleClick] + ); + + if (to) { + return ( + + {children} + + ); + } else { + return
{children}
; + } +} diff --git a/packages/frontend/core/src/components/page-list/tags/virtualized-tag-list.tsx b/packages/frontend/core/src/components/page-list/tags/virtualized-tag-list.tsx new file mode 100644 index 0000000000..f50a63170d --- /dev/null +++ b/packages/frontend/core/src/components/page-list/tags/virtualized-tag-list.tsx @@ -0,0 +1,96 @@ +import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace'; +import { Trans } from '@affine/i18n'; +import type { Tag } from '@blocksuite/store'; +import { useAtomValue } from 'jotai'; +import { useCallback, useMemo, useRef, useState } from 'react'; + +import { ListFloatingToolbar } from '../components/list-floating-toolbar'; +import { tagHeaderColsDef } from '../header-col-def'; +import { TagListItemRenderer } from '../page-group'; +import { ListTableHeader } from '../page-header'; +import type { ItemListHandle, ListItem, TagMeta } from '../types'; +import { VirtualizedList } from '../virtualized-list'; +import { TagListHeader } from './tag-list-header'; + +export const VirtualizedTagList = ({ + tags, + tagMetas, + setHideHeaderCreateNewTag, + onTagDelete, +}: { + tags: Tag[]; + tagMetas: TagMeta[]; + setHideHeaderCreateNewTag: (hide: boolean) => void; + onTagDelete: (tagIds: string[]) => void; +}) => { + const listRef = useRef(null); + const [showFloatingToolbar, setShowFloatingToolbar] = useState(false); + const [selectedTagIds, setSelectedTagIds] = useState([]); + const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom); + + const filteredSelectedTagIds = useMemo(() => { + const ids = tags.map(tag => tag.id); + return selectedTagIds.filter(id => ids.includes(id)); + }, [selectedTagIds, tags]); + + const hideFloatingToolbar = useCallback(() => { + listRef.current?.toggleSelectable(); + }, []); + + const tagOperationRenderer = useCallback(() => { + return null; + }, []); + + const tagHeaderRenderer = useCallback(() => { + return ; + }, []); + + const tagItemRenderer = useCallback((item: ListItem) => { + return ; + }, []); + + const handleDelete = useCallback(() => { + onTagDelete(selectedTagIds); + hideFloatingToolbar(); + return; + }, [hideFloatingToolbar, onTagDelete, selectedTagIds]); + + return ( + <> + } + selectedIds={filteredSelectedTagIds} + onSelectedIdsChange={setSelectedTagIds} + items={tagMetas} + itemRenderer={tagItemRenderer} + rowAsLink + blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace} + operationsRenderer={tagOperationRenderer} + headerRenderer={tagHeaderRenderer} + /> + 0} + content={ + +
+ {{ count: selectedTagIds.length } as any} +
+ selected +
+ } + onClose={hideFloatingToolbar} + onDelete={handleDelete} + /> + + ); +}; diff --git a/packages/frontend/core/src/components/page-list/types.ts b/packages/frontend/core/src/components/page-list/types.ts index 1443f660d9..e820c96c2c 100644 --- a/packages/frontend/core/src/components/page-list/types.ts +++ b/packages/frontend/core/src/components/page-list/types.ts @@ -1,8 +1,24 @@ -import type { Tag } from '@affine/env/filter'; +import type { Collection, Tag } from '@affine/env/filter'; import type { PageMeta, Workspace } from '@blocksuite/store'; -import type { ReactNode } from 'react'; +import type { PropsWithChildren, ReactNode } from 'react'; import type { To } from 'react-router-dom'; +export type ListItem = PageMeta | CollectionMeta | TagMeta; + +export interface CollectionMeta extends Collection { + title: string; + createDate?: Date; + updatedDate?: Date; +} + +export type TagMeta = { + id: string; + title: string; + color: string; + pageCount?: number; + createDate?: Date; + updatedDate?: Date; +}; // TODO: consider reducing the number of props here // using type instead of interface to make it Record compatible export type PageListItemProps = { @@ -23,10 +39,41 @@ export type PageListItemProps = { onSelectedChange?: () => void; }; -export interface PageListHeaderProps {} +export type CollectionListItemProps = { + collectionId: string; + icon: JSX.Element; + title: ReactNode; // using ReactNode to allow for rich content rendering + createDate?: Date; + updatedDate?: Date; + to?: To; // whether or not to render this item as a Link + draggable?: boolean; // whether or not to allow dragging this item + selectable?: boolean; // show selection checkbox + selected?: boolean; + operations?: ReactNode; // operations to show on the right side of the item + onClick?: () => void; + onSelectedChange?: () => void; +}; + +export type TagListItemProps = { + tagId: string; + color: string; + title: ReactNode; // using ReactNode to allow for rich content rendering + pageCount?: number; + createDate?: Date; + updatedDate?: Date; + to?: To; // whether or not to render this item as a Link + draggable?: boolean; // whether or not to allow dragging this item + selectable?: boolean; // show selection checkbox + selected?: boolean; + operations?: ReactNode; // operations to show on the right side of the item + onClick?: () => void; + onSelectedChange?: () => void; +}; + +export interface ItemListHeaderProps {} // todo: a temporary solution. may need to be refactored later -export type PagesGroupByType = 'createDate' | 'updatedDate'; // todo: can add more later +export type ItemGroupByType = 'createDate' | 'updatedDate'; // todo: can add more later // todo: a temporary solution. may need to be refactored later export interface SortBy { @@ -36,56 +83,75 @@ export interface SortBy { export type DateKey = 'createDate' | 'updatedDate'; -export interface PageListProps { +export interface ListProps { // required data: - pages: PageMeta[]; + items: T[]; blockSuiteWorkspace: Workspace; className?: string; hideHeader?: boolean; // whether or not to hide the header. default is false (showing header) - groupBy?: PagesGroupByType | false; - isPreferredEdgeless: (pageId: string) => boolean; // determines the icon used for each row + groupBy?: ItemGroupByType | false; + isPreferredEdgeless?: (pageId: string) => boolean; // determines the icon used for each row rowAsLink?: boolean; selectable?: 'toggle' | boolean; // show selection checkbox. toggle means showing a toggle selection in header on click; boolean == true means showing a selection checkbox for each item - selectedPageIds?: string[]; // selected page ids - onSelectedPageIdsChange?: (selected: string[]) => void; + selectedIds?: string[]; // selected page ids + onSelectedIdsChange?: (selected: string[]) => void; onSelectionActiveChange?: (active: boolean) => void; draggable?: boolean; // whether or not to allow dragging this page item // we also need the following to make sure the page list functions properly // maybe we could also give a function to render PageListItem? - pageOperationsRenderer?: (page: PageMeta) => ReactNode; + operationsRenderer?: (item: T) => ReactNode; } -export interface VirtualizedPageListProps extends PageListProps { +export interface VirtualizedListProps extends ListProps { heading?: ReactNode; // the user provided heading part (non sticky, above the original header) + headerRenderer?: () => ReactNode; // the user provided header renderer + itemRenderer?: (item: T) => ReactNode; // the user provided item renderer atTopThreshold?: number; // the threshold to determine whether or not the user has scrolled to the top. default is 0 atTopStateChange?: (atTop: boolean) => void; // called when the user scrolls to the top or not } -export interface PageListHandle { +export interface ItemListHandle { toggleSelectable: () => void; } -export interface PageGroupDefinition { +export interface ItemGroupDefinition { id: string; // using a function to render custom group header label: (() => ReactNode) | ReactNode; - match: (item: PageMeta) => boolean; + match: (item: T) => boolean; } -export interface PageGroupProps { +export interface ItemGroupProps { id: string; label?: ReactNode; // if there is no label, it is a default group (without header) - items: PageMeta[]; - allItems: PageMeta[]; + items: T[]; + allItems: T[]; } type MakeRecord = { [P in keyof T]: T[P]; }; -export type PageMetaRecord = MakeRecord; +export type MetaRecord = MakeRecord; export type DraggableTitleCellData = { pageId: string; pageTitle: ReactNode; }; + +export type HeaderColDef = { + key: string; + content: ReactNode; + flex: ColWrapperProps['flex']; + alignment?: ColWrapperProps['alignment']; + sortable?: boolean; + hideInSmallContainer?: boolean; +}; + +export type ColWrapperProps = PropsWithChildren<{ + flex?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; + alignment?: 'start' | 'center' | 'end'; + styles?: React.CSSProperties; + hideInSmallContainer?: boolean; +}> & + React.HTMLAttributes; diff --git a/packages/frontend/core/src/pages/workspace/pages.tsx b/packages/frontend/core/src/components/page-list/use-filtered-page-metas.tsx similarity index 83% rename from packages/frontend/core/src/pages/workspace/pages.tsx rename to packages/frontend/core/src/components/page-list/use-filtered-page-metas.tsx index ecb689923b..0a17b50ff5 100644 --- a/packages/frontend/core/src/pages/workspace/pages.tsx +++ b/packages/frontend/core/src/components/page-list/use-filtered-page-metas.tsx @@ -1,16 +1,16 @@ -import { - filterPage, - filterPageByRules, - useCollectionManager, -} from '@affine/core/components/page-list'; +import { allPageModeSelectAtom } from '@affine/core/atoms'; +import { collectionsCRUDAtom } from '@affine/core/atoms/collections'; +import { usePageHelper } from '@affine/core/components/blocksuite/block-suite-page-list/utils'; +import type { BlockSuiteWorkspace } from '@affine/core/shared'; import type { PageMeta } from '@blocksuite/store'; import { useAtomValue } from 'jotai'; import { useMemo } from 'react'; -import { allPageModeSelectAtom } from '../../atoms'; -import { collectionsCRUDAtom } from '../../atoms/collections'; -import { usePageHelper } from '../../components/blocksuite/block-suite-page-list/utils'; -import type { BlockSuiteWorkspace } from '../../shared'; +import { + filterPage, + filterPageByRules, + useCollectionManager, +} from './use-collection-manager'; export const useFilteredPageMetas = ( route: 'all' | 'trash', diff --git a/packages/frontend/core/src/components/page-list/use-tag-metas.ts b/packages/frontend/core/src/components/page-list/use-tag-metas.ts new file mode 100644 index 0000000000..4e08f22bf1 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/use-tag-metas.ts @@ -0,0 +1,100 @@ +import type { PageMeta, Tag, Workspace } from '@blocksuite/store'; +import { useCallback, useMemo } from 'react'; + +interface TagUsageCounts { + [key: string]: number; +} + +export function useTagMetas( + currentWorkspace: Workspace, + pageMetas: PageMeta[] +) { + const tags = useMemo(() => { + return currentWorkspace.meta.properties.tags?.options || []; + }, [currentWorkspace]); + + const [tagMetas, tagUsageCounts] = useMemo(() => { + const tagUsageCounts: TagUsageCounts = {}; + tags.forEach(tag => { + tagUsageCounts[tag.id] = 0; + }); + + pageMetas.forEach(page => { + if (!page.tags) { + return; + } + page.tags.forEach(tagId => { + if (Object.prototype.hasOwnProperty.call(tagUsageCounts, tagId)) { + tagUsageCounts[tagId]++; + } + }); + }); + + const tagsList = tags.map(tag => { + return { + ...tag, + title: tag.value, + color: tag.color, + pageCount: tagUsageCounts[tag.id] || 0, + }; + }); + + return [tagsList, tagUsageCounts]; + }, [tags, pageMetas]); + + const filterPageMetaByTag = useCallback( + (tagId: string) => { + return pageMetas.filter(page => { + return page.tags.includes(tagId); + }); + }, + [pageMetas] + ); + + const addNewTag = useCallback( + (tag: Tag) => { + const newTags = [...tags, tag]; + currentWorkspace.meta.setProperties({ + tags: { options: newTags }, + }); + }, + [currentWorkspace.meta, tags] + ); + + const updateTag = useCallback( + (tag: Tag) => { + const newTags = tags.map(t => { + if (t.id === tag.id) { + return tag; + } + return t; + }); + currentWorkspace.meta.setProperties({ + tags: { options: newTags }, + }); + }, + [currentWorkspace.meta, tags] + ); + + const deleteTags = useCallback( + (tagIds: string[]) => { + const newTags = tags.filter(tag => { + return !tagIds.includes(tag.id); + }); + currentWorkspace.meta.setProperties({ + tags: { options: newTags }, + }); + }, + [currentWorkspace.meta, tags] + ); + + return { + tags, + tagMetas, + tagUsageCounts, + filterPageMetaByTag, + addNewTag, + updateTag, + deleteTags, + }; +} diff --git a/packages/frontend/core/src/components/page-list/utils.tsx b/packages/frontend/core/src/components/page-list/utils.tsx index c0f29a9e10..64d6869878 100644 --- a/packages/frontend/core/src/components/page-list/utils.tsx +++ b/packages/frontend/core/src/components/page-list/utils.tsx @@ -1,11 +1,8 @@ import clsx from 'clsx'; -import { - type BaseSyntheticEvent, - forwardRef, - type PropsWithChildren, -} from 'react'; +import { type BaseSyntheticEvent, forwardRef } from 'react'; -import * as styles from './page-list.css'; +import * as styles from './list.css'; +import type { ColWrapperProps } from './types'; export function isToday(date: Date): boolean { const today = new Date(); @@ -71,14 +68,6 @@ export const formatDate = (date: Date): string => { return `${month}-${day} ${hours}:${minutes}`; }; -export type ColWrapperProps = PropsWithChildren<{ - flex?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; - alignment?: 'start' | 'center' | 'end'; - styles?: React.CSSProperties; - hideInSmallContainer?: boolean; -}> & - React.HTMLAttributes; - export const ColWrapper = forwardRef( function ColWrapper( { @@ -103,11 +92,10 @@ export const ColWrapper = forwardRef( flexBasis: flex ? `${(flex / 12) * 100}%` : 'auto', justifyContent: alignment, }} - className={clsx( - className, - styles.colWrapper, - hideInSmallContainer ? styles.hideInSmallContainer : null - )} + data-hide-item={hideInSmallContainer ? true : undefined} + className={clsx(className, styles.colWrapper, { + [styles.hideInSmallContainer]: hideInSmallContainer, + })} > {children}
@@ -173,3 +161,20 @@ export function shallowEqual(objA: any, objB: any) { return true; } + +// hack: map var(--affine-tag-xxx) colors to var(--affine-palette-line-xxx) +export const tagColorMap = (color: string) => { + const mapping: Record = { + 'var(--affine-tag-red)': 'var(--affine-palette-line-red)', + 'var(--affine-tag-teal)': 'var(--affine-palette-line-green)', + 'var(--affine-tag-blue)': 'var(--affine-palette-line-blue)', + 'var(--affine-tag-yellow)': 'var(--affine-palette-line-yellow)', + 'var(--affine-tag-pink)': 'var(--affine-palette-line-magenta)', + 'var(--affine-tag-white)': 'var(--affine-palette-line-grey)', + 'var(--affine-tag-gray)': 'var(--affine-palette-line-grey)', + 'var(--affine-tag-orange)': 'var(--affine-palette-line-orange)', + 'var(--affine-tag-purple)': 'var(--affine-palette-line-purple)', + 'var(--affine-tag-green)': 'var(--affine-palette-line-green)', + }; + return mapping[color] || color; +}; diff --git a/packages/frontend/core/src/components/page-list/view/collection-list.css.ts b/packages/frontend/core/src/components/page-list/view/collection-list.css.ts index 8e73a8d392..cc1b313557 100644 --- a/packages/frontend/core/src/components/page-list/view/collection-list.css.ts +++ b/packages/frontend/core/src/components/page-list/view/collection-list.css.ts @@ -38,4 +38,9 @@ export const filterMenuTrigger = style({ ':hover': { backgroundColor: 'var(--affine-hover-color)', }, + selectors: { + [`&[data-is-hidden="true"]`]: { + display: 'none', + }, + }, }); diff --git a/packages/frontend/core/src/components/page-list/view/collection-list.tsx b/packages/frontend/core/src/components/page-list/view/collection-list.tsx index 2a99409c3b..ec4096df20 100644 --- a/packages/frontend/core/src/components/page-list/view/collection-list.tsx +++ b/packages/frontend/core/src/components/page-list/view/collection-list.tsx @@ -25,11 +25,13 @@ export const CollectionList = ({ propertiesMeta, allPageListConfig, userInfo, + disable, }: { setting: ReturnType; propertiesMeta: PropertiesMeta; allPageListConfig: AllPageListConfig; userInfo: DeleteCollectionInfo; + disable?: boolean; }) => { const t = useAFFiNEI18N(); const [collection, setCollection] = useState(); @@ -72,6 +74,7 @@ export const CollectionList = ({ className={styles.filterMenuTrigger} type="default" icon={} + data-is-hidden={disable} data-testid="create-first-filter" > {t['com.affine.filter']()} diff --git a/packages/frontend/core/src/components/page-list/view/edit-collection/pages-mode.tsx b/packages/frontend/core/src/components/page-list/view/edit-collection/pages-mode.tsx index f13d99599c..b0c707bba4 100644 --- a/packages/frontend/core/src/components/page-list/view/edit-collection/pages-mode.tsx +++ b/packages/frontend/core/src/components/page-list/view/edit-collection/pages-mode.tsx @@ -8,7 +8,11 @@ import { type ReactNode, useCallback } from 'react'; import { FilterList } from '../../filter/filter-list'; import { VariableSelect } from '../../filter/vars'; -import { VirtualizedPageList } from '../../virtualized-page-list'; +import { pageHeaderColsDef } from '../../header-col-def'; +import { PageListItemRenderer } from '../../page-group'; +import { ListTableHeader } from '../../page-header'; +import type { ListItem } from '../../types'; +import { VirtualizedList } from '../../virtualized-list'; import type { AllPageListConfig } from './edit-collection'; import * as styles from './edit-collection.css'; import { EmptyList } from './select-page'; @@ -46,9 +50,19 @@ export const PagesMode = ({ }); }, [collection, updateCollection]); const pageOperationsRenderer = useCallback( - (page: PageMeta) => allPageListConfig.favoriteRender(page), + (item: ListItem) => { + const page = item as PageMeta; + return allPageListConfig.favoriteRender(page); + }, [allPageListConfig] ); + + const pageItemRenderer = useCallback((item: ListItem) => { + return ; + }, []); + const pageHeaderRenderer = useCallback(() => { + return ; + }, []); return ( <> ) : null} {searchedList.length ? ( - { + onSelectedIdsChange={ids => { updateCollection({ ...collection, allowList: ids, }); }} - pageOperationsRenderer={pageOperationsRenderer} - selectedPageIds={collection.allowList} + itemRenderer={pageItemRenderer} + operationsRenderer={pageOperationsRenderer} + headerRenderer={pageHeaderRenderer} + selectedIds={collection.allowList} isPreferredEdgeless={allPageListConfig.isEdgeless} - > + /> ) : ( )} diff --git a/packages/frontend/core/src/components/page-list/view/edit-collection/rules-mode.tsx b/packages/frontend/core/src/components/page-list/view/edit-collection/rules-mode.tsx index c7e4b009c3..1bdf1a1bf9 100644 --- a/packages/frontend/core/src/components/page-list/view/edit-collection/rules-mode.tsx +++ b/packages/frontend/core/src/components/page-list/view/edit-collection/rules-mode.tsx @@ -13,7 +13,8 @@ import clsx from 'clsx'; import { type ReactNode, useCallback, useEffect, useState } from 'react'; import { FilterList } from '../../filter'; -import { PageList, PageListScrollContainer } from '../../page-list'; +import { List, ListScrollContainer } from '../../list'; +import type { ListItem } from '../../types'; import { filterPageByRules } from '../../use-collection-manager'; import { AffineShapeIcon } from '../affine-shape'; import type { AllPageListConfig } from './edit-collection'; @@ -78,6 +79,13 @@ export const RulesMode = ({ const [expandInclude, setExpandInclude] = useState( collection.allowList.length > 0 ); + const operationsRenderer = useCallback( + (item: ListItem) => { + const page = item as PageMeta; + return allPageListConfig.favoriteRender(page); + }, + [allPageListConfig] + ); return ( <> {/*prevents modal autofocus to the first input*/} @@ -241,22 +249,22 @@ export const RulesMode = ({ ) : null} - {rulesPages.length > 0 ? ( - + operationsRenderer={operationsRenderer} + > ) : ( {t['com.affine.editCollection.rules.include.title']()} - + operationsRenderer={operationsRenderer} + > ) : null} - +
diff --git a/packages/frontend/core/src/components/page-list/view/edit-collection/select-page.tsx b/packages/frontend/core/src/components/page-list/view/edit-collection/select-page.tsx index 7debf879c0..3974edb585 100644 --- a/packages/frontend/core/src/components/page-list/view/edit-collection/select-page.tsx +++ b/packages/frontend/core/src/components/page-list/view/edit-collection/select-page.tsx @@ -2,12 +2,14 @@ import { Button, Menu } from '@affine/component'; import { Trans } from '@affine/i18n'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { FilterIcon } from '@blocksuite/icons'; +import type { PageMeta } from '@blocksuite/store'; import clsx from 'clsx'; import { useCallback, useState } from 'react'; import { FilterList } from '../../filter'; import { VariableSelect } from '../../filter/vars'; -import { VirtualizedPageList } from '../../virtualized-page-list'; +import type { ListItem } from '../../types'; +import { VirtualizedList } from '../../virtualized-list'; import { AffineShapeIcon } from '../affine-shape'; import type { AllPageListConfig } from './edit-collection'; import * as styles from './edit-collection.css'; @@ -43,6 +45,15 @@ export const SelectPage = ({ } = useFilter(allPageListConfig.allPages); const { searchText, updateSearchText, searchedList } = useSearch(filteredList); + + const operationsRenderer = useCallback( + (item: ListItem) => { + const page = item as PageMeta; + return allPageListConfig.favoriteRender(page); + }, + [allPageListConfig] + ); + return (
) : null} {searchedList.length ? ( - ) : ( diff --git a/packages/frontend/core/src/components/page-list/virtualized-page-list.tsx b/packages/frontend/core/src/components/page-list/virtualized-list.tsx similarity index 62% rename from packages/frontend/core/src/components/page-list/virtualized-page-list.tsx rename to packages/frontend/core/src/components/page-list/virtualized-list.tsx index baff371df5..87f94aa647 100644 --- a/packages/frontend/core/src/components/page-list/virtualized-page-list.tsx +++ b/packages/frontend/core/src/components/page-list/virtualized-list.tsx @@ -1,5 +1,4 @@ import { Scrollable } from '@affine/component'; -import type { PageMeta } from '@blocksuite/store'; import clsx from 'clsx'; import { selectAtom } from 'jotai/utils'; import { @@ -12,29 +11,29 @@ import { } from 'react'; import { Virtuoso } from 'react-virtuoso'; -import { PageGroupHeader, PageMetaListItemRenderer } from './page-group'; -import { PageListTableHeader } from './page-header'; -import { PageListInnerWrapper } from './page-list'; -import * as styles from './page-list.css'; +import { ListInnerWrapper } from './list'; +import * as styles from './list.css'; +import { ItemGroupHeader } from './page-group'; import { - pageGroupCollapseStateAtom, - pageGroupsAtom, - pageListPropsAtom, - PageListProvider, + groupCollapseStateAtom, + groupsAtom, + listPropsAtom, + ListProvider, useAtomValue, } from './scoped-atoms'; import type { - PageGroupProps, - PageListHandle, - VirtualizedPageListProps, + ItemGroupProps, + ItemListHandle, + ListItem, + VirtualizedListProps, } from './types'; // we have three item types for rendering rows in Virtuoso type VirtuosoItemType = | 'sticky-header' - | 'page-group-header' - | 'page-item' - | 'page-item-spacer'; + | 'group-header' + | 'item' + | 'item-spacer'; interface BaseVirtuosoItem { type: VirtuosoItemType; @@ -44,62 +43,62 @@ interface VirtuosoItemStickyHeader extends BaseVirtuosoItem { type: 'sticky-header'; } -interface VirtuosoItemPageItem extends BaseVirtuosoItem { - type: 'page-item'; - data: PageMeta; +interface VirtuosoItemItem extends BaseVirtuosoItem { + type: 'item'; + data: T; } -interface VirtuosoItemPageGroupHeader extends BaseVirtuosoItem { - type: 'page-group-header'; - data: PageGroupProps; +interface VirtuosoItemGroupHeader extends BaseVirtuosoItem { + type: 'group-header'; + data: ItemGroupProps; } interface VirtuosoPageItemSpacer extends BaseVirtuosoItem { - type: 'page-item-spacer'; + type: 'item-spacer'; data: { height: number; }; } -type VirtuosoItem = +type VirtuosoItem = | VirtuosoItemStickyHeader - | VirtuosoItemPageItem - | VirtuosoItemPageGroupHeader + | VirtuosoItemItem + | VirtuosoItemGroupHeader | VirtuosoPageItemSpacer; /** * Given a list of pages, render a list of pages * Similar to normal PageList, but uses react-virtuoso to render the list (virtual rendering) */ -export const VirtualizedPageList = forwardRef< - PageListHandle, - VirtualizedPageListProps ->(function VirtualizedPageList(props, ref) { +export const VirtualizedList = forwardRef< + ItemListHandle, + VirtualizedListProps +>(function VirtualizedList(props, ref) { return ( // push pageListProps to the atom so that downstream components can consume it // this makes sure pageListPropsAtom is always populated // @ts-expect-error fix type issues later - - - - - + + + + + ); }); -const headingAtom = selectAtom(pageListPropsAtom, props => props.heading); +const headingAtom = selectAtom(listPropsAtom, props => props.heading); const PageListHeading = () => { const heading = useAtomValue(headingAtom); return
{heading}
; }; -const useVirtuosoItems = () => { - const groups = useAtomValue(pageGroupsAtom); - const groupCollapsedState = useAtomValue(pageGroupCollapseStateAtom); +const useVirtuosoItems = () => { + const groups = useAtomValue(groupsAtom); + const groupCollapsedState = useAtomValue(groupCollapseStateAtom); return useMemo(() => { - const items: VirtuosoItem[] = []; + const items: VirtuosoItem[] = []; // 1. // always put sticky header at the top @@ -114,21 +113,21 @@ const useVirtuosoItems = () => { // skip empty group header since it will cause issue in virtuoso ("Zero-sized element") if (group.label) { items.push({ - type: 'page-group-header', - data: group, + type: 'group-header', + data: group as ItemGroupProps, }); } // do not render items if the group is collapsed if (!groupCollapsedState[group.id]) { for (const item of group.items) { items.push({ - type: 'page-item', - data: item, + type: 'item', + data: item as T, }); // add a spacer between items (4px), unless it's the last item if (item !== group.items[group.items.length - 1]) { items.push({ - type: 'page-item-spacer', + type: 'item-spacer', data: { height: 4, }, @@ -139,7 +138,7 @@ const useVirtuosoItems = () => { // add a spacer between groups (16px) items.push({ - type: 'page-item-spacer', + type: 'item-spacer', data: { height: 16, }, @@ -149,19 +148,6 @@ const useVirtuosoItems = () => { }, [groupCollapsedState, groups]); }; -const itemContentRenderer = (_index: number, data: VirtuosoItem) => { - switch (data.type) { - case 'sticky-header': - return ; - case 'page-group-header': - return ; - case 'page-item': - return ; - case 'page-item-spacer': - return
; - } -}; - const Scroller = forwardRef< HTMLDivElement, PropsWithChildren> @@ -178,12 +164,12 @@ const Scroller = forwardRef< Scroller.displayName = 'Scroller'; -const PageListInner = ({ +const ListInner = ({ atTopStateChange, atTopThreshold, ...props -}: VirtualizedPageListProps) => { - const virtuosoItems = useVirtuosoItems(); +}: VirtualizedListProps) => { + const virtuosoItems = useVirtuosoItems(); const [atTop, setAtTop] = useState(false); const handleAtTopStateChange = useCallback( (atTop: boolean) => { @@ -198,15 +184,30 @@ const PageListInner = ({ Scroller: Scroller, }; }, [props.heading]); + const itemContentRenderer = useCallback( + (_index: number, data: VirtuosoItem) => { + switch (data.type) { + case 'sticky-header': + return props.headerRenderer?.(); + case 'group-header': + return ; + case 'item': + return props.itemRenderer?.(data.data); + case 'item-spacer': + return
; + } + }, + [props] + ); return ( - + > data-has-scroll-top={!atTop} atTopThreshold={atTopThreshold ?? 0} atTopStateChange={handleAtTopStateChange} components={components} data={virtuosoItems} data-testid="virtualized-page-list" - data-total-count={props.pages.length} // for testing, since we do not know the total count in test + data-total-count={props.items.length} // for testing, since we do not know the total count in test topItemCount={1} // sticky header totalCount={virtuosoItems.length} itemContent={itemContentRenderer} diff --git a/packages/frontend/core/src/components/pure/workspace-mode-filter-tab/index.tsx b/packages/frontend/core/src/components/pure/workspace-mode-filter-tab/index.tsx index 61b8078c61..fa5f22fcd5 100644 --- a/packages/frontend/core/src/components/pure/workspace-mode-filter-tab/index.tsx +++ b/packages/frontend/core/src/components/pure/workspace-mode-filter-tab/index.tsx @@ -1,30 +1,59 @@ import { RadioButton, RadioButtonGroup } from '@affine/component'; +import type { AllPageFilterOption } from '@affine/core/atoms'; +import { allPageFilterSelectAtom } from '@affine/core/atoms'; +import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper'; +import { WorkspaceSubPath } from '@affine/core/shared'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAtom } from 'jotai'; +import { useCallback, useEffect, useState } from 'react'; -import { allPageModeSelectAtom } from '../../../atoms'; import * as styles from './index.css'; -export const WorkspaceModeFilterTab = () => { +export const WorkspaceModeFilterTab = ({ + workspaceId, + activeFilter, +}: { + workspaceId: string; + activeFilter: AllPageFilterOption; +}) => { const t = useAFFiNEI18N(); - const [value, setMode] = useAtom(allPageModeSelectAtom); - const handleValueChange = (value: string) => { - if (value !== 'all' && value !== 'page' && value !== 'edgeless') { - throw new Error('Invalid value for page mode option'); + const [value, setValue] = useState(activeFilter); + const [filterMode, setFilterMode] = useAtom(allPageFilterSelectAtom); + const { jumpToCollections, jumpToTags, jumpToSubPath } = useNavigateHelper(); + const handleValueChange = useCallback( + (value: AllPageFilterOption) => { + switch (value) { + case 'collections': + jumpToCollections(workspaceId); + break; + case 'tags': + jumpToTags(workspaceId); + break; + case 'docs': + jumpToSubPath(workspaceId, WorkspaceSubPath.ALL); + break; + } + }, + [jumpToCollections, jumpToSubPath, jumpToTags, workspaceId] + ); + + useEffect(() => { + if (value !== activeFilter) { + setValue(activeFilter); + setFilterMode(activeFilter); } - setMode(value); - }; + }, [activeFilter, filterMode, setFilterMode, value]); return ( - - {t['com.affine.pageMode.all']()} + + {t['com.affine.docs.header']()} - - {t['com.affine.pageMode.page']()} + + {t['com.affine.collections.header']()} - - {t['com.affine.pageMode.edgeless']()} + + {t['Tags']()} ); diff --git a/packages/frontend/core/src/components/root-app-sidebar/index.tsx b/packages/frontend/core/src/components/root-app-sidebar/index.tsx index 3e888fe866..ffc86afb3c 100644 --- a/packages/frontend/core/src/components/root-app-sidebar/index.tsx +++ b/packages/frontend/core/src/components/root-app-sidebar/index.tsx @@ -69,15 +69,12 @@ export type RootAppSidebarProps = { const RouteMenuLinkItem = forwardRef< HTMLDivElement, { - currentPath: string; // todo: pass through useRouter? path: string; icon: ReactElement; + active?: boolean; children?: ReactElement; - isDraggedOver?: boolean; } & HTMLAttributes ->(({ currentPath, path, icon, children, isDraggedOver, ...props }, ref) => { - // Force active style when a page is dragged over - const active = isDraggedOver || currentPath === path; +>(({ path, icon, active, children, ...props }, ref) => { return ( { + if ( + currentPath.startsWith(`/workspace/${currentWorkspaceId}/collection/`) || + currentPath.startsWith(`/workspace/${currentWorkspaceId}/tag/`) + ) { + return true; + } + return currentPath === paths.all(currentWorkspaceId); + }, [currentPath, currentWorkspaceId, paths]); + + const trashActive = useMemo(() => { + return ( + currentPath === paths.trash(currentWorkspaceId) || trashDroppable.isOver + ); + }, [currentPath, currentWorkspaceId, paths, trashDroppable.isOver]); + return ( } - currentPath={currentPath} + active={allPageActive} path={paths.all(currentWorkspaceId)} onClick={backToAll} > @@ -289,9 +302,8 @@ export const RootAppSidebar = ({
} - currentPath={currentPath} + active={trashActive} path={paths.trash(currentWorkspaceId)} > diff --git a/packages/frontend/core/src/hooks/use-navigate-helper.ts b/packages/frontend/core/src/hooks/use-navigate-helper.ts index 5e5dc12dcb..6fbc927674 100644 --- a/packages/frontend/core/src/hooks/use-navigate-helper.ts +++ b/packages/frontend/core/src/hooks/use-navigate-helper.ts @@ -42,6 +42,22 @@ export function useNavigateHelper() { }, [navigate] ); + const jumpToCollections = useCallback( + (workspaceId: string, logic: RouteLogic = RouteLogic.PUSH) => { + return navigate(`/workspace/${workspaceId}/all?filterMode=collections`, { + replace: logic === RouteLogic.REPLACE, + }); + }, + [navigate] + ); + const jumpToTags = useCallback( + (workspaceId: string, logic: RouteLogic = RouteLogic.PUSH) => { + return navigate(`/workspace/${workspaceId}/all?filterMode=tags`, { + replace: logic === RouteLogic.REPLACE, + }); + }, + [navigate] + ); const jumpToCollection = useCallback( ( workspaceId: string, @@ -144,6 +160,8 @@ export function useNavigateHelper() { jumpToExpired, jumpToSignIn, jumpToCollection, + jumpToCollections, + jumpToTags, }), [ jumpToPage, @@ -156,6 +174,8 @@ export function useNavigateHelper() { jumpToExpired, jumpToSignIn, jumpToCollection, + jumpToCollections, + jumpToTags, ] ); } diff --git a/packages/frontend/core/src/hooks/use-quota.ts b/packages/frontend/core/src/hooks/use-quota.ts index 30d8dc08c9..9ea58f6994 100644 --- a/packages/frontend/core/src/hooks/use-quota.ts +++ b/packages/frontend/core/src/hooks/use-quota.ts @@ -1,4 +1,4 @@ -import { quotaQuery } from '@affine/graphql'; +import { quotaQuery, workspaceQuotaQuery } from '@affine/graphql'; import { useQuery } from './use-query'; @@ -9,3 +9,14 @@ export const useUserQuota = () => { return data.currentUser?.quota || null; }; + +export const useWorkspaceQuota = (id: string) => { + const { data } = useQuery({ + query: workspaceQuotaQuery, + variables: { + id, + }, + }); + + return data.workspace?.quota || null; +}; diff --git a/packages/frontend/core/src/hooks/use-register-workspace-commands.ts b/packages/frontend/core/src/hooks/use-register-workspace-commands.ts index 2a17abc569..6075b1dc4c 100644 --- a/packages/frontend/core/src/hooks/use-register-workspace-commands.ts +++ b/packages/frontend/core/src/hooks/use-register-workspace-commands.ts @@ -1,6 +1,6 @@ import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; -import { useAtom, useAtomValue, useStore } from 'jotai'; +import { useAtomValue, useSetAtom, useStore } from 'jotai'; import { useTheme } from 'next-themes'; import { useEffect } from 'react'; @@ -26,7 +26,7 @@ export function useRegisterWorkspaceCommands() { const languageHelper = useLanguageHelper(); const pageHelper = usePageHelper(currentWorkspace.blockSuiteWorkspace); const navigationHelper = useNavigateHelper(); - const [pageListMode, setPageListMode] = useAtom(allPageModeSelectAtom); + const setPageListMode = useSetAtom(allPageModeSelectAtom); const [editor] = useActiveBlocksuiteEditor(); // register AffineUpdatesCommands @@ -48,7 +48,6 @@ export function useRegisterWorkspaceCommands() { t, workspace: currentWorkspace.blockSuiteWorkspace, navigationHelper, - pageListMode, setPageListMode, }); @@ -60,7 +59,6 @@ export function useRegisterWorkspaceCommands() { t, currentWorkspace.blockSuiteWorkspace, navigationHelper, - pageListMode, setPageListMode, ]); diff --git a/packages/frontend/core/src/hooks/use-workspace-quota.ts b/packages/frontend/core/src/hooks/use-workspace-quota.ts index 6420226402..aea5670ab1 100644 --- a/packages/frontend/core/src/hooks/use-workspace-quota.ts +++ b/packages/frontend/core/src/hooks/use-workspace-quota.ts @@ -17,24 +17,18 @@ export const useWorkspaceQuota = (workspaceId: string) => { }, []); const quotaData = data.workspace.quota; - const blobLimit = BigInt(quotaData.blobLimit); - const storageQuota = BigInt(quotaData.storageQuota); - const usedSize = BigInt(quotaData.usedSize); - - const humanReadableBlobLimit = changeToHumanReadable(blobLimit.toString()); - const humanReadableStorageQuota = changeToHumanReadable( - storageQuota.toString() + const humanReadableUsedSize = changeToHumanReadable( + quotaData.usedSize.toString() ); - const humanReadableUsedSize = changeToHumanReadable(usedSize.toString()); return { - blobLimit, - storageQuota, - usedSize, + blobLimit: quotaData.blobLimit, + storageQuota: quotaData.storageQuota, + usedSize: quotaData.usedSize, humanReadable: { - name: quotaData.humanReadableName, - blobLimit: humanReadableBlobLimit, - storageQuota: humanReadableStorageQuota, + name: quotaData.humanReadable.name, + blobLimit: quotaData.humanReadable.blobLimit, + storageQuota: quotaData.humanReadable.storageQuota, usedSize: humanReadableUsedSize, }, }; diff --git a/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx b/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx new file mode 100644 index 0000000000..c536cb9f89 --- /dev/null +++ b/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx @@ -0,0 +1,110 @@ +import { IconButton } from '@affine/component'; +import type { AllPageFilterOption } from '@affine/core/atoms'; +import { collectionsCRUDAtom } from '@affine/core/atoms/collections'; +import { + CollectionList, + PageListNewPageButton, + useCollectionManager, +} from '@affine/core/components/page-list'; +import { Header } from '@affine/core/components/pure/header'; +import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls'; +import { WorkspaceModeFilterTab } from '@affine/core/components/pure/workspace-mode-filter-tab'; +import { useAllPageListConfig } from '@affine/core/hooks/affine/use-all-page-list-config'; +import { useDeleteCollectionInfo } from '@affine/core/hooks/affine/use-delete-collection-info'; +import { PlusIcon } from '@blocksuite/icons'; +import type { Workspace } from '@blocksuite/store'; +import clsx from 'clsx'; +import { useMemo } from 'react'; + +import * as styles from './all-page.css'; +import { FilterContainer } from './all-page-filter'; + +export const AllPageHeader = ({ + workspace, + showCreateNew, + isDefaultFilter, + activeFilter, + onCreateCollection, +}: { + workspace: Workspace; + showCreateNew: boolean; + isDefaultFilter: boolean; + activeFilter: AllPageFilterOption; + onCreateCollection?: () => void; +}) => { + const setting = useCollectionManager(collectionsCRUDAtom); + const config = useAllPageListConfig(); + const userInfo = useDeleteCollectionInfo(); + const isWindowsDesktop = environment.isDesktop && environment.isWindows; + + const disableFilterButton = useMemo(() => { + return activeFilter !== 'docs' && isDefaultFilter; + }, [activeFilter, isDefaultFilter]); + + const renderRightItem = useMemo(() => { + if (activeFilter === 'tags') { + return null; + } + if ( + activeFilter === 'collections' && + isDefaultFilter && + onCreateCollection + ) { + return ( + } + onClick={onCreateCollection} + className={clsx( + styles.headerCreateNewButton, + styles.headerCreateNewCollectionIconButton, + !showCreateNew && styles.headerCreateNewButtonHidden + )} + /> + ); + } + return ( + + + + ); + }, [activeFilter, isDefaultFilter, onCreateCollection, showCreateNew]); + + return ( + <> +
+ } + right={ +
+ {renderRightItem} + {isWindowsDesktop ? : null} +
+ } + center={ + + } + /> + + + ); +}; diff --git a/packages/frontend/core/src/pages/workspace/all-page/all-page.css.ts b/packages/frontend/core/src/pages/workspace/all-page/all-page.css.ts index 70db74ebc4..1619148bd6 100644 --- a/packages/frontend/core/src/pages/workspace/all-page/all-page.css.ts +++ b/packages/frontend/core/src/pages/workspace/all-page/all-page.css.ts @@ -14,53 +14,15 @@ export const scrollContainer = style({ paddingBottom: '32px', }); -export const allPagesHeader = style({ - height: 100, - alignItems: 'center', - padding: '48px 16px 20px 24px', - overflow: 'hidden', - display: 'flex', - justifyContent: 'space-between', - background: 'var(--affine-background-primary-color)', -}); - -export const allPagesHeaderTitle = style({ - fontSize: 'var(--affine-font-h-5)', - fontWeight: 500, - color: 'var(--affine-text-secondary-color)', - display: 'flex', - alignItems: 'center', - gap: 8, -}); - -export const titleIcon = style({ - color: 'var(--affine-icon-color)', - display: 'inline-flex', - alignItems: 'center', -}); - -export const titleCollectionName = style({ - color: 'var(--affine-text-primary-color)', -}); - -export const floatingToolbar = style({ - position: 'absolute', - bottom: 26, - width: '100%', - zIndex: 1, -}); - -export const toolbarSelectedNumber = style({ - color: 'var(--affine-text-secondary-color)', -}); - export const headerCreateNewButton = style({ transition: 'opacity 0.1s ease-in-out', }); - -export const newPageButtonLabel = style({ - display: 'flex', - alignItems: 'center', +export const headerCreateNewCollectionIconButton = style({ + padding: '4px 8px', + fontSize: '16px', + width: '32px', + height: '28px', + borderRadius: '8px', }); export const headerCreateNewButtonHidden = style({ @@ -72,5 +34,9 @@ export const headerRightWindows = style({ display: 'flex', alignItems: 'center', gap: 8, - transform: 'translateX(16px)', + selectors: { + '&[data-is-windows-desktop="true"]': { + transform: 'translateX(16px)', + }, + }, }); diff --git a/packages/frontend/core/src/pages/workspace/all-page/all-page.tsx b/packages/frontend/core/src/pages/workspace/all-page/all-page.tsx index 5aff78bb27..5642330c48 100644 --- a/packages/frontend/core/src/pages/workspace/all-page/all-page.tsx +++ b/packages/frontend/core/src/pages/workspace/all-page/all-page.tsx @@ -1,322 +1,209 @@ -import { toast } from '@affine/component'; +import type { AllPageFilterOption } from '@affine/core/atoms'; +import { collectionsCRUDAtom } from '@affine/core/atoms/collections'; +import { HubIsland } from '@affine/core/components/affine/hub-island'; import { - CollectionList, + CollectionListHeader, + type CollectionMeta, + createEmptyCollection, currentCollectionAtom, - FloatingToolbar, - NewPageButton as PureNewPageButton, - OperationCell, - type PageListHandle, + PageListHeader, useCollectionManager, + useEditCollectionName, + useFilteredPageMetas, + useSavedCollections, + useTagMetas, + VirtualizedCollectionList, VirtualizedPageList, } from '@affine/core/components/page-list'; +import { + TagListHeader, + VirtualizedTagList, +} from '@affine/core/components/page-list/tags'; +import { useAllPageListConfig } from '@affine/core/hooks/affine/use-all-page-list-config'; import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta'; +import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper'; import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace'; -import { Trans } from '@affine/i18n'; +import { performanceRenderLogger } from '@affine/core/shared'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; -import { - CloseIcon, - DeleteIcon, - PlusIcon, - ViewLayersIcon, -} from '@blocksuite/icons'; -import type { PageMeta, Workspace } from '@blocksuite/store'; -import clsx from 'clsx'; import { useAtomValue, useSetAtom } from 'jotai'; -import { - type PropsWithChildren, - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from 'react'; +import { nanoid } from 'nanoid'; +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useLocation, useParams } from 'react-router-dom'; import { NIL } from 'uuid'; -import { collectionsCRUDAtom } from '../../../atoms/collections'; -import { HubIsland } from '../../../components/affine/hub-island'; -import { usePageHelper } from '../../../components/blocksuite/block-suite-page-list/utils'; -import { Header } from '../../../components/pure/header'; -import { WindowsAppControls } from '../../../components/pure/header/windows-app-controls'; -import { WorkspaceModeFilterTab } from '../../../components/pure/workspace-mode-filter-tab'; -import { useAllPageListConfig } from '../../../hooks/affine/use-all-page-list-config'; -import { useBlockSuiteMetaHelper } from '../../../hooks/affine/use-block-suite-meta-helper'; -import { useDeleteCollectionInfo } from '../../../hooks/affine/use-delete-collection-info'; -import { useTrashModalHelper } from '../../../hooks/affine/use-trash-modal-helper'; -import { useNavigateHelper } from '../../../hooks/use-navigate-helper'; -import { performanceRenderLogger } from '../../../shared'; -import { EmptyPageList } from '../page-list-empty'; -import { useFilteredPageMetas } from '../pages'; +import { + EmptyCollectionList, + EmptyPageList, + EmptyTagList, +} from '../page-list-empty'; import * as styles from './all-page.css'; -import { FilterContainer } from './all-page-filter'; - -const PageListHeader = () => { - const t = useAFFiNEI18N(); - const setting = useCollectionManager(collectionsCRUDAtom); - const title = useMemo(() => { - if (setting.isDefault) { - return t['com.affine.all-pages.header'](); - } - return ( - <> - {t['com.affine.collections.header']()} / -
- -
-
- {setting.currentCollection.name} -
- - ); - }, [setting.currentCollection.name, setting.isDefault, t]); - - return ( -
-
{title}
- - {t['New Page']()} - -
- ); -}; - -const usePageOperationsRenderer = () => { - const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom); - const { setTrashModal } = useTrashModalHelper( - currentWorkspace.blockSuiteWorkspace - ); - const { toggleFavorite } = useBlockSuiteMetaHelper( - currentWorkspace.blockSuiteWorkspace - ); - const t = useAFFiNEI18N(); - const pageOperationsRenderer = useCallback( - (page: PageMeta) => { - const onDisablePublicSharing = () => { - toast('Successfully disabled', { - portal: document.body, - }); - }; - return ( - - setTrashModal({ - open: true, - pageIds: [page.id], - pageTitles: [page.title], - }) - } - onToggleFavoritePage={() => { - const status = page.favorite; - toggleFavorite(page.id); - toast( - status - ? t['com.affine.toastMessage.removedFavorites']() - : t['com.affine.toastMessage.addedFavorites']() - ); - }} - /> - ); - }, - [currentWorkspace.id, setTrashModal, t, toggleFavorite] - ); - - return pageOperationsRenderer; -}; - -const PageListFloatingToolbar = ({ - selectedIds, - onClose, - open, -}: { - open: boolean; - selectedIds: string[]; - onClose: () => void; -}) => { - const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom); - const { setTrashModal } = useTrashModalHelper( - currentWorkspace.blockSuiteWorkspace - ); - const pageMetas = useBlockSuitePageMeta(currentWorkspace.blockSuiteWorkspace); - const handleMultiDelete = useCallback(() => { - const pageNameMapping = Object.fromEntries( - pageMetas.map(meta => [meta.id, meta.title]) - ); - - const pageNames = selectedIds.map(id => pageNameMapping[id] ?? ''); - setTrashModal({ - open: true, - pageIds: selectedIds, - pageTitles: pageNames, - }); - }, [pageMetas, selectedIds, setTrashModal]); - - return ( - - - -
- {{ count: selectedIds.length } as any} -
- selected -
-
- } /> - - } - type="danger" - data-testid="page-list-toolbar-delete" - /> -
- ); -}; - -const NewPageButton = ({ - className, - children, - size, - testId, -}: PropsWithChildren<{ - className?: string; - size?: 'small' | 'default'; - testId?: string; -}>) => { - const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom); - const { importFile, createEdgeless, createPage } = usePageHelper( - currentWorkspace.blockSuiteWorkspace - ); - return ( -
- -
{children}
-
-
- ); -}; - -const AllPageHeader = ({ - workspace, - showCreateNew, -}: { - workspace: Workspace; - showCreateNew: boolean; -}) => { - const setting = useCollectionManager(collectionsCRUDAtom); - const config = useAllPageListConfig(); - const userInfo = useDeleteCollectionInfo(); - const isWindowsDesktop = environment.isDesktop && environment.isWindows; - - return ( - <> -
- } - right={ -
- - - - {isWindowsDesktop ? : null} -
- } - center={} - /> - - - ); -}; +import { AllPageHeader } from './all-page-header'; // even though it is called all page, it is also being used for collection route as well -export const AllPage = () => { +export const AllPage = ({ + activeFilter, +}: { + activeFilter: AllPageFilterOption; +}) => { + const t = useAFFiNEI18N(); + const params = useParams(); const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom); - const { isPreferredEdgeless } = usePageHelper( - currentWorkspace.blockSuiteWorkspace - ); const pageMetas = useBlockSuitePageMeta(currentWorkspace.blockSuiteWorkspace); - const pageOperationsRenderer = usePageOperationsRenderer(); + const [hideHeaderCreateNew, setHideHeaderCreateNew] = useState(true); + + const setting = useCollectionManager(collectionsCRUDAtom); + const config = useAllPageListConfig(); + const { collections } = useSavedCollections(collectionsCRUDAtom); + const { tags, tagMetas, filterPageMetaByTag, deleteTags } = useTagMetas( + currentWorkspace.blockSuiteWorkspace, + pageMetas + ); const filteredPageMetas = useFilteredPageMetas( 'all', pageMetas, currentWorkspace.blockSuiteWorkspace ); - const [selectedPageIds, setSelectedPageIds] = useState([]); - const pageListRef = useRef(null); + const tagPageMetas = useMemo(() => { + if (params.tagId) { + return filterPageMetaByTag(params.tagId); + } + return []; + }, [filterPageMetaByTag, params.tagId]); - const [showFloatingToolbar, setShowFloatingToolbar] = useState(false); + const collectionMetas = useMemo(() => { + const collectionsList: CollectionMeta[] = collections.map(collection => { + return { + ...collection, + title: collection.name, + }; + }); + return collectionsList; + }, [collections]); - const hideFloatingToolbar = useCallback(() => { - pageListRef.current?.toggleSelectable(); - }, []); + const navigateHelper = useNavigateHelper(); + const { open, node } = useEditCollectionName({ + title: t['com.affine.editCollection.createCollection'](), + showTips: true, + }); - // make sure selected id is in the filtered list - const filteredSelectedPageIds = useMemo(() => { - const ids = filteredPageMetas.map(page => page.id); - return selectedPageIds.filter(id => ids.includes(id)); - }, [filteredPageMetas, selectedPageIds]); + const handleCreateCollection = useCallback(() => { + open('') + .then(name => { + const id = nanoid(); + setting.createCollection(createEmptyCollection(id, { name })); + navigateHelper.jumpToCollection(currentWorkspace.id, id); + }) + .catch(err => { + console.error(err); + }); + }, [currentWorkspace.id, navigateHelper, open, setting]); - const [hideHeaderCreateNewPage, setHideHeaderCreateNewPage] = useState(true); + const currentTag = useMemo(() => { + if (params.tagId) { + return tags.find(tag => tag.id === params.tagId); + } + return; + }, [params.tagId, tags]); + + const content = useMemo(() => { + if (filteredPageMetas.length > 0 && activeFilter === 'docs') { + return ( + + ); + } else if (activeFilter === 'collections' && !setting.isDefault) { + return ( + + ); + } else if (activeFilter === 'collections' && setting.isDefault) { + return collectionMetas.length > 0 ? ( + + ) : ( + + } + /> + ); + } else if (activeFilter === 'tags') { + if (params.tagId) { + return tagPageMetas.length > 0 ? ( + + ) : ( + } + blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace} + /> + ); + } + return tags.length > 0 ? ( + + ) : ( + } /> + ); + } + return ( + } + blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace} + /> + ); + }, [ + activeFilter, + collectionMetas, + collections, + config, + currentTag, + currentWorkspace.blockSuiteWorkspace, + currentWorkspace.id, + deleteTags, + filteredPageMetas.length, + handleCreateCollection, + node, + params.tagId, + setting.currentCollection, + setting.isDefault, + tagMetas, + tagPageMetas, + tags, + ]); return (
- {filteredPageMetas.length > 0 ? ( - <> - } - selectedPageIds={filteredSelectedPageIds} - onSelectedPageIdsChange={setSelectedPageIds} - pages={filteredPageMetas} - rowAsLink - isPreferredEdgeless={isPreferredEdgeless} - blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace} - pageOperationsRenderer={pageOperationsRenderer} - /> - 0} - selectedIds={filteredSelectedPageIds} - onClose={hideFloatingToolbar} - /> - - ) : ( - } - blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace} - /> - )} + {content}
); @@ -329,6 +216,18 @@ export const Component = () => { const currentCollection = useSetAtom(currentCollectionAtom); const navigateHelper = useNavigateHelper(); + const location = useLocation(); + const activeFilter = useMemo(() => { + const query = new URLSearchParams(location.search); + const filterMode = query.get('filterMode'); + if (filterMode === 'collections') { + return 'collections'; + } else if (filterMode === 'tags') { + return 'tags'; + } + return 'docs'; + }, [location.search]); + useEffect(() => { function checkJumpOnce() { for (const [pageId] of currentWorkspace.blockSuiteWorkspace.pages) { @@ -355,5 +254,5 @@ export const Component = () => { currentCollection(NIL); }, [currentCollection]); - return ; + return ; }; diff --git a/packages/frontend/core/src/pages/workspace/collection.tsx b/packages/frontend/core/src/pages/workspace/collection.tsx index 446ea36edb..53c478a2db 100644 --- a/packages/frontend/core/src/pages/workspace/collection.tsx +++ b/packages/frontend/core/src/pages/workspace/collection.tsx @@ -10,6 +10,7 @@ import { useEditCollection, } from '@affine/core/components/page-list'; import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls'; +import { useAllPageListConfig } from '@affine/core/hooks/affine/use-all-page-list-config'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace'; import type { Collection } from '@affine/env/filter'; @@ -31,7 +32,6 @@ import { collectionsCRUDAtom, pageCollectionBaseAtom, } from '../../atoms/collections'; -import { useAllPageListConfig } from '../../hooks/affine/use-all-page-list-config'; import { useNavigateHelper } from '../../hooks/use-navigate-helper'; import { WorkspaceSubPath } from '../../shared'; import { getWorkspaceSetting } from '../../utils/workspace-setting'; @@ -89,17 +89,24 @@ export const Component = function CollectionPage() { return null; } return isEmpty(collection) ? ( - + ) : ( - + ); }; const isWindowsDesktop = environment.isDesktop && environment.isWindows; -const Placeholder = ({ collection }: { collection: Collection }) => { +const Placeholder = ({ + collection, + workspaceId, +}: { + collection: Collection; + workspaceId: string; +}) => { const { updateCollection } = useCollectionManager(collectionsCRUDAtom); const { node, open } = useEditCollection(useAllPageListConfig()); + const { jumpToCollections } = useNavigateHelper(); const openPageEdit = useAsyncCallback(async () => { const ret = await open({ ...collection }, 'page'); updateCollection(ret); @@ -118,6 +125,11 @@ const Placeholder = ({ collection }: { collection: Collection }) => { }, []); const t = useAFFiNEI18N(); const leftSidebarOpen = useAtomValue(appSidebarOpenAtom); + + const handleJumpToCollections = useCallback(() => { + jumpToCollections(workspaceId); + }, [jumpToCollections, workspaceId]); + return (
{ display: 'flex', alignItems: 'center', gap: 4, + cursor: 'pointer', color: 'var(--affine-text-secondary-color)', ['WebkitAppRegion' as string]: 'no-drag', }} + onClick={handleJumpToCollections} > ); }; + +export const EmptyCollectionList = ({ heading }: { heading: ReactNode }) => { + const t = useAFFiNEI18N(); + return ( +
+ {heading &&
{heading}
} + +
+ ); +}; +export const EmptyTagList = ({ heading }: { heading: ReactNode }) => { + const t = useAFFiNEI18N(); + return ( +
+ {heading &&
{heading}
} + +
+ ); +}; diff --git a/packages/frontend/core/src/pages/workspace/tag.tsx b/packages/frontend/core/src/pages/workspace/tag.tsx new file mode 100644 index 0000000000..9cc95d5aa9 --- /dev/null +++ b/packages/frontend/core/src/pages/workspace/tag.tsx @@ -0,0 +1,52 @@ +import { TagListHeader, useTagMetas } from '@affine/core/components/page-list'; +import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta'; +import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace'; +import { useAtomValue } from 'jotai'; +import { useMemo } from 'react'; +import { type LoaderFunction, redirect, useParams } from 'react-router-dom'; + +import { AllPage } from './all-page/all-page'; +import { AllPageHeader } from './all-page/all-page-header'; +import { EmptyPageList } from './page-list-empty'; + +export const loader: LoaderFunction = async args => { + if (!args.params.tagId) { + return redirect('/404'); + } + + return null; +}; + +export const Component = function TagPage() { + const params = useParams(); + const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom); + const pageMetas = useBlockSuitePageMeta(currentWorkspace.blockSuiteWorkspace); + const { tagUsageCounts } = useTagMetas( + currentWorkspace.blockSuiteWorkspace, + pageMetas + ); + const isEmpty = useMemo(() => { + if (params.tagId) { + return tagUsageCounts[params.tagId] === 0; + } + return true; + }, [params.tagId, tagUsageCounts]); + + return isEmpty ? ( + <> + + } + /> + + ) : ( + + ); +}; diff --git a/packages/frontend/core/src/pages/workspace/trash-page.tsx b/packages/frontend/core/src/pages/workspace/trash-page.tsx index d5b4540c53..d7e07a77b7 100644 --- a/packages/frontend/core/src/pages/workspace/trash-page.tsx +++ b/packages/frontend/core/src/pages/workspace/trash-page.tsx @@ -1,9 +1,18 @@ import { toast } from '@affine/component'; +import { usePageHelper } from '@affine/core/components/blocksuite/block-suite-page-list/utils'; import { currentCollectionAtom, + type ListItem, + ListTableHeader, + PageListItemRenderer, TrashOperationCell, - VirtualizedPageList, + useFilteredPageMetas, + VirtualizedList, } from '@affine/core/components/page-list'; +import { pageHeaderColsDef } from '@affine/core/components/page-list/header-col-def'; +import { Header } from '@affine/core/components/pure/header'; +import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls'; +import { useBlockSuiteMetaHelper } from '@affine/core/hooks/affine/use-block-suite-meta-helper'; import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta'; import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; @@ -16,12 +25,7 @@ import { useCallback } from 'react'; import { type LoaderFunction } from 'react-router-dom'; import { NIL } from 'uuid'; -import { usePageHelper } from '../../components/blocksuite/block-suite-page-list/utils'; -import { Header } from '../../components/pure/header'; -import { WindowsAppControls } from '../../components/pure/header/windows-app-controls'; -import { useBlockSuiteMetaHelper } from '../../hooks/affine/use-block-suite-meta-helper'; import { EmptyPageList } from './page-list-empty'; -import { useFilteredPageMetas } from './pages'; import * as styles from './trash-page.css'; const isWindowsDesktop = environment.isDesktop && environment.isWindows; @@ -74,7 +78,8 @@ export const TrashPage = () => { const t = useAFFiNEI18N(); const pageOperationsRenderer = useCallback( - (page: PageMeta) => { + (item: ListItem) => { + const page = item as PageMeta; const onRestorePage = () => { restoreFromTrash(page.id); toast( @@ -94,20 +99,28 @@ export const TrashPage = () => { /> ); }, + [permanentlyDeletePage, restoreFromTrash, t] ); - + const pageItemRenderer = useCallback((item: ListItem) => { + return ; + }, []); + const pageHeaderRenderer = useCallback(() => { + return ; + }, []); return (
{filteredPageMetas.length > 0 ? ( - ) : ( import('./pages/workspace/collection'), }, + { + path: 'tag/:tagId', + lazy: () => import('./pages/workspace/tag'), + }, { path: 'trash', lazy: () => import('./pages/workspace/trash-page'), diff --git a/packages/frontend/electron/package.json b/packages/frontend/electron/package.json index ed40b6b48e..48a2697cd6 100644 --- a/packages/frontend/electron/package.json +++ b/packages/frontend/electron/package.json @@ -25,10 +25,10 @@ "@affine-test/kit": "workspace:*", "@affine/env": "workspace:*", "@affine/native": "workspace:*", - "@blocksuite/blocks": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/lit": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/presets": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/store": "0.12.0-nightly-202401240410-02f373e", + "@blocksuite/blocks": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/lit": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/presets": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/store": "0.12.0-nightly-202401290223-b6302df", "@electron-forge/cli": "^7.2.0", "@electron-forge/core": "^7.2.0", "@electron-forge/core-utils": "^7.2.0", diff --git a/packages/frontend/graphql/src/graphql/index.ts b/packages/frontend/graphql/src/graphql/index.ts index 59c0a5ac24..f8b7a049cd 100644 --- a/packages/frontend/graphql/src/graphql/index.ts +++ b/packages/frontend/graphql/src/graphql/index.ts @@ -905,10 +905,19 @@ export const workspaceQuotaQuery = { query workspaceQuota($id: String!) { workspace(id: $id) { quota { - humanReadableName - storageQuota - usedSize + name blobLimit + storageQuota + historyPeriod + memberLimit + humanReadable { + name + blobLimit + storageQuota + historyPeriod + memberLimit + } + usedSize } } }`, diff --git a/packages/frontend/graphql/src/graphql/workspace-quota.gql b/packages/frontend/graphql/src/graphql/workspace-quota.gql index 7b9cc193e1..5ce5e63195 100644 --- a/packages/frontend/graphql/src/graphql/workspace-quota.gql +++ b/packages/frontend/graphql/src/graphql/workspace-quota.gql @@ -1,10 +1,19 @@ query workspaceQuota($id: String!) { workspace(id: $id) { quota { - humanReadableName - storageQuota - usedSize + name blobLimit + storageQuota + historyPeriod + memberLimit + humanReadable { + name + blobLimit + storageQuota + historyPeriod + memberLimit + } + usedSize } } } diff --git a/packages/frontend/graphql/src/schema.ts b/packages/frontend/graphql/src/schema.ts index af7a63be6e..4dd041c7b3 100644 --- a/packages/frontend/graphql/src/schema.ts +++ b/packages/frontend/graphql/src/schema.ts @@ -854,10 +854,20 @@ export type WorkspaceQuotaQuery = { __typename?: 'WorkspaceType'; quota: { __typename?: 'QuotaQueryType'; - humanReadableName: string; - storageQuota: number; - usedSize: number; + name: string; blobLimit: number; + storageQuota: number; + historyPeriod: number; + memberLimit: number; + usedSize: number; + humanReadable: { + __typename?: 'HumanReadableQuotaType'; + name: string; + blobLimit: string; + storageQuota: string; + historyPeriod: string; + memberLimit: string; + }; }; }; }; diff --git a/packages/frontend/i18n/src/resources/en.json b/packages/frontend/i18n/src/resources/en.json index 1c3884f49c..bc317d99d2 100644 --- a/packages/frontend/i18n/src/resources/en.json +++ b/packages/frontend/i18n/src/resources/en.json @@ -554,9 +554,10 @@ "com.affine.collection.menu.edit": "Edit Collection", "com.affine.collection.menu.rename": "Rename", "com.affine.collectionBar.backToAll": "Back to all", + "com.affine.docs.header": "Docs", "com.affine.collections.header": "Collections", "com.affine.collections.empty.message": "No collections", - "com.affine.collections.empty.new-collection-button": "New collection", + "com.affine.collections.empty.new-collection-button": "New Collection", "com.affine.confirmModal.button.cancel": "Cancel", "com.affine.currentYear": "Current Year", "com.affine.deleteLeaveWorkspace.description": "Delete workspace from this device and optionally delete all data.", @@ -601,6 +602,8 @@ "com.affine.editCollectionName.name.placeholder": "Collection Name", "com.affine.editorModeSwitch.tooltip": "Switch", "com.affine.emptyDesc": "There's no page here yet", + "com.affine.emptyDesc.collection": "There's no collection here yet", + "com.affine.emptyDesc.tag": "There's no tag here yet", "com.affine.enableAffineCloudModal.button.cancel": "Cancel", "com.affine.expired.page.subtitle": "Please request a new reset password link.", "com.affine.expired.page.title": "This link has expired...", @@ -714,6 +717,12 @@ "com.affine.page.toolbar.selected": "<0>{{count}} selected", "com.affine.page.toolbar.selected_one": "<0>{{count}} page selected", "com.affine.page.toolbar.selected_others": "<0>{{count}} page(s) selected", + "com.affine.collection.toolbar.selected": "<0>{{count}} selected", + "com.affine.collection.toolbar.selected_one": "<0>{{count}} collection selected", + "com.affine.collection.toolbar.selected_others": "<0>{{count}} collection(s) selected", + "com.affine.tag.toolbar.selected": "<0>{{count}} selected", + "com.affine.tag.toolbar.selected_one": "<0>{{count}} tag selected", + "com.affine.tag.toolbar.selected_others": "<0>{{count}} tag(s) selected", "com.affine.pageMode": "Page Mode", "com.affine.pageMode.all": "all", "com.affine.pageMode.edgeless": "Edgeless", diff --git a/packages/frontend/templates/build.mjs b/packages/frontend/templates/build.mjs index 26769eff55..5659277ed3 100644 --- a/packages/frontend/templates/build.mjs +++ b/packages/frontend/templates/build.mjs @@ -1,31 +1,32 @@ import fs from 'node:fs'; -import path from 'node:path'; +import path, { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; import * as glob from 'glob'; // purpose: bundle all json files into one json file in onboarding folder -const __dirname = new URL('.', import.meta.url).pathname; +const __dirname = join(fileURLToPath(import.meta.url), '..'); const jsonFiles = glob.sync('./*.json', { - cwd: path.resolve(__dirname, 'onboarding'), + cwd: path.join(__dirname, 'onboarding'), }); const imports = jsonFiles - .map((fileName, index) => { - return `import json_${index} from './onboarding/${fileName}';`; - }) + .map( + (fileName, index) => `import json_${index} from './onboarding/${fileName}';` + ) .join('\n'); const exports = `export const onboarding = { - ${jsonFiles - .map((fileName, index) => { - return `'${fileName}': json_${index}`; - }) - .join(',\n')} +${jsonFiles + .map((fileName, index) => { + return ` '${fileName}': json_${index}`; + }) + .join(',\n')} }`; const template = `/* eslint-disable simple-import-sort/imports */ // Auto generated, do not edit manually ${imports}\n\n${exports}`; -fs.writeFileSync(path.resolve(__dirname, 'templates.gen.ts'), template); +fs.writeFileSync(path.join(__dirname, 'templates.gen.ts'), template); diff --git a/packages/frontend/templates/templates.gen.ts b/packages/frontend/templates/templates.gen.ts index 7188531ffb..aaf6e85bcb 100644 --- a/packages/frontend/templates/templates.gen.ts +++ b/packages/frontend/templates/templates.gen.ts @@ -1,29 +1,29 @@ /* eslint-disable simple-import-sort/imports */ // Auto generated, do not edit manually import json_0 from './onboarding/wbXL4bZcblxLKC6ETqcQ1.snapshot.json'; -import json_1 from './onboarding/rzyBHDgN5KIlEYzB9oBaD.snapshot.json'; -import json_2 from './onboarding/nPPyOV0JBNKu5hvW9hE00.snapshot.json'; -import json_3 from './onboarding/info.json'; -import json_4 from './onboarding/e5cYLNpIRUb-nwpSZGdix.snapshot.json'; -import json_5 from './onboarding/b1F2xKjgZ4ISHhXNe1kck.snapshot.json'; -import json_6 from './onboarding/Scod6coKmJJ-waH1-jkiW.snapshot.json'; -import json_7 from './onboarding/RCpxnWMtBWmUZy5awgJBh.snapshot.json'; -import json_8 from './onboarding/GWsRbUtMF4Ee6foVg-H9R.snapshot.json'; +import json_1 from './onboarding/Scod6coKmJJ-waH1-jkiW.snapshot.json'; +import json_2 from './onboarding/rzyBHDgN5KIlEYzB9oBaD.snapshot.json'; +import json_3 from './onboarding/RCpxnWMtBWmUZy5awgJBh.snapshot.json'; +import json_4 from './onboarding/nPPyOV0JBNKu5hvW9hE00.snapshot.json'; +import json_5 from './onboarding/info.json'; +import json_6 from './onboarding/GWsRbUtMF4Ee6foVg-H9R.snapshot.json'; +import json_7 from './onboarding/e5cYLNpIRUb-nwpSZGdix.snapshot.json'; +import json_8 from './onboarding/b1F2xKjgZ4ISHhXNe1kck.snapshot.json'; import json_9 from './onboarding/9iIScyvuIB_kUKbs1AYOQ.snapshot.json'; import json_10 from './onboarding/0nee_XzkrN23Xy7HMoXL-.snapshot.json'; import json_11 from './onboarding/-P-O4GSfVGTkI16zJRVa4.snapshot.json'; export const onboarding = { 'wbXL4bZcblxLKC6ETqcQ1.snapshot.json': json_0, -'rzyBHDgN5KIlEYzB9oBaD.snapshot.json': json_1, -'nPPyOV0JBNKu5hvW9hE00.snapshot.json': json_2, -'info.json': json_3, -'e5cYLNpIRUb-nwpSZGdix.snapshot.json': json_4, -'b1F2xKjgZ4ISHhXNe1kck.snapshot.json': json_5, -'Scod6coKmJJ-waH1-jkiW.snapshot.json': json_6, -'RCpxnWMtBWmUZy5awgJBh.snapshot.json': json_7, -'GWsRbUtMF4Ee6foVg-H9R.snapshot.json': json_8, -'9iIScyvuIB_kUKbs1AYOQ.snapshot.json': json_9, -'0nee_XzkrN23Xy7HMoXL-.snapshot.json': json_10, -'-P-O4GSfVGTkI16zJRVa4.snapshot.json': json_11 + 'Scod6coKmJJ-waH1-jkiW.snapshot.json': json_1, + 'rzyBHDgN5KIlEYzB9oBaD.snapshot.json': json_2, + 'RCpxnWMtBWmUZy5awgJBh.snapshot.json': json_3, + 'nPPyOV0JBNKu5hvW9hE00.snapshot.json': json_4, + 'info.json': json_5, + 'GWsRbUtMF4Ee6foVg-H9R.snapshot.json': json_6, + 'e5cYLNpIRUb-nwpSZGdix.snapshot.json': json_7, + 'b1F2xKjgZ4ISHhXNe1kck.snapshot.json': json_8, + '9iIScyvuIB_kUKbs1AYOQ.snapshot.json': json_9, + '0nee_XzkrN23Xy7HMoXL-.snapshot.json': json_10, + '-P-O4GSfVGTkI16zJRVa4.snapshot.json': json_11 } \ No newline at end of file diff --git a/scripts/bump-blocksuite.sh b/scripts/bump-blocksuite.sh index 4ecc8ead63..229af65b59 100755 --- a/scripts/bump-blocksuite.sh +++ b/scripts/bump-blocksuite.sh @@ -3,10 +3,11 @@ LATEST_NIGHTLY=$(npm view @blocksuite/presets@nightly version | cut -d ':' -f 2 | tr -d '[:space:]') echo "Bump to latest BlockSuite nightly version: $LATEST_NIGHTLY" -yarn up "@blocksuite/store@${LATEST_NIGHTLY}" -yarn up "@blocksuite/blocks@${LATEST_NIGHTLY}" -yarn up "@blocksuite/presets@${LATEST_NIGHTLY}" -yarn up "@blocksuite/global@${LATEST_NIGHTLY}" -yarn up "@blocksuite/block-std@${LATEST_NIGHTLY}" -yarn up "@blocksuite/lit@${LATEST_NIGHTLY}" -yarn up "@blocksuite/inline@${LATEST_NIGHTLY}" +yarn up \ + "@blocksuite/store@${LATEST_NIGHTLY}" \ + "@blocksuite/blocks@${LATEST_NIGHTLY}" \ + "@blocksuite/presets@${LATEST_NIGHTLY}" \ + "@blocksuite/global@${LATEST_NIGHTLY}" \ + "@blocksuite/block-std@${LATEST_NIGHTLY}" \ + "@blocksuite/lit@${LATEST_NIGHTLY}" \ + "@blocksuite/inline@${LATEST_NIGHTLY}" diff --git a/tests/affine-legacy/0.6.1-beta.1/package.json b/tests/affine-legacy/0.6.1-beta.1/package.json index 0ab0f65c68..743a45791c 100644 --- a/tests/affine-legacy/0.6.1-beta.1/package.json +++ b/tests/affine-legacy/0.6.1-beta.1/package.json @@ -9,10 +9,6 @@ "devDependencies": { "@affine-test/fixtures": "workspace:*", "@affine-test/kit": "workspace:*", - "@blocksuite/block-std": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/blocks": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/global": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/store": "0.12.0-nightly-202401240410-02f373e", "@playwright/test": "^1.41.0", "express": "^4.18.2", "http-proxy-middleware": "^3.0.0-beta.1", diff --git a/tests/affine-legacy/0.7.0-canary.18/package.json b/tests/affine-legacy/0.7.0-canary.18/package.json index 11a128b785..e35a6d494a 100644 --- a/tests/affine-legacy/0.7.0-canary.18/package.json +++ b/tests/affine-legacy/0.7.0-canary.18/package.json @@ -9,10 +9,6 @@ "devDependencies": { "@affine-test/fixtures": "workspace:*", "@affine-test/kit": "workspace:*", - "@blocksuite/block-std": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/blocks": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/global": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/store": "0.12.0-nightly-202401240410-02f373e", "@playwright/test": "^1.41.0", "express": "^4.18.2", "http-proxy-middleware": "^3.0.0-beta.1", diff --git a/tests/affine-legacy/0.8.0-canary.7/package.json b/tests/affine-legacy/0.8.0-canary.7/package.json index 4f82bc78cc..e1d27a628c 100644 --- a/tests/affine-legacy/0.8.0-canary.7/package.json +++ b/tests/affine-legacy/0.8.0-canary.7/package.json @@ -9,10 +9,6 @@ "devDependencies": { "@affine-test/fixtures": "workspace:*", "@affine-test/kit": "workspace:*", - "@blocksuite/block-std": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/blocks": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/global": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/store": "0.12.0-nightly-202401240410-02f373e", "@playwright/test": "^1.41.0", "express": "^4.18.2", "http-proxy-middleware": "^3.0.0-beta.1", diff --git a/tests/affine-legacy/0.8.4/package.json b/tests/affine-legacy/0.8.4/package.json index 96ad038223..1e657a7e71 100644 --- a/tests/affine-legacy/0.8.4/package.json +++ b/tests/affine-legacy/0.8.4/package.json @@ -9,10 +9,6 @@ "devDependencies": { "@affine-test/fixtures": "workspace:*", "@affine-test/kit": "workspace:*", - "@blocksuite/block-std": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/blocks": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/global": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/store": "0.12.0-nightly-202401240410-02f373e", "@playwright/test": "^1.41.0", "express": "^4.18.2", "http-proxy-middleware": "^3.0.0-beta.1", diff --git a/tests/affine-local/e2e/all-page.spec.ts b/tests/affine-local/e2e/all-page.spec.ts index 898336f756..cdc6332ff8 100644 --- a/tests/affine-local/e2e/all-page.spec.ts +++ b/tests/affine-local/e2e/all-page.spec.ts @@ -212,7 +212,7 @@ test('select two pages and delete', async ({ page }) => { ); // click delete button - await page.locator('[data-testid="page-list-toolbar-delete"]').click(); + await page.locator('[data-testid="list-toolbar-delete"]').click(); // the confirm dialog should appear await expect(page.getByText('Delete 2 pages?')).toBeVisible(); diff --git a/tests/affine-local/e2e/local-first-collections-items.spec.ts b/tests/affine-local/e2e/local-first-collections-items.spec.ts index fe09cbdfe9..cfa091a507 100644 --- a/tests/affine-local/e2e/local-first-collections-items.spec.ts +++ b/tests/affine-local/e2e/local-first-collections-items.spec.ts @@ -18,7 +18,7 @@ const removeOnboardingPages = async (page: Page) => { await page.getByTestId('page-list-header-selection-checkbox').click(); // click again to select all await page.getByTestId('page-list-header-selection-checkbox').click(); - await page.getByTestId('page-list-toolbar-delete').click(); + await page.getByTestId('list-toolbar-delete').click(); // confirm delete await page.getByTestId('confirm-delete-page').click(); }; diff --git a/tests/affine-migration/package.json b/tests/affine-migration/package.json index 81ec254708..4315a207bf 100644 --- a/tests/affine-migration/package.json +++ b/tests/affine-migration/package.json @@ -7,10 +7,6 @@ "devDependencies": { "@affine-test/fixtures": "workspace:*", "@affine-test/kit": "workspace:*", - "@blocksuite/block-std": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/blocks": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/global": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/store": "0.12.0-nightly-202401240410-02f373e", "@playwright/test": "^1.41.0" }, "version": "0.12.0" diff --git a/tests/storybook/package.json b/tests/storybook/package.json index cd66c99786..4c4d88b9f5 100644 --- a/tests/storybook/package.json +++ b/tests/storybook/package.json @@ -9,6 +9,7 @@ "dependencies": { "@affine/component": "workspace:*", "@affine/i18n": "workspace:*", + "@affine/workspace-impl": "workspace:*", "@dnd-kit/sortable": "^8.0.0", "@storybook/jest": "^0.2.3", "@storybook/testing-library": "^0.2.2", @@ -21,14 +22,14 @@ "storybook-addon-react-router-v6": "^2.0.10" }, "devDependencies": { - "@blocksuite/block-std": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/blocks": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/global": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/icons": "2.1.42", - "@blocksuite/inline": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/lit": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/presets": "0.12.0-nightly-202401240410-02f373e", - "@blocksuite/store": "0.12.0-nightly-202401240410-02f373e", + "@blocksuite/block-std": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/blocks": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/global": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/icons": "2.1.44", + "@blocksuite/inline": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/lit": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/presets": "0.12.0-nightly-202401290223-b6302df", + "@blocksuite/store": "0.12.0-nightly-202401290223-b6302df", "@storybook/addon-actions": "^7.5.3", "@storybook/addon-essentials": "^7.5.3", "@storybook/addon-interactions": "^7.5.3", diff --git a/tests/storybook/src/stories/page-list.stories.tsx b/tests/storybook/src/stories/page-list.stories.tsx index 26c99d6478..f232bcad0b 100644 --- a/tests/storybook/src/stories/page-list.stories.tsx +++ b/tests/storybook/src/stories/page-list.stories.tsx @@ -1,14 +1,15 @@ import { toast } from '@affine/component'; import { FloatingToolbar, + List, + type ListItem, + type ListProps, + ListScrollContainer, NewPageButton, - OperationCell, - type OperationCellProps, - PageList, PageListItem, type PageListItemProps, - type PageListProps, - PageListScrollContainer, + PageOperationCell, + type PageOperationCellProps, PageTags, type PageTagsProps, } from '@affine/core/components/page-list'; @@ -29,9 +30,9 @@ export default { }, } satisfies Meta; -export const AffineOperationCell: StoryFn = ({ +export const AffineOperationCell: StoryFn = ({ ...props -}) => ; +}) => ; AffineOperationCell.args = { favorite: false, @@ -159,11 +160,11 @@ const testTags = [ }, ]; -export const ListItem: StoryFn = props => ( +export const PageListItemComponent: StoryFn = props => ( ); -ListItem.args = { +PageListItemComponent.args = { pageId: 'test-page-id', title: 'Test Page Title', preview: @@ -178,7 +179,7 @@ ListItem.args = { selected: true, }; -ListItem.decorators = [withRouter]; +PageListItemComponent.decorators = [withRouter]; export const ListItemTags: StoryFn = props => (
@@ -195,15 +196,18 @@ ListItemTags.args = { maxItems: 5, }; -export const PageListStory: StoryFn = (props, { loaded }) => { +export const PageListStory: StoryFn> = ( + props, + { loaded } +) => { return ( - - - + + ); }; diff --git a/tools/bump-blocksuite/index.js b/tools/bump-blocksuite/index.js new file mode 100644 index 0000000000..23b41c1595 --- /dev/null +++ b/tools/bump-blocksuite/index.js @@ -0,0 +1,146 @@ +import { execSync } from 'node:child_process'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { Clipboard } from '@napi-rs/clipboard'; +import { Repository, Sort } from '@napi-rs/simple-git'; + +import corePackage from '../../packages/frontend/core/package.json' assert { type: 'json' }; + +const clipboard = new Clipboard(); + +const oldHash = corePackage.dependencies['@blocksuite/block-std'] + .split('-') + .pop(); + +const info = await fetch( + 'https://registry.npmjs.org/@blocksuite/block-std' +).then(res => res.json()); + +const latestVersion = info['dist-tags'].nightly; +const latestHash = latestVersion.split('-').pop(); + +console.info(`Upgrade blocksuite from ${oldHash} -> ${latestHash}`); + +const blockSuiteDeps = execSync(`yarn info -A --name-only --json`, { + encoding: 'utf8', +}); + +const blocksuiteDepsList = blockSuiteDeps + .split('\n') + .map(s => s.trim()) + .filter(Boolean) + .map(s => s.substring(1, s.length - 1)) + .filter( + s => s.startsWith('@blocksuite') && !s.startsWith('@blocksuite/icons') + ) + .map(s => s.split('@npm').at(0)); + +for (const pkg of blocksuiteDepsList) { + const command = `yarn up ${pkg}@${latestVersion}`; + console.info(`Executing ${command}`); + execSync(command, { + stdio: 'inherit', + }); +} + +console.info(`Upgrade complete`); + +const repo = new Repository( + join(fileURLToPath(import.meta.url), '..', '..', '..', '..', 'BlockSuite') +); + +repo.remote('origin').fetch(['master'], progress => { + if (progress.totalDeltas && progress.totalObjects) { + console.log( + `${( + (progress.receivedObjects / progress.totalObjects) * 50 + + (progress.indexedDeltas / progress.totalDeltas) * 50 + ).toFixed(2)}%` + ); + } +}); + +const latest = repo.findCommit(latestHash); + +const commits = { + Features: [], + Bugfix: [], + Refactor: [], + Misc: [], +}; + +for (const oid of repo + .revWalk() + .push(latest.id()) + .setSorting(Sort.Time & Sort.Topological)) { + const commit = repo.findCommit(oid); + const summary = commit.summary(); + if (summary.startsWith('feat')) { + commits.Features.push(commit); + } else if (summary.startsWith('fix')) { + commits.Bugfix.push(commit); + } else if (summary.startsWith('refactor')) { + commits.Refactor.push(commit); + } else { + commits.Misc.push(commit); + } + if (oid.startsWith(oldHash)) { + break; + } +} + +clipboard.setText(await formatCommits(commits)); + +console.info(`Changelog copied to clipboard`); + +async function formatCommits(commits) { + return `## Features +${await Promise.all(commits.Features.map(format)).then(commits => + commits.join('\n') +)} + +## Bugfix +${await Promise.all(commits.Bugfix.map(format)).then(commits => + commits.join('\n') +)} + +## Refactor +${await Promise.all(commits.Refactor.map(format)).then(commits => + commits.join('\n') +)} + +## Misc +${await Promise.all(commits.Misc.map(format)).then(commits => + commits.join('\n') +)} +`; + /** + * @param {import('./index').Commit} commit + * @returns string + */ + async function format(commit) { + const summary = commit.summary(); + const match = summary.match(/\(#(\d+)\)/); + if (match) { + const [_, pull] = match; + const pullInfo = await fetch( + `https://api.github.com/repos/toeverything/BlockSuite/pulls/${pull}`, + { + headers: { + Accept: 'application/vnd.github+json', + Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, + 'X-GitHub-Api-Version': '2022-11-28', + }, + } + ) + .then(res => res.json()) + .catch(() => ({ user: {} })); + const { + user: { login }, + } = pullInfo; + return `- https://github.com/toeverything/BlockSuite/pull/${pull} @${login}`; + } + return `- ${summary}`; + } +} diff --git a/tools/bump-blocksuite/package.json b/tools/bump-blocksuite/package.json new file mode 100644 index 0000000000..72a09e5f3d --- /dev/null +++ b/tools/bump-blocksuite/package.json @@ -0,0 +1,12 @@ +{ + "name": "@affine/bump-blocksuite", + "version": "0.0.0", + "type": "module", + "main": "index.js", + "private": true, + "description": "Generate changelog from blocksuite version change", + "dependencies": { + "@napi-rs/clipboard": "^1.1.1", + "@napi-rs/simple-git": "^0.1.11" + } +} diff --git a/yarn.lock b/yarn.lock index 2a6ce1e818..0f456c132d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25,10 +25,6 @@ __metadata: dependencies: "@affine-test/fixtures": "workspace:*" "@affine-test/kit": "workspace:*" - "@blocksuite/block-std": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/blocks": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" "@playwright/test": "npm:^1.41.0" express: "npm:^4.18.2" http-proxy-middleware: "npm:^3.0.0-beta.1" @@ -42,10 +38,6 @@ __metadata: dependencies: "@affine-test/fixtures": "workspace:*" "@affine-test/kit": "workspace:*" - "@blocksuite/block-std": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/blocks": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" "@playwright/test": "npm:^1.41.0" express: "npm:^4.18.2" http-proxy-middleware: "npm:^3.0.0-beta.1" @@ -59,10 +51,6 @@ __metadata: dependencies: "@affine-test/fixtures": "workspace:*" "@affine-test/kit": "workspace:*" - "@blocksuite/block-std": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/blocks": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" "@playwright/test": "npm:^1.41.0" express: "npm:^4.18.2" http-proxy-middleware: "npm:^3.0.0-beta.1" @@ -76,10 +64,6 @@ __metadata: dependencies: "@affine-test/fixtures": "workspace:*" "@affine-test/kit": "workspace:*" - "@blocksuite/block-std": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/blocks": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" "@playwright/test": "npm:^1.41.0" express: "npm:^4.18.2" http-proxy-middleware: "npm:^3.0.0-beta.1" @@ -139,10 +123,6 @@ __metadata: dependencies: "@affine-test/fixtures": "workspace:*" "@affine-test/kit": "workspace:*" - "@blocksuite/block-std": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/blocks": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" "@playwright/test": "npm:^1.41.0" languageName: unknown linkType: soft @@ -169,6 +149,15 @@ __metadata: languageName: unknown linkType: soft +"@affine/bump-blocksuite@workspace:tools/bump-blocksuite": + version: 0.0.0-use.local + resolution: "@affine/bump-blocksuite@workspace:tools/bump-blocksuite" + dependencies: + "@napi-rs/clipboard": "npm:^1.1.1" + "@napi-rs/simple-git": "npm:^0.1.11" + languageName: unknown + linkType: soft + "@affine/cli@workspace:*, @affine/cli@workspace:tools/cli": version: 0.0.0-use.local resolution: "@affine/cli@workspace:tools/cli" @@ -206,12 +195,12 @@ __metadata: "@affine/graphql": "workspace:*" "@affine/i18n": "workspace:*" "@affine/workspace": "workspace:*" - "@blocksuite/blocks": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/icons": "npm:2.1.42" - "@blocksuite/lit": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/presets": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" + "@blocksuite/blocks": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/global": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/icons": "npm:2.1.44" + "@blocksuite/lit": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/presets": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/store": "npm:0.12.0-nightly-202401290223-b6302df" "@dnd-kit/core": "npm:^6.0.8" "@dnd-kit/modifiers": "npm:^7.0.0" "@dnd-kit/sortable": "npm:^8.0.0" @@ -308,15 +297,15 @@ __metadata: "@affine/templates": "workspace:*" "@affine/workspace": "workspace:*" "@affine/workspace-impl": "workspace:*" - "@aws-sdk/client-s3": "npm:3.485.0" - "@blocksuite/block-std": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/blocks": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/icons": "npm:2.1.42" - "@blocksuite/inline": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/lit": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/presets": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" + "@aws-sdk/client-s3": "npm:3.499.0" + "@blocksuite/block-std": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/blocks": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/global": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/icons": "npm:2.1.44" + "@blocksuite/inline": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/lit": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/presets": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/store": "npm:0.12.0-nightly-202401290223-b6302df" "@dnd-kit/core": "npm:^6.0.8" "@dnd-kit/sortable": "npm:^8.0.0" "@emotion/cache": "npm:^11.11.0" @@ -443,10 +432,10 @@ __metadata: "@affine-test/kit": "workspace:*" "@affine/env": "workspace:*" "@affine/native": "workspace:*" - "@blocksuite/blocks": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/lit": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/presets": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" + "@blocksuite/blocks": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/lit": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/presets": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/store": "npm:0.12.0-nightly-202401290223-b6302df" "@electron-forge/cli": "npm:^7.2.0" "@electron-forge/core": "npm:^7.2.0" "@electron-forge/core-utils": "npm:^7.2.0" @@ -495,8 +484,8 @@ __metadata: version: 0.0.0-use.local resolution: "@affine/env@workspace:packages/common/env" dependencies: - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" + "@blocksuite/global": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/store": "npm:0.12.0-nightly-202401290223-b6302df" lit: "npm:^3.0.2" react: "npm:18.2.0" react-dom: "npm:18.2.0" @@ -579,7 +568,7 @@ __metadata: eslint-plugin-vue: "npm:^9.18.1" fake-indexeddb: "npm:5.0.2" happy-dom: "npm:^13.0.0" - husky: "npm:^8.0.3" + husky: "npm:^9.0.6" lint-staged: "npm:^15.1.0" msw: "npm:^2.0.8" nanoid: "npm:^5.0.3" @@ -628,7 +617,7 @@ __metadata: "@affine/storage": "workspace:*" "@apollo/server": "npm:^4.9.5" "@auth/prisma-adapter": "npm:^1.0.7" - "@aws-sdk/client-s3": "npm:^3.454.0" + "@aws-sdk/client-s3": "npm:^3.499.0" "@google-cloud/opentelemetry-cloud-monitoring-exporter": "npm:^0.17.0" "@google-cloud/opentelemetry-cloud-trace-exporter": "npm:^2.1.0" "@google-cloud/opentelemetry-resource-util": "npm:^2.1.0" @@ -742,14 +731,15 @@ __metadata: dependencies: "@affine/component": "workspace:*" "@affine/i18n": "workspace:*" - "@blocksuite/block-std": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/blocks": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/icons": "npm:2.1.42" - "@blocksuite/inline": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/lit": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/presets": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" + "@affine/workspace-impl": "workspace:*" + "@blocksuite/block-std": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/blocks": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/global": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/icons": "npm:2.1.44" + "@blocksuite/inline": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/lit": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/presets": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/store": "npm:0.12.0-nightly-202401290223-b6302df" "@dnd-kit/sortable": "npm:^8.0.0" "@storybook/addon-actions": "npm:^7.5.3" "@storybook/addon-essentials": "npm:^7.5.3" @@ -1255,512 +1245,514 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/client-s3@npm:3.485.0, @aws-sdk/client-s3@npm:^3.454.0": - version: 3.485.0 - resolution: "@aws-sdk/client-s3@npm:3.485.0" +"@aws-sdk/client-s3@npm:3.499.0, @aws-sdk/client-s3@npm:^3.499.0": + version: 3.499.0 + resolution: "@aws-sdk/client-s3@npm:3.499.0" dependencies: "@aws-crypto/sha1-browser": "npm:3.0.0" "@aws-crypto/sha256-browser": "npm:3.0.0" "@aws-crypto/sha256-js": "npm:3.0.0" - "@aws-sdk/client-sts": "npm:3.485.0" - "@aws-sdk/core": "npm:3.485.0" - "@aws-sdk/credential-provider-node": "npm:3.485.0" - "@aws-sdk/middleware-bucket-endpoint": "npm:3.485.0" - "@aws-sdk/middleware-expect-continue": "npm:3.485.0" - "@aws-sdk/middleware-flexible-checksums": "npm:3.485.0" - "@aws-sdk/middleware-host-header": "npm:3.485.0" - "@aws-sdk/middleware-location-constraint": "npm:3.485.0" - "@aws-sdk/middleware-logger": "npm:3.485.0" - "@aws-sdk/middleware-recursion-detection": "npm:3.485.0" - "@aws-sdk/middleware-sdk-s3": "npm:3.485.0" - "@aws-sdk/middleware-signing": "npm:3.485.0" - "@aws-sdk/middleware-ssec": "npm:3.485.0" - "@aws-sdk/middleware-user-agent": "npm:3.485.0" - "@aws-sdk/region-config-resolver": "npm:3.485.0" - "@aws-sdk/signature-v4-multi-region": "npm:3.485.0" - "@aws-sdk/types": "npm:3.485.0" - "@aws-sdk/util-endpoints": "npm:3.485.0" - "@aws-sdk/util-user-agent-browser": "npm:3.485.0" - "@aws-sdk/util-user-agent-node": "npm:3.485.0" - "@aws-sdk/xml-builder": "npm:3.485.0" - "@smithy/config-resolver": "npm:^2.0.23" - "@smithy/core": "npm:^1.2.2" - "@smithy/eventstream-serde-browser": "npm:^2.0.16" - "@smithy/eventstream-serde-config-resolver": "npm:^2.0.16" - "@smithy/eventstream-serde-node": "npm:^2.0.16" - "@smithy/fetch-http-handler": "npm:^2.3.2" - "@smithy/hash-blob-browser": "npm:^2.0.17" - "@smithy/hash-node": "npm:^2.0.18" - "@smithy/hash-stream-node": "npm:^2.0.18" - "@smithy/invalid-dependency": "npm:^2.0.16" - "@smithy/md5-js": "npm:^2.0.18" - "@smithy/middleware-content-length": "npm:^2.0.18" - "@smithy/middleware-endpoint": "npm:^2.3.0" - "@smithy/middleware-retry": "npm:^2.0.26" - "@smithy/middleware-serde": "npm:^2.0.16" - "@smithy/middleware-stack": "npm:^2.0.10" - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/node-http-handler": "npm:^2.2.2" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/smithy-client": "npm:^2.2.1" - "@smithy/types": "npm:^2.8.0" - "@smithy/url-parser": "npm:^2.0.16" - "@smithy/util-base64": "npm:^2.0.1" - "@smithy/util-body-length-browser": "npm:^2.0.1" - "@smithy/util-body-length-node": "npm:^2.1.0" - "@smithy/util-defaults-mode-browser": "npm:^2.0.24" - "@smithy/util-defaults-mode-node": "npm:^2.0.32" - "@smithy/util-endpoints": "npm:^1.0.8" - "@smithy/util-retry": "npm:^2.0.9" - "@smithy/util-stream": "npm:^2.0.24" - "@smithy/util-utf8": "npm:^2.0.2" - "@smithy/util-waiter": "npm:^2.0.16" + "@aws-sdk/client-sts": "npm:3.499.0" + "@aws-sdk/core": "npm:3.496.0" + "@aws-sdk/credential-provider-node": "npm:3.499.0" + "@aws-sdk/middleware-bucket-endpoint": "npm:3.496.0" + "@aws-sdk/middleware-expect-continue": "npm:3.496.0" + "@aws-sdk/middleware-flexible-checksums": "npm:3.496.0" + "@aws-sdk/middleware-host-header": "npm:3.496.0" + "@aws-sdk/middleware-location-constraint": "npm:3.496.0" + "@aws-sdk/middleware-logger": "npm:3.496.0" + "@aws-sdk/middleware-recursion-detection": "npm:3.496.0" + "@aws-sdk/middleware-sdk-s3": "npm:3.499.0" + "@aws-sdk/middleware-signing": "npm:3.496.0" + "@aws-sdk/middleware-ssec": "npm:3.498.0" + "@aws-sdk/middleware-user-agent": "npm:3.496.0" + "@aws-sdk/region-config-resolver": "npm:3.496.0" + "@aws-sdk/signature-v4-multi-region": "npm:3.499.0" + "@aws-sdk/types": "npm:3.496.0" + "@aws-sdk/util-endpoints": "npm:3.496.0" + "@aws-sdk/util-user-agent-browser": "npm:3.496.0" + "@aws-sdk/util-user-agent-node": "npm:3.496.0" + "@aws-sdk/xml-builder": "npm:3.496.0" + "@smithy/config-resolver": "npm:^2.1.1" + "@smithy/core": "npm:^1.3.1" + "@smithy/eventstream-serde-browser": "npm:^2.1.1" + "@smithy/eventstream-serde-config-resolver": "npm:^2.1.1" + "@smithy/eventstream-serde-node": "npm:^2.1.1" + "@smithy/fetch-http-handler": "npm:^2.4.1" + "@smithy/hash-blob-browser": "npm:^2.1.1" + "@smithy/hash-node": "npm:^2.1.1" + "@smithy/hash-stream-node": "npm:^2.1.1" + "@smithy/invalid-dependency": "npm:^2.1.1" + "@smithy/md5-js": "npm:^2.1.1" + "@smithy/middleware-content-length": "npm:^2.1.1" + "@smithy/middleware-endpoint": "npm:^2.4.1" + "@smithy/middleware-retry": "npm:^2.1.1" + "@smithy/middleware-serde": "npm:^2.1.1" + "@smithy/middleware-stack": "npm:^2.1.1" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/node-http-handler": "npm:^2.3.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/smithy-client": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/url-parser": "npm:^2.1.1" + "@smithy/util-base64": "npm:^2.1.1" + "@smithy/util-body-length-browser": "npm:^2.1.1" + "@smithy/util-body-length-node": "npm:^2.2.1" + "@smithy/util-defaults-mode-browser": "npm:^2.1.1" + "@smithy/util-defaults-mode-node": "npm:^2.1.1" + "@smithy/util-endpoints": "npm:^1.1.1" + "@smithy/util-retry": "npm:^2.1.1" + "@smithy/util-stream": "npm:^2.1.1" + "@smithy/util-utf8": "npm:^2.1.1" + "@smithy/util-waiter": "npm:^2.1.1" fast-xml-parser: "npm:4.2.5" tslib: "npm:^2.5.0" - checksum: 9ce365c960e11480fa9e3141468815166a6fe123faca480dd23aba0d423684d18ae0a7e479099997a534932f4c636dbb36344f53de5edfb70f2f81eaf2a757e8 + checksum: cb66c6f96bf97873fdb87b95fe2978b0d3db45be7ebc34916555c45e55dd114f6a00daad1fa7c84f5bcb4eb1b17aa8e0510a65979b5d8182894ba97b470e7af0 languageName: node linkType: hard -"@aws-sdk/client-sso@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/client-sso@npm:3.485.0" +"@aws-sdk/client-sso@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/client-sso@npm:3.496.0" dependencies: "@aws-crypto/sha256-browser": "npm:3.0.0" "@aws-crypto/sha256-js": "npm:3.0.0" - "@aws-sdk/core": "npm:3.485.0" - "@aws-sdk/middleware-host-header": "npm:3.485.0" - "@aws-sdk/middleware-logger": "npm:3.485.0" - "@aws-sdk/middleware-recursion-detection": "npm:3.485.0" - "@aws-sdk/middleware-user-agent": "npm:3.485.0" - "@aws-sdk/region-config-resolver": "npm:3.485.0" - "@aws-sdk/types": "npm:3.485.0" - "@aws-sdk/util-endpoints": "npm:3.485.0" - "@aws-sdk/util-user-agent-browser": "npm:3.485.0" - "@aws-sdk/util-user-agent-node": "npm:3.485.0" - "@smithy/config-resolver": "npm:^2.0.23" - "@smithy/core": "npm:^1.2.2" - "@smithy/fetch-http-handler": "npm:^2.3.2" - "@smithy/hash-node": "npm:^2.0.18" - "@smithy/invalid-dependency": "npm:^2.0.16" - "@smithy/middleware-content-length": "npm:^2.0.18" - "@smithy/middleware-endpoint": "npm:^2.3.0" - "@smithy/middleware-retry": "npm:^2.0.26" - "@smithy/middleware-serde": "npm:^2.0.16" - "@smithy/middleware-stack": "npm:^2.0.10" - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/node-http-handler": "npm:^2.2.2" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/smithy-client": "npm:^2.2.1" - "@smithy/types": "npm:^2.8.0" - "@smithy/url-parser": "npm:^2.0.16" - "@smithy/util-base64": "npm:^2.0.1" - "@smithy/util-body-length-browser": "npm:^2.0.1" - "@smithy/util-body-length-node": "npm:^2.1.0" - "@smithy/util-defaults-mode-browser": "npm:^2.0.24" - "@smithy/util-defaults-mode-node": "npm:^2.0.32" - "@smithy/util-endpoints": "npm:^1.0.8" - "@smithy/util-retry": "npm:^2.0.9" - "@smithy/util-utf8": "npm:^2.0.2" + "@aws-sdk/core": "npm:3.496.0" + "@aws-sdk/middleware-host-header": "npm:3.496.0" + "@aws-sdk/middleware-logger": "npm:3.496.0" + "@aws-sdk/middleware-recursion-detection": "npm:3.496.0" + "@aws-sdk/middleware-user-agent": "npm:3.496.0" + "@aws-sdk/region-config-resolver": "npm:3.496.0" + "@aws-sdk/types": "npm:3.496.0" + "@aws-sdk/util-endpoints": "npm:3.496.0" + "@aws-sdk/util-user-agent-browser": "npm:3.496.0" + "@aws-sdk/util-user-agent-node": "npm:3.496.0" + "@smithy/config-resolver": "npm:^2.1.1" + "@smithy/core": "npm:^1.3.1" + "@smithy/fetch-http-handler": "npm:^2.4.1" + "@smithy/hash-node": "npm:^2.1.1" + "@smithy/invalid-dependency": "npm:^2.1.1" + "@smithy/middleware-content-length": "npm:^2.1.1" + "@smithy/middleware-endpoint": "npm:^2.4.1" + "@smithy/middleware-retry": "npm:^2.1.1" + "@smithy/middleware-serde": "npm:^2.1.1" + "@smithy/middleware-stack": "npm:^2.1.1" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/node-http-handler": "npm:^2.3.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/smithy-client": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/url-parser": "npm:^2.1.1" + "@smithy/util-base64": "npm:^2.1.1" + "@smithy/util-body-length-browser": "npm:^2.1.1" + "@smithy/util-body-length-node": "npm:^2.2.1" + "@smithy/util-defaults-mode-browser": "npm:^2.1.1" + "@smithy/util-defaults-mode-node": "npm:^2.1.1" + "@smithy/util-endpoints": "npm:^1.1.1" + "@smithy/util-retry": "npm:^2.1.1" + "@smithy/util-utf8": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: 635de0e310c3608bd94d90766ac36b56663ae39df0164122236f5d4e5a3447ba7dd2f66d7f3481380e74f1d508053d218bd0c2872df679f11225dc46f52dba11 + checksum: 4544cca0dd1f5bf4cfbc82c4fdf5416a5472f8ed99b93ad57cc10e78e49294a797bc02fec5850ca91cd280e81e499c9e6cec10ecf6ba94844caa2eb06257ebda languageName: node linkType: hard -"@aws-sdk/client-sts@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/client-sts@npm:3.485.0" +"@aws-sdk/client-sts@npm:3.499.0": + version: 3.499.0 + resolution: "@aws-sdk/client-sts@npm:3.499.0" dependencies: "@aws-crypto/sha256-browser": "npm:3.0.0" "@aws-crypto/sha256-js": "npm:3.0.0" - "@aws-sdk/core": "npm:3.485.0" - "@aws-sdk/credential-provider-node": "npm:3.485.0" - "@aws-sdk/middleware-host-header": "npm:3.485.0" - "@aws-sdk/middleware-logger": "npm:3.485.0" - "@aws-sdk/middleware-recursion-detection": "npm:3.485.0" - "@aws-sdk/middleware-user-agent": "npm:3.485.0" - "@aws-sdk/region-config-resolver": "npm:3.485.0" - "@aws-sdk/types": "npm:3.485.0" - "@aws-sdk/util-endpoints": "npm:3.485.0" - "@aws-sdk/util-user-agent-browser": "npm:3.485.0" - "@aws-sdk/util-user-agent-node": "npm:3.485.0" - "@smithy/config-resolver": "npm:^2.0.23" - "@smithy/core": "npm:^1.2.2" - "@smithy/fetch-http-handler": "npm:^2.3.2" - "@smithy/hash-node": "npm:^2.0.18" - "@smithy/invalid-dependency": "npm:^2.0.16" - "@smithy/middleware-content-length": "npm:^2.0.18" - "@smithy/middleware-endpoint": "npm:^2.3.0" - "@smithy/middleware-retry": "npm:^2.0.26" - "@smithy/middleware-serde": "npm:^2.0.16" - "@smithy/middleware-stack": "npm:^2.0.10" - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/node-http-handler": "npm:^2.2.2" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/smithy-client": "npm:^2.2.1" - "@smithy/types": "npm:^2.8.0" - "@smithy/url-parser": "npm:^2.0.16" - "@smithy/util-base64": "npm:^2.0.1" - "@smithy/util-body-length-browser": "npm:^2.0.1" - "@smithy/util-body-length-node": "npm:^2.1.0" - "@smithy/util-defaults-mode-browser": "npm:^2.0.24" - "@smithy/util-defaults-mode-node": "npm:^2.0.32" - "@smithy/util-endpoints": "npm:^1.0.8" - "@smithy/util-middleware": "npm:^2.0.9" - "@smithy/util-retry": "npm:^2.0.9" - "@smithy/util-utf8": "npm:^2.0.2" + "@aws-sdk/core": "npm:3.496.0" + "@aws-sdk/credential-provider-node": "npm:3.499.0" + "@aws-sdk/middleware-host-header": "npm:3.496.0" + "@aws-sdk/middleware-logger": "npm:3.496.0" + "@aws-sdk/middleware-recursion-detection": "npm:3.496.0" + "@aws-sdk/middleware-user-agent": "npm:3.496.0" + "@aws-sdk/region-config-resolver": "npm:3.496.0" + "@aws-sdk/types": "npm:3.496.0" + "@aws-sdk/util-endpoints": "npm:3.496.0" + "@aws-sdk/util-user-agent-browser": "npm:3.496.0" + "@aws-sdk/util-user-agent-node": "npm:3.496.0" + "@smithy/config-resolver": "npm:^2.1.1" + "@smithy/core": "npm:^1.3.1" + "@smithy/fetch-http-handler": "npm:^2.4.1" + "@smithy/hash-node": "npm:^2.1.1" + "@smithy/invalid-dependency": "npm:^2.1.1" + "@smithy/middleware-content-length": "npm:^2.1.1" + "@smithy/middleware-endpoint": "npm:^2.4.1" + "@smithy/middleware-retry": "npm:^2.1.1" + "@smithy/middleware-serde": "npm:^2.1.1" + "@smithy/middleware-stack": "npm:^2.1.1" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/node-http-handler": "npm:^2.3.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/smithy-client": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/url-parser": "npm:^2.1.1" + "@smithy/util-base64": "npm:^2.1.1" + "@smithy/util-body-length-browser": "npm:^2.1.1" + "@smithy/util-body-length-node": "npm:^2.2.1" + "@smithy/util-defaults-mode-browser": "npm:^2.1.1" + "@smithy/util-defaults-mode-node": "npm:^2.1.1" + "@smithy/util-endpoints": "npm:^1.1.1" + "@smithy/util-middleware": "npm:^2.1.1" + "@smithy/util-retry": "npm:^2.1.1" + "@smithy/util-utf8": "npm:^2.1.1" fast-xml-parser: "npm:4.2.5" tslib: "npm:^2.5.0" - checksum: 98c7f4d7223cd32a1e8ded3f4d8f2fdb228c3a717a42859fbbf8afbadec56826f1e41a33d126ef2855e1e7b6d411abf25d83cd6baf9afcd65b682436570e81bd + checksum: 06e190f3f888b8a4fc2c84caf439a4b07ea3d13aa70acbccee363058bc047cd8e19df39b35bc6ab3b397b141797da9809924b36392c168df7d8e5bbd2f7c3814 languageName: node linkType: hard -"@aws-sdk/core@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/core@npm:3.485.0" +"@aws-sdk/core@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/core@npm:3.496.0" dependencies: - "@smithy/core": "npm:^1.2.2" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/signature-v4": "npm:^2.0.0" - "@smithy/smithy-client": "npm:^2.2.1" - "@smithy/types": "npm:^2.8.0" + "@smithy/core": "npm:^1.3.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/signature-v4": "npm:^2.1.1" + "@smithy/smithy-client": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: b84dafb213d97ebbab5d03b473e032c0e7f85872a8745fdb3274b628aa5c6e300c87a4df0747ebd29ac812c14566c295994642525210bfc81ded083d7559dbc9 + checksum: 177d31f2f72d0c4ba184949d08aa6229307fd6fac9c404b442364381aa9d5a2fd955b01b9ccfe152e96741648232008d1ded75ca79b7cefbc051bda3ed1187ad languageName: node linkType: hard -"@aws-sdk/credential-provider-env@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/credential-provider-env@npm:3.485.0" +"@aws-sdk/credential-provider-env@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/credential-provider-env@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@smithy/property-provider": "npm:^2.0.0" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/property-provider": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: b8346ea6f54cdce2302d266e76cff3569151ef9d5cf31364e99b9b0808f5f62cb45ffacb48cb68ccc85bd5774443231056a648fe9db45ac9c9f6d83e47a0c2d7 + checksum: 8b32ff1d3c1f4b40cba3d6d9047bde936bf57669ca37a50f3d6cc26b2736dd8498f8c0010927a3b6de64b4646201ef841760ce51acfaff87838a489365a37619 languageName: node linkType: hard -"@aws-sdk/credential-provider-ini@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/credential-provider-ini@npm:3.485.0" +"@aws-sdk/credential-provider-ini@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/credential-provider-ini@npm:3.496.0" dependencies: - "@aws-sdk/credential-provider-env": "npm:3.485.0" - "@aws-sdk/credential-provider-process": "npm:3.485.0" - "@aws-sdk/credential-provider-sso": "npm:3.485.0" - "@aws-sdk/credential-provider-web-identity": "npm:3.485.0" - "@aws-sdk/types": "npm:3.485.0" - "@smithy/credential-provider-imds": "npm:^2.0.0" - "@smithy/property-provider": "npm:^2.0.0" - "@smithy/shared-ini-file-loader": "npm:^2.0.6" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/credential-provider-env": "npm:3.496.0" + "@aws-sdk/credential-provider-process": "npm:3.496.0" + "@aws-sdk/credential-provider-sso": "npm:3.496.0" + "@aws-sdk/credential-provider-web-identity": "npm:3.496.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/credential-provider-imds": "npm:^2.2.1" + "@smithy/property-provider": "npm:^2.1.1" + "@smithy/shared-ini-file-loader": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 3176b03ee14ae1b84340a235161e1812f16da95115330917c22b0bbcc7fa86a051e53d493d589a537466cb5bbd4866897a8088d43d7d337c36aa9bb5b12b8525 + checksum: 745941363c64573b779cc287cd7861763e931d4414d1800a94ac13d9e31f63326dc8df7c97fe2c9aecd8ce65e985397eb830afb6fcb3e2957c447973835aa192 languageName: node linkType: hard -"@aws-sdk/credential-provider-node@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/credential-provider-node@npm:3.485.0" +"@aws-sdk/credential-provider-node@npm:3.499.0": + version: 3.499.0 + resolution: "@aws-sdk/credential-provider-node@npm:3.499.0" dependencies: - "@aws-sdk/credential-provider-env": "npm:3.485.0" - "@aws-sdk/credential-provider-ini": "npm:3.485.0" - "@aws-sdk/credential-provider-process": "npm:3.485.0" - "@aws-sdk/credential-provider-sso": "npm:3.485.0" - "@aws-sdk/credential-provider-web-identity": "npm:3.485.0" - "@aws-sdk/types": "npm:3.485.0" - "@smithy/credential-provider-imds": "npm:^2.0.0" - "@smithy/property-provider": "npm:^2.0.0" - "@smithy/shared-ini-file-loader": "npm:^2.0.6" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/credential-provider-env": "npm:3.496.0" + "@aws-sdk/credential-provider-ini": "npm:3.496.0" + "@aws-sdk/credential-provider-process": "npm:3.496.0" + "@aws-sdk/credential-provider-sso": "npm:3.496.0" + "@aws-sdk/credential-provider-web-identity": "npm:3.496.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/credential-provider-imds": "npm:^2.2.1" + "@smithy/property-provider": "npm:^2.1.1" + "@smithy/shared-ini-file-loader": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: d31e5a95ea06436dc10978c39ce33263339dbd295934c37c2e762000039054456f623cf3549a07e1a2250c9f2b0552236e38dbe4cd97df809b6f7e946a65d98e + checksum: ab592362acc32598b0ee1924747b42e523352684a7dfa3399370f0cf3d0206354c78575722962e25fd19697750571c8541322529d3bc42bf115d86e3e6d35f61 languageName: node linkType: hard -"@aws-sdk/credential-provider-process@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/credential-provider-process@npm:3.485.0" +"@aws-sdk/credential-provider-process@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/credential-provider-process@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@smithy/property-provider": "npm:^2.0.0" - "@smithy/shared-ini-file-loader": "npm:^2.0.6" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/property-provider": "npm:^2.1.1" + "@smithy/shared-ini-file-loader": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: e740fb949ec17afd4e3a7515aa6f279eb587539f9114455e0869e762a1fb90b8349c3b7e2ceed1de307e3bef2ef9916a00e89ee5a3c1b1b6caf02a686a2d4be0 + checksum: 94e1816fe2e8c9dbb7a5ca694178bd6e139363248543941fac45566a9031153481ff2b6d2336ad6219451240181003973e06beca2da9a4021d688bbcc237b8ed languageName: node linkType: hard -"@aws-sdk/credential-provider-sso@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/credential-provider-sso@npm:3.485.0" +"@aws-sdk/credential-provider-sso@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/credential-provider-sso@npm:3.496.0" dependencies: - "@aws-sdk/client-sso": "npm:3.485.0" - "@aws-sdk/token-providers": "npm:3.485.0" - "@aws-sdk/types": "npm:3.485.0" - "@smithy/property-provider": "npm:^2.0.0" - "@smithy/shared-ini-file-loader": "npm:^2.0.6" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/client-sso": "npm:3.496.0" + "@aws-sdk/token-providers": "npm:3.496.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/property-provider": "npm:^2.1.1" + "@smithy/shared-ini-file-loader": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 7269315797a1a6a9e3d1dbfd2a65ad7c092fcc4631be880f748b3561cebab30631d10d7c281880d46113306c7794b10f2b7b3f934e8047c8559e0ec0da15d0fb + checksum: ab47f0104ee30b8d8772c878cee150e7e585b99301bd3e452f62d7fe61440c224ce74082a5ce1c3f986dce170c4841737fb700cc5edae2bdfd4829b5593d1bb3 languageName: node linkType: hard -"@aws-sdk/credential-provider-web-identity@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/credential-provider-web-identity@npm:3.485.0" +"@aws-sdk/credential-provider-web-identity@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/credential-provider-web-identity@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@smithy/property-provider": "npm:^2.0.0" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/property-provider": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 33125ce0b7c3bf36ff3f52bda6657f667698e25bd09cb0c302e1e85b8d8b20b322e225981c887363bbe8ba47e22721184ad83ff30271b2887d4ea25de270b760 + checksum: a43c0bf19de371d602669188ce357fe0fd0def52396152ecc1067a4ae08e15822697f96630619052ae7cf96777a800a9d16fa9f63f645d07d10dc13492141c34 languageName: node linkType: hard -"@aws-sdk/middleware-bucket-endpoint@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.485.0" +"@aws-sdk/middleware-bucket-endpoint@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@aws-sdk/util-arn-parser": "npm:3.465.0" - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/types": "npm:^2.8.0" - "@smithy/util-config-provider": "npm:^2.1.0" + "@aws-sdk/types": "npm:3.496.0" + "@aws-sdk/util-arn-parser": "npm:3.495.0" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-config-provider": "npm:^2.2.1" tslib: "npm:^2.5.0" - checksum: 2c285960e3a3c9fa4edf20fff00898cf087bf99c92bcebb484cffb42cc8dca04ed27a7bcb991f1122ecefc767796e33a756f070fbb03a446a22f2f38cb14ab23 + checksum: 00b4facd3e350519a249fa619b21f182ca76a0dd076078da61999790f6994ea898c887f96556516c9d4fee4c5731a04abc9173b3e49e368f7eea3cb08ee781dd languageName: node linkType: hard -"@aws-sdk/middleware-expect-continue@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/middleware-expect-continue@npm:3.485.0" +"@aws-sdk/middleware-expect-continue@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/middleware-expect-continue@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: f6c712ac29430b92dfae5534f1a65d048a7774d0df75557d8ebe23efb80088e8e6eaa096577ca24f83c3ae15502a17ebc0e87473dc6a427b67a99dda68d65bce + checksum: 3fe6a8e132747cca354369d00a2ca8f07206f751726fa713dcd011163dfb9c4451def68ddc72fa19ead6ab34974ce9f8d103655963262f243a0aef4210a06edd languageName: node linkType: hard -"@aws-sdk/middleware-flexible-checksums@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.485.0" +"@aws-sdk/middleware-flexible-checksums@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.496.0" dependencies: "@aws-crypto/crc32": "npm:3.0.0" "@aws-crypto/crc32c": "npm:3.0.0" - "@aws-sdk/types": "npm:3.485.0" - "@smithy/is-array-buffer": "npm:^2.0.0" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/types": "npm:^2.8.0" - "@smithy/util-utf8": "npm:^2.0.2" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/is-array-buffer": "npm:^2.1.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-utf8": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: 10c61b9166321ca5ea940a8269d3ceddda422ad1029e87286d0b129ac9ae67737eac79f00cd79b65011d6b60dc37c38c7bf7b385f5b8fe518f8658b24ec53ef0 + checksum: 7a15e90b29febccbcfb5d90e49258bf7b4857511a41f1c60041c9df11b862d25b1b5c7089d0f88fe281041350400bfc8ce49c6e3b1d4669dbda357abc804944c languageName: node linkType: hard -"@aws-sdk/middleware-host-header@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/middleware-host-header@npm:3.485.0" +"@aws-sdk/middleware-host-header@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/middleware-host-header@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 9ca3da2a264885448a84efe37d3262909118c5ca7d74d0459f74dd9291e036660835d648f8962144a27ef25f9b8662610e104f2534e40cb2765c2747cb7a22b9 + checksum: 148547d93094a2c175d15c23436b4585bfc4676224be45c631e55cd045737277f9bb1079ad5060163a47d8b52a11b87a81fde58aac132a4ea091a58c45b31e2a languageName: node linkType: hard -"@aws-sdk/middleware-location-constraint@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/middleware-location-constraint@npm:3.485.0" +"@aws-sdk/middleware-location-constraint@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/middleware-location-constraint@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: e0c6637ae1e4302f5c69e46bb1d47c644e1211850c688ad36926c1905bf0af6e141d0bc6c8f7f1c4adc66ad861480efdae6206154c6c2d488e22531d17b0fec5 + checksum: f293604f9aff7bc1a72a1dc5704ce1f66f54da2530ae6855776189ecc57f2f0507eb0eb7306875cdcb1a7fdcd817d0894a228d48f4a6c56f83529ae5567cefba languageName: node linkType: hard -"@aws-sdk/middleware-logger@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/middleware-logger@npm:3.485.0" +"@aws-sdk/middleware-logger@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/middleware-logger@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 2fcb731794ecc665517b2aaba20ae24f42046cf1c7e663288afc7e97263116b6d9fa9dd36c1ba47c6ea01954a15519d6da57653b50097dab0853c6a344a69492 + checksum: 1a1845b6452716e9d4bde8fae3896acfaeec6c5a6902f415ed79141346ffa23d423aa4e2940f1c8d138e14e666d93158d3640ee4f4fb5a2485e5644147d07245 languageName: node linkType: hard -"@aws-sdk/middleware-recursion-detection@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/middleware-recursion-detection@npm:3.485.0" +"@aws-sdk/middleware-recursion-detection@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/middleware-recursion-detection@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: afdea18930299e12a961f68a9a898f34f737c2ce9709c70e0043d6b7ec2ea2c6ad8df05877ab013f8d7d3f6322253bbf1ff6100ab6be445ef91a95a865f74ffa + checksum: cfc97c7084a4aa3f0da7fb58cc2eb41d4fb35ad7f9b485b359c5e21b427203ed237af66bbd3a5de9040b7a32ba17a8ec92be3c12e25672f1019bfa28895cb253 languageName: node linkType: hard -"@aws-sdk/middleware-sdk-s3@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/middleware-sdk-s3@npm:3.485.0" +"@aws-sdk/middleware-sdk-s3@npm:3.499.0": + version: 3.499.0 + resolution: "@aws-sdk/middleware-sdk-s3@npm:3.499.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@aws-sdk/util-arn-parser": "npm:3.465.0" - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/signature-v4": "npm:^2.0.0" - "@smithy/smithy-client": "npm:^2.2.1" - "@smithy/types": "npm:^2.8.0" - "@smithy/util-config-provider": "npm:^2.1.0" + "@aws-sdk/types": "npm:3.496.0" + "@aws-sdk/util-arn-parser": "npm:3.495.0" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/signature-v4": "npm:^2.1.1" + "@smithy/smithy-client": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-config-provider": "npm:^2.2.1" tslib: "npm:^2.5.0" - checksum: 48a727d7b2cec8aa4f1034e9c74221fa9a0b778b1ba8f5420609d5e8ea78a188ab35d99f70a50b089bb5614a266aab1ba2ec41a532507d47f59f0319309b6c6f + checksum: fccfd29e224aa58ce8719eba1054ffbfb03756fb08de561456a035f3c31d4f3915652b55743fd513a989a4f8934cd3e7a29951f3ed480e82a0ef3e97ac97020c languageName: node linkType: hard -"@aws-sdk/middleware-signing@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/middleware-signing@npm:3.485.0" +"@aws-sdk/middleware-signing@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/middleware-signing@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@smithy/property-provider": "npm:^2.0.0" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/signature-v4": "npm:^2.0.0" - "@smithy/types": "npm:^2.8.0" - "@smithy/util-middleware": "npm:^2.0.9" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/property-provider": "npm:^2.1.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/signature-v4": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-middleware": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: f9dbb39d8dda2841350c015eacbaa9f2444fa9b48080a5da2a41465252241f45da65007c21ce56a1961c75bf7d5395fadf39ce11ec78c96a7923a8b98a6684a2 + checksum: ddba07855b98d25bd93a57859fc8c03e8ab6048c53f942751accdc8d71ccf5c676e82bcf3de5e890665951aff90fc981a72a22b0f095a573563cc5f52b6824c4 languageName: node linkType: hard -"@aws-sdk/middleware-ssec@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/middleware-ssec@npm:3.485.0" +"@aws-sdk/middleware-ssec@npm:3.498.0": + version: 3.498.0 + resolution: "@aws-sdk/middleware-ssec@npm:3.498.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 3a550c960c9a2cdceb5e56743a7c253c92009928167f148c6ce80d1a9358f47578abee8bf96cf211deeec45768121b0751128ab1a3578ce56bae61531f035589 + checksum: 22c53fe93ca49843eb2ade5e55b8e5b10254227604a60b1637c46e553a0fa1acedf6b7d332397b7ff2675c8754284592b25744105155fad5803fcad105556888 languageName: node linkType: hard -"@aws-sdk/middleware-user-agent@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/middleware-user-agent@npm:3.485.0" +"@aws-sdk/middleware-user-agent@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/middleware-user-agent@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@aws-sdk/util-endpoints": "npm:3.485.0" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/types": "npm:3.496.0" + "@aws-sdk/util-endpoints": "npm:3.496.0" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: a8fc812aff61a1a98dbd1cb6555786b7156a1024d3aba6554d56f5302e90b1b660e141f274c0a00e107276b0f4129ce4978faeb5847a54c54cc9289dd2834035 + checksum: 4863d3f7678ecc936f5baf82c3bb9ece94b72fa20bdc0a1aab0c55afd843f3f02730c0c7cbec5e4b60661fb5e6db058d71e1dc2851d51b4f8011d2ee0df50e80 languageName: node linkType: hard -"@aws-sdk/region-config-resolver@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/region-config-resolver@npm:3.485.0" +"@aws-sdk/region-config-resolver@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/region-config-resolver@npm:3.496.0" dependencies: - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/types": "npm:^2.8.0" - "@smithy/util-config-provider": "npm:^2.1.0" - "@smithy/util-middleware": "npm:^2.0.9" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-config-provider": "npm:^2.2.1" + "@smithy/util-middleware": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: 55bc5128b8dd325f7826afb741544689ff89da8ed5cfe4a704c90eff1c477ecf71b023cb6f52d0a2d5045eecfb4b61d82e3f98f10feb913d3720f14cce4df632 + checksum: 08858d55220f886da272e89acbe76136bb2815af06bb34f1156fe8b620200bfbe6d88535e0d98bcc7dbad8454dcadbb2291655028efb865356e157a7ba8f3a7f languageName: node linkType: hard -"@aws-sdk/signature-v4-multi-region@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/signature-v4-multi-region@npm:3.485.0" +"@aws-sdk/signature-v4-multi-region@npm:3.499.0": + version: 3.499.0 + resolution: "@aws-sdk/signature-v4-multi-region@npm:3.499.0" dependencies: - "@aws-sdk/middleware-sdk-s3": "npm:3.485.0" - "@aws-sdk/types": "npm:3.485.0" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/signature-v4": "npm:^2.0.0" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/middleware-sdk-s3": "npm:3.499.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/signature-v4": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 14551f298a136e90e95ccb87a89147d4a0b845fbc79fbc68351ba70c8962cc0fd906ba5facf64fd0727c837f65938547b8222a192cbe182e7d2f815c76dea086 + checksum: 6fe18183544d81a42d7f021ea215d67c33c870b0e47973553366d673fe3432e2abdab32ec6a6f4be858bdca9daa6cffd49aef584b3b612d79df8123ca6e332e5 languageName: node linkType: hard -"@aws-sdk/token-providers@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/token-providers@npm:3.485.0" +"@aws-sdk/token-providers@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/token-providers@npm:3.496.0" dependencies: "@aws-crypto/sha256-browser": "npm:3.0.0" "@aws-crypto/sha256-js": "npm:3.0.0" - "@aws-sdk/middleware-host-header": "npm:3.485.0" - "@aws-sdk/middleware-logger": "npm:3.485.0" - "@aws-sdk/middleware-recursion-detection": "npm:3.485.0" - "@aws-sdk/middleware-user-agent": "npm:3.485.0" - "@aws-sdk/region-config-resolver": "npm:3.485.0" - "@aws-sdk/types": "npm:3.485.0" - "@aws-sdk/util-endpoints": "npm:3.485.0" - "@aws-sdk/util-user-agent-browser": "npm:3.485.0" - "@aws-sdk/util-user-agent-node": "npm:3.485.0" - "@smithy/config-resolver": "npm:^2.0.23" - "@smithy/fetch-http-handler": "npm:^2.3.2" - "@smithy/hash-node": "npm:^2.0.18" - "@smithy/invalid-dependency": "npm:^2.0.16" - "@smithy/middleware-content-length": "npm:^2.0.18" - "@smithy/middleware-endpoint": "npm:^2.3.0" - "@smithy/middleware-retry": "npm:^2.0.26" - "@smithy/middleware-serde": "npm:^2.0.16" - "@smithy/middleware-stack": "npm:^2.0.10" - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/node-http-handler": "npm:^2.2.2" - "@smithy/property-provider": "npm:^2.0.0" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/shared-ini-file-loader": "npm:^2.0.6" - "@smithy/smithy-client": "npm:^2.2.1" - "@smithy/types": "npm:^2.8.0" - "@smithy/url-parser": "npm:^2.0.16" - "@smithy/util-base64": "npm:^2.0.1" - "@smithy/util-body-length-browser": "npm:^2.0.1" - "@smithy/util-body-length-node": "npm:^2.1.0" - "@smithy/util-defaults-mode-browser": "npm:^2.0.24" - "@smithy/util-defaults-mode-node": "npm:^2.0.32" - "@smithy/util-endpoints": "npm:^1.0.8" - "@smithy/util-retry": "npm:^2.0.9" - "@smithy/util-utf8": "npm:^2.0.2" + "@aws-sdk/middleware-host-header": "npm:3.496.0" + "@aws-sdk/middleware-logger": "npm:3.496.0" + "@aws-sdk/middleware-recursion-detection": "npm:3.496.0" + "@aws-sdk/middleware-user-agent": "npm:3.496.0" + "@aws-sdk/region-config-resolver": "npm:3.496.0" + "@aws-sdk/types": "npm:3.496.0" + "@aws-sdk/util-endpoints": "npm:3.496.0" + "@aws-sdk/util-user-agent-browser": "npm:3.496.0" + "@aws-sdk/util-user-agent-node": "npm:3.496.0" + "@smithy/config-resolver": "npm:^2.1.1" + "@smithy/fetch-http-handler": "npm:^2.4.1" + "@smithy/hash-node": "npm:^2.1.1" + "@smithy/invalid-dependency": "npm:^2.1.1" + "@smithy/middleware-content-length": "npm:^2.1.1" + "@smithy/middleware-endpoint": "npm:^2.4.1" + "@smithy/middleware-retry": "npm:^2.1.1" + "@smithy/middleware-serde": "npm:^2.1.1" + "@smithy/middleware-stack": "npm:^2.1.1" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/node-http-handler": "npm:^2.3.1" + "@smithy/property-provider": "npm:^2.1.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/shared-ini-file-loader": "npm:^2.3.1" + "@smithy/smithy-client": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/url-parser": "npm:^2.1.1" + "@smithy/util-base64": "npm:^2.1.1" + "@smithy/util-body-length-browser": "npm:^2.1.1" + "@smithy/util-body-length-node": "npm:^2.2.1" + "@smithy/util-defaults-mode-browser": "npm:^2.1.1" + "@smithy/util-defaults-mode-node": "npm:^2.1.1" + "@smithy/util-endpoints": "npm:^1.1.1" + "@smithy/util-retry": "npm:^2.1.1" + "@smithy/util-utf8": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: aed270b62546e34a476e034f90a1d10fbb05a8a14be6c93bbcd5dd8ab77cfa3b2915bae0d6a0c21044bdd039851fcbbac01f4c931b35d4f7cd5317be5b3eab24 + checksum: ca39e300e7659a633ef9ec19e60d9aec9b7acb52e8bb5d514d2eff4af74f9a9d2f1dd3c3a55a9733546a266a0a854d2890b3bd77fe0bda2fe1eabd190cd30577 languageName: node linkType: hard -"@aws-sdk/types@npm:3.485.0, @aws-sdk/types@npm:^3.222.0": - version: 3.485.0 - resolution: "@aws-sdk/types@npm:3.485.0" +"@aws-sdk/types@npm:3.496.0, @aws-sdk/types@npm:^3.222.0": + version: 3.496.0 + resolution: "@aws-sdk/types@npm:3.496.0" dependencies: - "@smithy/types": "npm:^2.8.0" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 588aae4b494d7914475280bcecb579690170ca2a1c8b6d9c64ed05819dfd79de225eaa64a455f3d168f57b365eca743a363c27be464aa3ac59a2f2199d125ae5 + checksum: 98eba036198e697e1820627ab182a649c987b7c18fc57d401fa80702e1a0b1c829ae2db9fbec09219951c4b65d6efa1828c164d9174affdd4276bb0742c48fd1 languageName: node linkType: hard -"@aws-sdk/util-arn-parser@npm:3.465.0": - version: 3.465.0 - resolution: "@aws-sdk/util-arn-parser@npm:3.465.0" +"@aws-sdk/util-arn-parser@npm:3.495.0": + version: 3.495.0 + resolution: "@aws-sdk/util-arn-parser@npm:3.495.0" dependencies: tslib: "npm:^2.5.0" - checksum: 0fb11c7e3d09901708f46cb0c885c2df7a8e8af70560484fa478bf9e2f8ee2aa6028c67187c0520eec6a92003bc43ae68c0ddc32db3af3e6d554b48080910af5 + checksum: 8f8574376e21ae90f2e5ee0ddf6516e8fb31ac433989f7015f0feed185b518108c7c65fc346c64924feb917daed6bfd7ede0c6cf047b64f09cff0125041162b6 languageName: node linkType: hard -"@aws-sdk/util-endpoints@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/util-endpoints@npm:3.485.0" +"@aws-sdk/util-endpoints@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/util-endpoints@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@smithy/util-endpoints": "npm:^1.0.8" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-endpoints": "npm:^1.1.1" tslib: "npm:^2.5.0" - checksum: c1844fed8bb8fd01490fde9ed6cf3dad5647a51b72a964f7fd525f82a812bb79a128ff24fe0c3a3afb459290da21435548ef32e249d0018fe53bb3b4d4635bcb + checksum: e916aad6ee123437c8b9f08ac80b584d05e5a235de5cbbca76db8fad7ce031f1b8b0861fc1fa6ae8e168e3c0d3986748a0c868158341a94a5024b06b1b8eef87 languageName: node linkType: hard @@ -1773,32 +1765,32 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-user-agent-browser@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/util-user-agent-browser@npm:3.485.0" +"@aws-sdk/util-user-agent-browser@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/util-user-agent-browser@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/types": "npm:^2.9.1" bowser: "npm:^2.11.0" tslib: "npm:^2.5.0" - checksum: d1e4d4c63508e91a38f0a1a35330cc7233d235efe315b56925f0d4cd4ea88baef3a6ca0f995571e3b81084e1b2ef229a5c0c9e72e2787321bb7da889231a8f77 + checksum: 671b0b117795387108abedc3b8d1ec64f2eee9e4b808216ab70cb4a7529801e14c7f2ddfd814d94834a49fcdef6a8a08700849537d68d2d83c8b2cc75c0fadba languageName: node linkType: hard -"@aws-sdk/util-user-agent-node@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/util-user-agent-node@npm:3.485.0" +"@aws-sdk/util-user-agent-node@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/util-user-agent-node@npm:3.496.0" dependencies: - "@aws-sdk/types": "npm:3.485.0" - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/types": "npm:^2.8.0" + "@aws-sdk/types": "npm:3.496.0" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" peerDependencies: aws-crt: ">=1.0.0" peerDependenciesMeta: aws-crt: optional: true - checksum: e2805ef37b90677673b73acc9dc009cdd70f6167d1f0f83fdfe65e867057f6091b924642f8ff5338aff711b8c623fe9e765f2438cdeaa232953359f756947dd5 + checksum: 21e18674ded51ffdf4537b434f77f405fc1b0767773c34ec4da8ccd7be68ae9c2ac5fdc7f4a80205dd3de55eab28b66d302b85fa45e975ae2c0c75f6ea8311ca languageName: node linkType: hard @@ -1811,13 +1803,13 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/xml-builder@npm:3.485.0": - version: 3.485.0 - resolution: "@aws-sdk/xml-builder@npm:3.485.0" +"@aws-sdk/xml-builder@npm:3.496.0": + version: 3.496.0 + resolution: "@aws-sdk/xml-builder@npm:3.496.0" dependencies: - "@smithy/types": "npm:^2.8.0" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 82bee30922662391703fca2ca1c735f6a91b031e3330091ca3fab774062742ac0dd88085feeebc2431e7d3c3d02f50bfa0d1bec7673e691dcd07ef03ff6bb880 + checksum: 9a5904a674f8e66be5528deac59f8d863bb4ea213a34e456c40b38d5bfdff3527d6ea79264ebdb4ab0b994d53b40f7bf93413308befd060fb07ab72e3708e103 languageName: node linkType: hard @@ -3394,29 +3386,29 @@ __metadata: languageName: node linkType: hard -"@blocksuite/block-std@npm:0.12.0-nightly-202401240410-02f373e": - version: 0.12.0-nightly-202401240410-02f373e - resolution: "@blocksuite/block-std@npm:0.12.0-nightly-202401240410-02f373e" +"@blocksuite/block-std@npm:0.12.0-nightly-202401290223-b6302df": + version: 0.12.0-nightly-202401290223-b6302df + resolution: "@blocksuite/block-std@npm:0.12.0-nightly-202401290223-b6302df" dependencies: - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" + "@blocksuite/global": "npm:0.12.0-nightly-202401290223-b6302df" lz-string: "npm:^1.5.0" w3c-keyname: "npm:^2.2.8" zod: "npm:^3.22.4" peerDependencies: - "@blocksuite/store": 0.12.0-nightly-202401240410-02f373e - checksum: aa1ca1003366b785ffbc291d022456be7119a00140036e2f000fdbc233b7b0d8252ec26f70dd45a47057c1b9d6954c103888846c9076e0a3e9caad5781155a9c + "@blocksuite/store": 0.12.0-nightly-202401290223-b6302df + checksum: 9fea130b429934bb275591ad0434d2c55983ad9816c6c3c726bd9f6d4266a8b1eeead75a20fbb73229a270e92ede35eaa0d7914c866b20be08a5652ebde728c7 languageName: node linkType: hard -"@blocksuite/blocks@npm:0.12.0-nightly-202401240410-02f373e": - version: 0.12.0-nightly-202401240410-02f373e - resolution: "@blocksuite/blocks@npm:0.12.0-nightly-202401240410-02f373e" +"@blocksuite/blocks@npm:0.12.0-nightly-202401290223-b6302df": + version: 0.12.0-nightly-202401290223-b6302df + resolution: "@blocksuite/blocks@npm:0.12.0-nightly-202401290223-b6302df" dependencies: - "@blocksuite/block-std": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/inline": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/lit": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" + "@blocksuite/block-std": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/global": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/inline": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/lit": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/store": "npm:0.12.0-nightly-202401290223-b6302df" "@floating-ui/dom": "npm:^1.5.4" "@toeverything/theme": "npm:^0.7.27" "@types/hast": "npm:^3.0.3" @@ -3450,81 +3442,81 @@ __metadata: unified: "npm:^11.0.4" webfontloader: "npm:^1.6.28" zod: "npm:^3.22.4" - checksum: d3a3b65ddda48c710ef253452f0ae51ee5953643505d3250f7af0c0342e5eaedb2249966f6336b13fc813874a0d28de15a09cb9c5fa87b97c2468eaa5eb5d404 + checksum: bd57e8b1ec108733e0f25e5dd578efe4af859cfd31a7b13f71f763ecd9c5585b3e17a9a81b09192e54f09247aeca8a93d28612b1f8429106a72c4a5b7918b479 languageName: node linkType: hard -"@blocksuite/global@npm:0.12.0-nightly-202401240410-02f373e": - version: 0.12.0-nightly-202401240410-02f373e - resolution: "@blocksuite/global@npm:0.12.0-nightly-202401240410-02f373e" +"@blocksuite/global@npm:0.12.0-nightly-202401290223-b6302df": + version: 0.12.0-nightly-202401290223-b6302df + resolution: "@blocksuite/global@npm:0.12.0-nightly-202401290223-b6302df" dependencies: zod: "npm:^3.22.4" - checksum: 4cc43d78d853ad65a1a6ca86555eea53da9598da0021cc0b7b404dddb724abe823108a5cf663c5ae517a97276b5f83c51ae0c1006980713466f770048341b269 + checksum: 9644627c34ee198ce183d5972bd4d03045b5cb15e227d1bc2f5996edbae818d5c1d3830194a2420930b17a350ac462aa025a316a44e562676cbaa2c4db19b898 languageName: node linkType: hard -"@blocksuite/icons@npm:2.1.42": - version: 2.1.42 - resolution: "@blocksuite/icons@npm:2.1.42" +"@blocksuite/icons@npm:2.1.44": + version: 2.1.44 + resolution: "@blocksuite/icons@npm:2.1.44" peerDependencies: "@types/react": ^18.0.25 react: ^18.2.0 - checksum: 090a5925b253df1b5ade7c47ed5c098955abe027b6cbecfb13ebbc97d4bf2e6dfe520b973362af78c5440ea85765b655cc6f6abc4d5965bf76441c75a80fa2d6 + checksum: 6d012ec2816de46ec10a17de9def5e9913a16d1df20b0f4f6730c5e79b2d1557546680054bdc63fe020728888eae68c59019ac88479ec0337e465340e4c7b6ca languageName: node linkType: hard -"@blocksuite/inline@npm:0.12.0-nightly-202401240410-02f373e": - version: 0.12.0-nightly-202401240410-02f373e - resolution: "@blocksuite/inline@npm:0.12.0-nightly-202401240410-02f373e" +"@blocksuite/inline@npm:0.12.0-nightly-202401290223-b6302df": + version: 0.12.0-nightly-202401290223-b6302df + resolution: "@blocksuite/inline@npm:0.12.0-nightly-202401290223-b6302df" dependencies: - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" + "@blocksuite/global": "npm:0.12.0-nightly-202401290223-b6302df" zod: "npm:^3.22.4" peerDependencies: lit: ^3.1.1 yjs: ^13 - checksum: 9c218173e199493939d4abdd4254cc9a76883b6169e9c948de872bdbdc85976f54fd16d970bed4a4fe73b6c127fd376ec3330d6a29cc090e5db97e3bcc0a1134 + checksum: 42c84d8b8184b8622ffa993ff57fb8b9c516da4696438e239f0410d3bc94a7c15741a8b30f1113516885eb85d2495cc0179ae54324072c9a1eafebd3948f1a6a languageName: node linkType: hard -"@blocksuite/lit@npm:0.12.0-nightly-202401240410-02f373e": - version: 0.12.0-nightly-202401240410-02f373e - resolution: "@blocksuite/lit@npm:0.12.0-nightly-202401240410-02f373e" +"@blocksuite/lit@npm:0.12.0-nightly-202401290223-b6302df": + version: 0.12.0-nightly-202401290223-b6302df + resolution: "@blocksuite/lit@npm:0.12.0-nightly-202401290223-b6302df" dependencies: - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/inline": "npm:0.12.0-nightly-202401240410-02f373e" + "@blocksuite/global": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/inline": "npm:0.12.0-nightly-202401290223-b6302df" lit: "npm:^3.1.1" peerDependencies: - "@blocksuite/block-std": 0.12.0-nightly-202401240410-02f373e - "@blocksuite/store": 0.12.0-nightly-202401240410-02f373e - checksum: 2baf2d48a92d95d5048299aca9998beddd620e3031b0b642b4d46c603a1cba935e1e2670935091960063b92435d71915bdeb845d3df5b4ee45dab9fd1a321166 + "@blocksuite/block-std": 0.12.0-nightly-202401290223-b6302df + "@blocksuite/store": 0.12.0-nightly-202401290223-b6302df + checksum: 7fb16d96f9553944b9d2dad548bd1f1448991d850aee703885fc117feda7f7e7cc8a24f455bf4ea4fc13c8f657e5eec7b6f8e89d4904de8a5f72549eb64b16c4 languageName: node linkType: hard -"@blocksuite/presets@npm:0.12.0-nightly-202401240410-02f373e": - version: 0.12.0-nightly-202401240410-02f373e - resolution: "@blocksuite/presets@npm:0.12.0-nightly-202401240410-02f373e" +"@blocksuite/presets@npm:0.12.0-nightly-202401290223-b6302df": + version: 0.12.0-nightly-202401290223-b6302df + resolution: "@blocksuite/presets@npm:0.12.0-nightly-202401290223-b6302df" dependencies: - "@blocksuite/block-std": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/blocks": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/inline": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/lit": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" + "@blocksuite/block-std": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/blocks": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/global": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/inline": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/lit": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/store": "npm:0.12.0-nightly-202401290223-b6302df" "@fal-ai/serverless-client": "npm:^0.8.2" "@floating-ui/dom": "npm:^1.5.4" "@toeverything/theme": "npm:^0.7.27" lit: "npm:^3.1.1" openai: "npm:^4.25.0" - checksum: 42cd6c8328df82fe0abc22075333d463c75a7b8311431472fc9c953e00927859098bff52a79aee51bc4b2cfff83c2710f72b0d127b8032c2c844b565929873b2 + checksum: a6e44172ae825a6e43a2084459effc1e8257c6c5f55df6e06c5e37c5da394616d07ce78eb0e65bf4b51f5fae2d2042b0a320b9df57d05b811bba63fb5954fb12 languageName: node linkType: hard -"@blocksuite/store@npm:0.12.0-nightly-202401240410-02f373e": - version: 0.12.0-nightly-202401240410-02f373e - resolution: "@blocksuite/store@npm:0.12.0-nightly-202401240410-02f373e" +"@blocksuite/store@npm:0.12.0-nightly-202401290223-b6302df": + version: 0.12.0-nightly-202401290223-b6302df + resolution: "@blocksuite/store@npm:0.12.0-nightly-202401290223-b6302df" dependencies: - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/inline": "npm:0.12.0-nightly-202401240410-02f373e" + "@blocksuite/global": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/inline": "npm:0.12.0-nightly-202401290223-b6302df" "@types/flexsearch": "npm:^0.7.6" flexsearch: "npm:0.7.43" idb-keyval: "npm:^6.2.1" @@ -3537,7 +3529,7 @@ __metadata: peerDependencies: async-call-rpc: ^6 yjs: ^13 - checksum: 4675519c075f8543d74fa9bcdd99d12150b10ff05c42ef365efeac2920ad04afc842d72bc8ceb65d77cd167f633161e8a80e3f33470c0a5e40ad805d58daf905 + checksum: 555f53e54d9725274f233be0c12735d62d6a664d677d673feca4e7d0ebdb494ec3ab82202a4874105bcbcca86b07c95a0726031f24c7c79e992168d58165803d languageName: node linkType: hard @@ -6753,6 +6745,115 @@ __metadata: languageName: node linkType: hard +"@napi-rs/clipboard-darwin-arm64@npm:1.1.1": + version: 1.1.1 + resolution: "@napi-rs/clipboard-darwin-arm64@npm:1.1.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/clipboard-darwin-x64@npm:1.1.1": + version: 1.1.1 + resolution: "@napi-rs/clipboard-darwin-x64@npm:1.1.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/clipboard-linux-arm-gnueabihf@npm:1.1.1": + version: 1.1.1 + resolution: "@napi-rs/clipboard-linux-arm-gnueabihf@npm:1.1.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/clipboard-linux-arm64-gnu@npm:1.1.1": + version: 1.1.1 + resolution: "@napi-rs/clipboard-linux-arm64-gnu@npm:1.1.1" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/clipboard-linux-arm64-musl@npm:1.1.1": + version: 1.1.1 + resolution: "@napi-rs/clipboard-linux-arm64-musl@npm:1.1.1" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/clipboard-linux-x64-gnu@npm:1.1.1": + version: 1.1.1 + resolution: "@napi-rs/clipboard-linux-x64-gnu@npm:1.1.1" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/clipboard-linux-x64-musl@npm:1.1.1": + version: 1.1.1 + resolution: "@napi-rs/clipboard-linux-x64-musl@npm:1.1.1" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/clipboard-win32-arm64-msvc@npm:1.1.1": + version: 1.1.1 + resolution: "@napi-rs/clipboard-win32-arm64-msvc@npm:1.1.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/clipboard-win32-ia32-msvc@npm:1.1.1": + version: 1.1.1 + resolution: "@napi-rs/clipboard-win32-ia32-msvc@npm:1.1.1" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@napi-rs/clipboard-win32-x64-msvc@npm:1.1.1": + version: 1.1.1 + resolution: "@napi-rs/clipboard-win32-x64-msvc@npm:1.1.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/clipboard@npm:^1.1.1": + version: 1.1.1 + resolution: "@napi-rs/clipboard@npm:1.1.1" + dependencies: + "@napi-rs/clipboard-darwin-arm64": "npm:1.1.1" + "@napi-rs/clipboard-darwin-x64": "npm:1.1.1" + "@napi-rs/clipboard-linux-arm-gnueabihf": "npm:1.1.1" + "@napi-rs/clipboard-linux-arm64-gnu": "npm:1.1.1" + "@napi-rs/clipboard-linux-arm64-musl": "npm:1.1.1" + "@napi-rs/clipboard-linux-x64-gnu": "npm:1.1.1" + "@napi-rs/clipboard-linux-x64-musl": "npm:1.1.1" + "@napi-rs/clipboard-win32-arm64-msvc": "npm:1.1.1" + "@napi-rs/clipboard-win32-ia32-msvc": "npm:1.1.1" + "@napi-rs/clipboard-win32-x64-msvc": "npm:1.1.1" + dependenciesMeta: + "@napi-rs/clipboard-darwin-arm64": + optional: true + "@napi-rs/clipboard-darwin-x64": + optional: true + "@napi-rs/clipboard-linux-arm-gnueabihf": + optional: true + "@napi-rs/clipboard-linux-arm64-gnu": + optional: true + "@napi-rs/clipboard-linux-arm64-musl": + optional: true + "@napi-rs/clipboard-linux-x64-gnu": + optional: true + "@napi-rs/clipboard-linux-x64-musl": + optional: true + "@napi-rs/clipboard-win32-arm64-msvc": + optional: true + "@napi-rs/clipboard-win32-ia32-msvc": + optional: true + "@napi-rs/clipboard-win32-x64-msvc": + optional: true + checksum: 3cdd934538417b3911589d494b79e5e5abe1e8be6bb832d13b78fcee3a5df9a514c3268df5b1d02bf8d78d29aeafac4c242854e7093a758c679cf696a975b9ec + languageName: node + linkType: hard + "@napi-rs/cross-toolchain@npm:^0.0.14": version: 0.0.14 resolution: "@napi-rs/cross-toolchain@npm:0.0.14" @@ -7052,6 +7153,125 @@ __metadata: languageName: node linkType: hard +"@napi-rs/simple-git-android-arm-eabi@npm:0.1.11": + version: 0.1.11 + resolution: "@napi-rs/simple-git-android-arm-eabi@npm:0.1.11" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/simple-git-android-arm64@npm:0.1.11": + version: 0.1.11 + resolution: "@napi-rs/simple-git-android-arm64@npm:0.1.11" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/simple-git-darwin-arm64@npm:0.1.11": + version: 0.1.11 + resolution: "@napi-rs/simple-git-darwin-arm64@npm:0.1.11" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/simple-git-darwin-x64@npm:0.1.11": + version: 0.1.11 + resolution: "@napi-rs/simple-git-darwin-x64@npm:0.1.11" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/simple-git-linux-arm-gnueabihf@npm:0.1.11": + version: 0.1.11 + resolution: "@napi-rs/simple-git-linux-arm-gnueabihf@npm:0.1.11" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/simple-git-linux-arm64-gnu@npm:0.1.11": + version: 0.1.11 + resolution: "@napi-rs/simple-git-linux-arm64-gnu@npm:0.1.11" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/simple-git-linux-arm64-musl@npm:0.1.11": + version: 0.1.11 + resolution: "@napi-rs/simple-git-linux-arm64-musl@npm:0.1.11" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/simple-git-linux-x64-gnu@npm:0.1.11": + version: 0.1.11 + resolution: "@napi-rs/simple-git-linux-x64-gnu@npm:0.1.11" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/simple-git-linux-x64-musl@npm:0.1.11": + version: 0.1.11 + resolution: "@napi-rs/simple-git-linux-x64-musl@npm:0.1.11" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/simple-git-win32-arm64-msvc@npm:0.1.11": + version: 0.1.11 + resolution: "@napi-rs/simple-git-win32-arm64-msvc@npm:0.1.11" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/simple-git-win32-x64-msvc@npm:0.1.11": + version: 0.1.11 + resolution: "@napi-rs/simple-git-win32-x64-msvc@npm:0.1.11" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/simple-git@npm:^0.1.11": + version: 0.1.11 + resolution: "@napi-rs/simple-git@npm:0.1.11" + dependencies: + "@napi-rs/simple-git-android-arm-eabi": "npm:0.1.11" + "@napi-rs/simple-git-android-arm64": "npm:0.1.11" + "@napi-rs/simple-git-darwin-arm64": "npm:0.1.11" + "@napi-rs/simple-git-darwin-x64": "npm:0.1.11" + "@napi-rs/simple-git-linux-arm-gnueabihf": "npm:0.1.11" + "@napi-rs/simple-git-linux-arm64-gnu": "npm:0.1.11" + "@napi-rs/simple-git-linux-arm64-musl": "npm:0.1.11" + "@napi-rs/simple-git-linux-x64-gnu": "npm:0.1.11" + "@napi-rs/simple-git-linux-x64-musl": "npm:0.1.11" + "@napi-rs/simple-git-win32-arm64-msvc": "npm:0.1.11" + "@napi-rs/simple-git-win32-x64-msvc": "npm:0.1.11" + dependenciesMeta: + "@napi-rs/simple-git-android-arm-eabi": + optional: true + "@napi-rs/simple-git-android-arm64": + optional: true + "@napi-rs/simple-git-darwin-arm64": + optional: true + "@napi-rs/simple-git-darwin-x64": + optional: true + "@napi-rs/simple-git-linux-arm-gnueabihf": + optional: true + "@napi-rs/simple-git-linux-arm64-gnu": + optional: true + "@napi-rs/simple-git-linux-arm64-musl": + optional: true + "@napi-rs/simple-git-linux-x64-gnu": + optional: true + "@napi-rs/simple-git-linux-x64-musl": + optional: true + "@napi-rs/simple-git-win32-arm64-msvc": + optional: true + "@napi-rs/simple-git-win32-x64-msvc": + optional: true + checksum: 5802a96fb4152d3fd6cc28ebea56fd363d7055bb7a185289dab33954980d7114ee174290b8d12f4b5630a97dc4a443d24e5873417a3f9aa6877a5d3ec2f62165 + languageName: node + linkType: hard + "@napi-rs/tar-android-arm-eabi@npm:0.1.0": version: 0.1.0 resolution: "@napi-rs/tar-android-arm-eabi@npm:0.1.0" @@ -10947,567 +11167,567 @@ __metadata: languageName: node linkType: hard -"@smithy/abort-controller@npm:^2.0.16": - version: 2.0.16 - resolution: "@smithy/abort-controller@npm:2.0.16" +"@smithy/abort-controller@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/abort-controller@npm:2.1.1" dependencies: - "@smithy/types": "npm:^2.8.0" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 3fa2db15cb247d63649ff95f676b4caf5ad311fc5103c432a9eb80ef3bafd1eaed688f926ae00f94e6965e959b6f52885eea29da367bc94b2d08df0f5cf5f778 + checksum: a35a94ed87980fb6c40ee44d2d6334fe6a0126de7192bd5d72aacb8caaa5580f92b3ce52609e55dc07c92ec0acf2df66fd9b314deb26538ff09c93f840b040c1 languageName: node linkType: hard -"@smithy/chunked-blob-reader-native@npm:^2.0.1": - version: 2.0.1 - resolution: "@smithy/chunked-blob-reader-native@npm:2.0.1" +"@smithy/chunked-blob-reader-native@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/chunked-blob-reader-native@npm:2.1.1" dependencies: - "@smithy/util-base64": "npm:^2.0.1" + "@smithy/util-base64": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: 3e3e1a9004336ab6853efe024aee053ee63e833b5f5e812d877fd4c7be74d7f8123c0352d749de77713d1152cf390991814c01e42d1ee5e349cf6816789a3109 + checksum: 3e4bfc4afe794e98fd9f0f6d8fa7eceea5fa79c330c42eb96d27d74d81d2fb65d89482e705e20537c68042688aa53c3c7b08743900eb8c06567fd9ac4b2f6368 languageName: node linkType: hard -"@smithy/chunked-blob-reader@npm:^2.0.0": - version: 2.0.0 - resolution: "@smithy/chunked-blob-reader@npm:2.0.0" +"@smithy/chunked-blob-reader@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/chunked-blob-reader@npm:2.1.1" dependencies: tslib: "npm:^2.5.0" - checksum: 3e35ce2bb2d8338f44b408958fd4b77054cb286b27730674a213d10b6ed84734889441d13dbdffb5f1971c61fe47c5f05703e5a93596ca0a6285937cd8b061cf + checksum: 130b8181184ed36f89e995870423b10e7730fe5f4ffc9ca3373e22a43f8195dbb5af230cae0bccd7b016d126796f742c3c44f51d21d08f178c541e767b71a9f4 languageName: node linkType: hard -"@smithy/config-resolver@npm:^2.0.23": - version: 2.0.23 - resolution: "@smithy/config-resolver@npm:2.0.23" +"@smithy/config-resolver@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/config-resolver@npm:2.1.1" dependencies: - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/types": "npm:^2.8.0" - "@smithy/util-config-provider": "npm:^2.1.0" - "@smithy/util-middleware": "npm:^2.0.9" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-config-provider": "npm:^2.2.1" + "@smithy/util-middleware": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: a590108883d6c56846e54b1e083484e7fb889d791121945b6508760d224c7f47fb78e6ae4cb927e73945d2854181bb33df7775fac95c3c0cb9ea9d3f27d95ed0 + checksum: eee4889ba8efd08d6d9e5b52360e2aebca03555a925a729269cbe83cb7a6a8d221c3e3382130382d8223aacdca6440fc05e56ae5e2c1805a41f8ae25d60fc732 languageName: node linkType: hard -"@smithy/core@npm:^1.2.2": - version: 1.2.2 - resolution: "@smithy/core@npm:1.2.2" +"@smithy/core@npm:^1.3.1": + version: 1.3.1 + resolution: "@smithy/core@npm:1.3.1" dependencies: - "@smithy/middleware-endpoint": "npm:^2.3.0" - "@smithy/middleware-retry": "npm:^2.0.26" - "@smithy/middleware-serde": "npm:^2.0.16" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/smithy-client": "npm:^2.2.1" - "@smithy/types": "npm:^2.8.0" - "@smithy/util-middleware": "npm:^2.0.9" + "@smithy/middleware-endpoint": "npm:^2.4.1" + "@smithy/middleware-retry": "npm:^2.1.1" + "@smithy/middleware-serde": "npm:^2.1.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/smithy-client": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-middleware": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: 4a6ff42aa0951f3e877b396dfd9d7f9c8bf28aa389bc7d19cc99fa6b9fab2edac069fc3c89beefa933f760362e5772d01ee46b7eaa79748f388e7d570403f40c + checksum: 80b200f556fc608f1fc5254a3ae0958bbf0d92c8ad7b71da437b509a3013395c4fe83f0f289a54726088aa5af5c1c712f7a9a4833c7b46c0b4020732f6b1c581 languageName: node linkType: hard -"@smithy/credential-provider-imds@npm:^2.0.0, @smithy/credential-provider-imds@npm:^2.1.5": - version: 2.1.5 - resolution: "@smithy/credential-provider-imds@npm:2.1.5" +"@smithy/credential-provider-imds@npm:^2.2.1": + version: 2.2.1 + resolution: "@smithy/credential-provider-imds@npm:2.2.1" dependencies: - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/property-provider": "npm:^2.0.17" - "@smithy/types": "npm:^2.8.0" - "@smithy/url-parser": "npm:^2.0.16" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/property-provider": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/url-parser": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: 829d1c1c37fa68aa4e1802e95f3ebd7f6ed9a30334890dd1a34225503afcb8a20723540a6bf1e763840bdf170c183677160436458083bb1c9ecd55562f007868 + checksum: 2e6ff2d96dbc27d9a3020d58b70423205c92c5a16bf5879182d1713f20212f8d7f97a6bdc769b3b04ef43869f605a1b6f6c889f6fa2a134105065309ef833f77 languageName: node linkType: hard -"@smithy/eventstream-codec@npm:^2.0.14, @smithy/eventstream-codec@npm:^2.0.16": - version: 2.0.16 - resolution: "@smithy/eventstream-codec@npm:2.0.16" +"@smithy/eventstream-codec@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/eventstream-codec@npm:2.1.1" dependencies: "@aws-crypto/crc32": "npm:3.0.0" - "@smithy/types": "npm:^2.8.0" - "@smithy/util-hex-encoding": "npm:^2.0.0" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-hex-encoding": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: c0fe19690bcb5f14b869841a2bde859894286d7eb2538146a3d12e6d957f36394bb90f38642ed5d35a88c66a4766a384c5d9b0ed3f22ead1c8fef1ec1531989b + checksum: 54c5051acbb41552d9a1436ed658fe56c36a3be2558ddcae73d3b909d908cdf73c5fe16f62e62a6daff338b429c614b758e743c7a56be9cd5876d2c1204f5351 languageName: node linkType: hard -"@smithy/eventstream-serde-browser@npm:^2.0.16": - version: 2.0.16 - resolution: "@smithy/eventstream-serde-browser@npm:2.0.16" +"@smithy/eventstream-serde-browser@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/eventstream-serde-browser@npm:2.1.1" dependencies: - "@smithy/eventstream-serde-universal": "npm:^2.0.16" - "@smithy/types": "npm:^2.8.0" + "@smithy/eventstream-serde-universal": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 7a8e5314a537e93f6a88df323d68ea5806cf659b07a586c86f359bf1b585f055de6d4d3f0c37d2e032d2aaa79015768c3f9d12a200ed49535d7134c72eed4cd2 + checksum: cbe857f80fb621bec432569b298785719f73dfe3a8e1763359a25a824463f35ad4355a87a04fe40475359a33d5ef1121785af3e01270ca684504f6fbf0edc02b languageName: node linkType: hard -"@smithy/eventstream-serde-config-resolver@npm:^2.0.16": - version: 2.0.16 - resolution: "@smithy/eventstream-serde-config-resolver@npm:2.0.16" +"@smithy/eventstream-serde-config-resolver@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/eventstream-serde-config-resolver@npm:2.1.1" dependencies: - "@smithy/types": "npm:^2.8.0" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 4ed2af1665f7e2238d644e5c0e085def68915d9ca7f76a825cecc084fb242486c07b9fca3b1c5c1138beeba64090ef95d2b1c7f038dacd0eb80a87a1c81a752c + checksum: 17be0e4a1c71a1927fa8a3d3dcd5718d6307c728fbdf5a72bd80b17bdb11c46adf5acbb6c161822c795dff24f534e914b725c4ff53b606bdcc2b5b7ee47b01fa languageName: node linkType: hard -"@smithy/eventstream-serde-node@npm:^2.0.16": - version: 2.0.16 - resolution: "@smithy/eventstream-serde-node@npm:2.0.16" +"@smithy/eventstream-serde-node@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/eventstream-serde-node@npm:2.1.1" dependencies: - "@smithy/eventstream-serde-universal": "npm:^2.0.16" - "@smithy/types": "npm:^2.8.0" + "@smithy/eventstream-serde-universal": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 83c21f0d38a70b5b76032341b04e62f1094d1f25cbcacc9c0875b3aa34e99d084ae6fd12ded0551bd040612be62b44ab2e5b1abc51e786319eb22c1c07f9d5a0 + checksum: 34224b488444bd5e095aa0b597a938dcab65e262dbe54056178f544bedec72ac78e3c1642287703efd9af1bd891c63db26dbcb1f394477e3b57f8160c8138fc7 languageName: node linkType: hard -"@smithy/eventstream-serde-universal@npm:^2.0.16": - version: 2.0.16 - resolution: "@smithy/eventstream-serde-universal@npm:2.0.16" +"@smithy/eventstream-serde-universal@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/eventstream-serde-universal@npm:2.1.1" dependencies: - "@smithy/eventstream-codec": "npm:^2.0.16" - "@smithy/types": "npm:^2.8.0" + "@smithy/eventstream-codec": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: fa35f3074547dac19476432c1abfb62b0b6432fc8c733aa5d8fb032c603fc35cf06bcf8b0559826e3108a0b67ec7986948f512efd4974e154cdbf88fbe1ae6a5 + checksum: ca52356375c9e7c701f3cd96179095435a37593edc84f55b686264b85825759d84827550db2f4644eb594ddb7cad24c54174581235ef189847574de27d520805 languageName: node linkType: hard -"@smithy/fetch-http-handler@npm:^2.3.2": - version: 2.3.2 - resolution: "@smithy/fetch-http-handler@npm:2.3.2" +"@smithy/fetch-http-handler@npm:^2.4.1": + version: 2.4.1 + resolution: "@smithy/fetch-http-handler@npm:2.4.1" dependencies: - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/querystring-builder": "npm:^2.0.16" - "@smithy/types": "npm:^2.8.0" - "@smithy/util-base64": "npm:^2.0.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/querystring-builder": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-base64": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: 0f64f8398f7e583390fc2fb967e55df4bc404a0d961353723095b18a2d64e65c72e58c20c6b33e42b1a62085ad39d67e804a6a4920b62ca9591c14bfe2803d65 + checksum: a91e454b70966d9b51bc762f065938bab51c86e0ff519ec09085a166a5b8d582d54f0bce5803c4f7df245255e6a822f8d5c15d70041d8a6c6be7714b32e8d489 languageName: node linkType: hard -"@smithy/hash-blob-browser@npm:^2.0.17": - version: 2.0.17 - resolution: "@smithy/hash-blob-browser@npm:2.0.17" +"@smithy/hash-blob-browser@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/hash-blob-browser@npm:2.1.1" dependencies: - "@smithy/chunked-blob-reader": "npm:^2.0.0" - "@smithy/chunked-blob-reader-native": "npm:^2.0.1" - "@smithy/types": "npm:^2.8.0" + "@smithy/chunked-blob-reader": "npm:^2.1.1" + "@smithy/chunked-blob-reader-native": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: a277c4c51ba05e78247f4979d1dccea1138c8fad85a59b4f25373737c607876e2b5f2af8d6b88b71a199ef73467e29a7305fe585da324a3d91e76d47a58c51bc + checksum: ff2537783211c65b6c57e21d605931c6715317b6644cdf19fd0a36d489b4cf3730a8a6dbe1ccc8d54301a5d575f63c14757b926652e719fef2b984557e6ad072 languageName: node linkType: hard -"@smithy/hash-node@npm:^2.0.18": - version: 2.0.18 - resolution: "@smithy/hash-node@npm:2.0.18" +"@smithy/hash-node@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/hash-node@npm:2.1.1" dependencies: - "@smithy/types": "npm:^2.8.0" - "@smithy/util-buffer-from": "npm:^2.0.0" - "@smithy/util-utf8": "npm:^2.0.2" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-buffer-from": "npm:^2.1.1" + "@smithy/util-utf8": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: ca85ebafafe6719f57a9dd784209aaef60295de6167f07dfbd764072d2e36327dcca088551180175faf528b9e3045ab600696934170d3ea256a5967383a1c53f + checksum: 66514402c338a25d52b000cc8d740696367c4fc230af4bac2124bf7c8bfd9f955fdee1becdf290f21b1153596b7288400407850beeb92f78d0e1107f6454faa3 languageName: node linkType: hard -"@smithy/hash-stream-node@npm:^2.0.18": - version: 2.0.18 - resolution: "@smithy/hash-stream-node@npm:2.0.18" +"@smithy/hash-stream-node@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/hash-stream-node@npm:2.1.1" dependencies: - "@smithy/types": "npm:^2.8.0" - "@smithy/util-utf8": "npm:^2.0.2" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-utf8": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: 7b6c2caeaf8fa6f1910a2b4c3aef7472073c9e1ec4446e8a4af16ff58f7cd8838e7c81ddf6f206c2a339988c9120f6cba4728fd008b6f47d00befd8f54e08751 + checksum: b5ea20b8446db158207ddcc0e6f70d3368bac42bad165d5e58053c69892472b0248099d6d4fb96ecec4b29a73a6a15074ebce528465438cac7516726c59a5ad9 languageName: node linkType: hard -"@smithy/invalid-dependency@npm:^2.0.16": - version: 2.0.16 - resolution: "@smithy/invalid-dependency@npm:2.0.16" +"@smithy/invalid-dependency@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/invalid-dependency@npm:2.1.1" dependencies: - "@smithy/types": "npm:^2.8.0" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 0055d593c20bc0e5d86836fee62c1fc41d236115c80b61d088186192c4438412136e7be5b1e8ab4207108882a51d337c7017574622e0f4837f538be4d1f8a74c + checksum: c0c6540a06df1b9ea24632a5a03b7a951a137f155484f11e0a82312814234c61f60e2c4d7c5ae2557af875a78c9fd6d5bc3d0ea17c7e873f2650ea6761c0c147 languageName: node linkType: hard -"@smithy/is-array-buffer@npm:^2.0.0": - version: 2.0.0 - resolution: "@smithy/is-array-buffer@npm:2.0.0" +"@smithy/is-array-buffer@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/is-array-buffer@npm:2.1.1" dependencies: tslib: "npm:^2.5.0" - checksum: 30f8e51403c52f27b5a6777e565128f2c8523d6e9a99f2005cdcaa31b7401376de77fa4a245de4a397d605af1cead8bea3189f3e7450386888e1656fe728030d + checksum: 0724355a8fa1e61c9fb77c6e6965cc7eae0cd561f158b768f8d1c9a26254db149bb545b318cdd81ebe383bbe5f26f6197b144c69e812dfd55f512e511e0ccbd8 languageName: node linkType: hard -"@smithy/md5-js@npm:^2.0.18": - version: 2.0.18 - resolution: "@smithy/md5-js@npm:2.0.18" +"@smithy/md5-js@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/md5-js@npm:2.1.1" dependencies: - "@smithy/types": "npm:^2.8.0" - "@smithy/util-utf8": "npm:^2.0.2" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-utf8": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: 471e7b3d4da5a72fd3632120df82feab20daecf5a67330b5e376bf5bbdd904c0d83768c8aea183e3287c1eea18de24ab9d145f6daf2b753139247a1b98c7fcd1 + checksum: 17a622b78263e230817a3793d2e89f602ce62be9badd4e855c39117cb21cb1c203173ff01f3c17b9424183a4b900a1693d7162fe4a6e5b0409480896d49e5e7e languageName: node linkType: hard -"@smithy/middleware-content-length@npm:^2.0.18": - version: 2.0.18 - resolution: "@smithy/middleware-content-length@npm:2.0.18" +"@smithy/middleware-content-length@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/middleware-content-length@npm:2.1.1" dependencies: - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/types": "npm:^2.8.0" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 84414174ecadcfeba5236bc9ab5d69c0b85b25b2356a6fc20472b9e1aba6c33750cdc3bd0fa508609a0616a69b88c2591515cf22ad499e33a3b10bf37e590f68 + checksum: ca871efeafd7009609e73012e3a0ec1ab28418c93f839814c22063e7fcf033fc9f68dd7e3a005a188c91e02d745b699898c78d17d83bf7483cba705453ce7545 languageName: node linkType: hard -"@smithy/middleware-endpoint@npm:^2.3.0": - version: 2.3.0 - resolution: "@smithy/middleware-endpoint@npm:2.3.0" +"@smithy/middleware-endpoint@npm:^2.4.1": + version: 2.4.1 + resolution: "@smithy/middleware-endpoint@npm:2.4.1" dependencies: - "@smithy/middleware-serde": "npm:^2.0.16" - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/shared-ini-file-loader": "npm:^2.2.8" - "@smithy/types": "npm:^2.8.0" - "@smithy/url-parser": "npm:^2.0.16" - "@smithy/util-middleware": "npm:^2.0.9" + "@smithy/middleware-serde": "npm:^2.1.1" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/shared-ini-file-loader": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/url-parser": "npm:^2.1.1" + "@smithy/util-middleware": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: 6a4a40755647afa24334de39faac340541bbcef60ef51ef65e6912b81cc44a45aefe8c189dabc8df80fab7288503fcb90eeed456a7aa8e33abc081c290beb057 + checksum: 4c23f4aac71e67f4bc4fded8cc033bfb881468d7c57e13927f32c554b77b62170057219751e1648a065630ceb4816321548a28f4e4b05a934f95f615bcfce887 languageName: node linkType: hard -"@smithy/middleware-retry@npm:^2.0.26": - version: 2.0.26 - resolution: "@smithy/middleware-retry@npm:2.0.26" +"@smithy/middleware-retry@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/middleware-retry@npm:2.1.1" dependencies: - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/service-error-classification": "npm:^2.0.9" - "@smithy/smithy-client": "npm:^2.2.1" - "@smithy/types": "npm:^2.8.0" - "@smithy/util-middleware": "npm:^2.0.9" - "@smithy/util-retry": "npm:^2.0.9" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/service-error-classification": "npm:^2.1.1" + "@smithy/smithy-client": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-middleware": "npm:^2.1.1" + "@smithy/util-retry": "npm:^2.1.1" tslib: "npm:^2.5.0" uuid: "npm:^8.3.2" - checksum: a615088a66392031cd6eac152bb7550232e5ec3bac53a7b19ac804a4e4fae128bcc3fbfc125bc3686585036056f5fee7520c986fa32b35071cfe69b786bec7a8 + checksum: da2b108c96c1d3c10b1b41f58be3ddf9358fc85547afb6f5a626145a48d06d1403ff0600b632db99879f4cedd7bcfd0dc25786d8d583c09b8369b408b7787a82 languageName: node linkType: hard -"@smithy/middleware-serde@npm:^2.0.16": - version: 2.0.16 - resolution: "@smithy/middleware-serde@npm:2.0.16" +"@smithy/middleware-serde@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/middleware-serde@npm:2.1.1" dependencies: - "@smithy/types": "npm:^2.8.0" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: d3b2ffafd106d2c4d9f5166411f70c9691c05a56d599c0a7d53d879d3d083f1940523c7fb8db509e65b79d11f4056e37ce8e776b607d6b479ef7ea8bacbd648c + checksum: 84fd7a65e1e0c425607e09d06feaf4a7b7e99d22aba41dab057f3ccdc9b04095c8cb65090c4b2d1781ebce653cd997cd1d99cb5112595fa39abf1d0dd5cf86bd languageName: node linkType: hard -"@smithy/middleware-stack@npm:^2.0.10": - version: 2.0.10 - resolution: "@smithy/middleware-stack@npm:2.0.10" +"@smithy/middleware-stack@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/middleware-stack@npm:2.1.1" dependencies: - "@smithy/types": "npm:^2.8.0" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: fcd8236988295b39f03f93c083a449202b28f5b7d7cd3992e6c4cdad429b5e8fbb4fe31d6d749d7524c3780d521a6df2ae7157ee904174b423af39b74ef2d5c5 + checksum: 4de8e63047cc0d54e84a66b505f16b7bde4d2c91feb5f3aa9e5ad5429c1d71cc82876418e3d07dd942b4bdb4715e31f38efa0df966d02b5c01ba57fca7473f00 languageName: node linkType: hard -"@smithy/node-config-provider@npm:^2.1.9": - version: 2.1.9 - resolution: "@smithy/node-config-provider@npm:2.1.9" - dependencies: - "@smithy/property-provider": "npm:^2.0.17" - "@smithy/shared-ini-file-loader": "npm:^2.2.8" - "@smithy/types": "npm:^2.8.0" - tslib: "npm:^2.5.0" - checksum: 32ef8d315096ddd728f00c3137a69c33438e27ea600ab9f0c720ad5535436357274399f0b5f6bc95fda02a0f30e77b6f8ef4ab7a5561b1723fcd1b422f88defa - languageName: node - linkType: hard - -"@smithy/node-http-handler@npm:^2.2.2": - version: 2.2.2 - resolution: "@smithy/node-http-handler@npm:2.2.2" - dependencies: - "@smithy/abort-controller": "npm:^2.0.16" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/querystring-builder": "npm:^2.0.16" - "@smithy/types": "npm:^2.8.0" - tslib: "npm:^2.5.0" - checksum: 545e306c879062753178d3671e4b68f5fe5384f14cab90a60567c680eecfbc8f2615966bf89d6d464f68b1d8d1606aaf7d548f03bfe8ef0d52869337afd30db2 - languageName: node - linkType: hard - -"@smithy/property-provider@npm:^2.0.0, @smithy/property-provider@npm:^2.0.17": - version: 2.0.17 - resolution: "@smithy/property-provider@npm:2.0.17" - dependencies: - "@smithy/types": "npm:^2.8.0" - tslib: "npm:^2.5.0" - checksum: f25ec4888b335c4a8ac38a78ee2ac12119ba1b717c8905856faf4041d003173dfaf3a484c651c17454705a61059abff7873fba5618ae2e5adab9234da9079233 - languageName: node - linkType: hard - -"@smithy/protocol-http@npm:^3.0.12": - version: 3.0.12 - resolution: "@smithy/protocol-http@npm:3.0.12" - dependencies: - "@smithy/types": "npm:^2.8.0" - tslib: "npm:^2.5.0" - checksum: 4fd205f54c9b17900a5b5135fc14d4b692ace53aba7d37cda18c42620d4380c46c93702d573debb2716207588295cee86640e9760cb8ca64dfb58a69898d2959 - languageName: node - linkType: hard - -"@smithy/querystring-builder@npm:^2.0.16": - version: 2.0.16 - resolution: "@smithy/querystring-builder@npm:2.0.16" - dependencies: - "@smithy/types": "npm:^2.8.0" - "@smithy/util-uri-escape": "npm:^2.0.0" - tslib: "npm:^2.5.0" - checksum: 8dc67e8e3e933fe2dfe3846b42ceba8c445a9054087ca37ec5b3cacd4c108dffcf17b87a89b5248528e8662603a719dcdac5c5951db8a02115a3eefa40ab0b89 - languageName: node - linkType: hard - -"@smithy/querystring-parser@npm:^2.0.16": - version: 2.0.16 - resolution: "@smithy/querystring-parser@npm:2.0.16" - dependencies: - "@smithy/types": "npm:^2.8.0" - tslib: "npm:^2.5.0" - checksum: 0c0f34fcdea223f2b96dba9cbae083b785d4518407ebfe0491a2932318c21cae52c210ce9727848a6f2b58817bef3186baebc5aab5845a2e7edf2a7981843789 - languageName: node - linkType: hard - -"@smithy/service-error-classification@npm:^2.0.9": - version: 2.0.9 - resolution: "@smithy/service-error-classification@npm:2.0.9" - dependencies: - "@smithy/types": "npm:^2.8.0" - checksum: 5eaa401dbb1ebf6e7f27c0f05d2720ce65f4520d14085f43ebfe3b6ae145ff04a3424fee11669e485cd221eb12b8c3f6a2dbf8dff804581d9705f767f1fd52d5 - languageName: node - linkType: hard - -"@smithy/shared-ini-file-loader@npm:^2.0.6, @smithy/shared-ini-file-loader@npm:^2.2.8": - version: 2.2.8 - resolution: "@smithy/shared-ini-file-loader@npm:2.2.8" - dependencies: - "@smithy/types": "npm:^2.8.0" - tslib: "npm:^2.5.0" - checksum: a6d9ee4e5929ce18447f9a852a83e86e73d5e119e059b47db1219753c54240130f0326ab11ef0fcf0b1c4c1cca6fdba0e9c8f28cb2dc2c9f55823fcd2621118e - languageName: node - linkType: hard - -"@smithy/signature-v4@npm:^2.0.0": - version: 2.0.16 - resolution: "@smithy/signature-v4@npm:2.0.16" - dependencies: - "@smithy/eventstream-codec": "npm:^2.0.14" - "@smithy/is-array-buffer": "npm:^2.0.0" - "@smithy/types": "npm:^2.6.0" - "@smithy/util-hex-encoding": "npm:^2.0.0" - "@smithy/util-middleware": "npm:^2.0.7" - "@smithy/util-uri-escape": "npm:^2.0.0" - "@smithy/util-utf8": "npm:^2.0.2" - tslib: "npm:^2.5.0" - checksum: d99bf7cdc1e4cb9a38bbc20c5fce285bc0b36be22a92f23c2f3fff217248c47f239e6a9bb41eea7d07a1f060a431691513e4f48887fad6ab51160bce2be03312 - languageName: node - linkType: hard - -"@smithy/smithy-client@npm:^2.2.1": +"@smithy/node-config-provider@npm:^2.2.1": version: 2.2.1 - resolution: "@smithy/smithy-client@npm:2.2.1" + resolution: "@smithy/node-config-provider@npm:2.2.1" dependencies: - "@smithy/middleware-endpoint": "npm:^2.3.0" - "@smithy/middleware-stack": "npm:^2.0.10" - "@smithy/protocol-http": "npm:^3.0.12" - "@smithy/types": "npm:^2.8.0" - "@smithy/util-stream": "npm:^2.0.24" + "@smithy/property-provider": "npm:^2.1.1" + "@smithy/shared-ini-file-loader": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 6e5d67d11e7c10db35604caf2dc4daa841f0b55b9f97092b34d819250737af8ca7a84a98870cbd249067c2aff478901b39dd16d9cecdaa9a53c1b2c58f8eb4f7 + checksum: 1122407d9bae623a2bc009acfd2ea3a2b047b5a455573fa811ba493d9b6b03093a8a77ff8277aa63289ea1ce14428e8ba3d89c21dd0b5629fc1f73d8ac6fd484 languageName: node linkType: hard -"@smithy/types@npm:^2.6.0, @smithy/types@npm:^2.8.0": - version: 2.8.0 - resolution: "@smithy/types@npm:2.8.0" +"@smithy/node-http-handler@npm:^2.3.1": + version: 2.3.1 + resolution: "@smithy/node-http-handler@npm:2.3.1" dependencies: + "@smithy/abort-controller": "npm:^2.1.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/querystring-builder": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 802ab14632d2e6a646d4d5e3edafde1dc0a066047140367176477e35645aebb568e4086080fe2758fcf713c102eebbc3e5d7097c0f6cb5b58e7da7da3e8d714f + checksum: 84e8c44b2f948e77fc96f327c72c8f8309dce410c398effd1bbdc7fb9e6f24364bed10fa6bd9feb119e4cdea7e76d03e3f3347bc2346fb2bf6d1aea4e2f36324 languageName: node linkType: hard -"@smithy/url-parser@npm:^2.0.16": - version: 2.0.16 - resolution: "@smithy/url-parser@npm:2.0.16" +"@smithy/property-provider@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/property-provider@npm:2.1.1" dependencies: - "@smithy/querystring-parser": "npm:^2.0.16" - "@smithy/types": "npm:^2.8.0" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: f9d6e65ee1cdcfa0f816c1c2c71988fd07d6abcc8d04e10cc05a8bf2c848656befb983a0c8118020e08e60e9704ba45436f7061a8717da8ac1f640e79aef9f95 + checksum: 74392f4814da0d5546cfacf6598f2c00d619fa0ddad8b7fe75c9fa0e0fc4708905e8062e3a3409a46eaf952fb8d21830ce85e05c796e7ee17c5d989cd663e93e languageName: node linkType: hard -"@smithy/util-base64@npm:^2.0.1": - version: 2.0.1 - resolution: "@smithy/util-base64@npm:2.0.1" +"@smithy/protocol-http@npm:^3.1.1": + version: 3.1.1 + resolution: "@smithy/protocol-http@npm:3.1.1" dependencies: - "@smithy/util-buffer-from": "npm:^2.0.0" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 6c71765396e7c36229f78b3ab7404d86390b4191350955b3af3ca6e3e42f67428801722706153f5593571be51f3b418843c49326d894cd4445eb9ed9a04844a7 + checksum: 4b3f0acfbab4690f0e00d649fc9a6ea2e14e4cbe9b6ffba9f09353c24979a52cea175ea56dd0c91542dbd966b82a20a529983f44f5e392a15e32c2b31661b262 languageName: node linkType: hard -"@smithy/util-body-length-browser@npm:^2.0.1": - version: 2.0.1 - resolution: "@smithy/util-body-length-browser@npm:2.0.1" +"@smithy/querystring-builder@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/querystring-builder@npm:2.1.1" dependencies: + "@smithy/types": "npm:^2.9.1" + "@smithy/util-uri-escape": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: fdeea18772d7d4542d0192a5cf9b145f7626b8ab76be57bd7453cb73d84480bb12f83b982467b7e4dc015434e16c9e3f7ffdffa0e4ba1c4f6e570c0425bee3d1 + checksum: 110d65892d7df181480ea6a6f8b276d10bac87b6c9a05f787a357712c039b18124ebad462852aaad4573d4fb925f4315ec5fc0389b784e73b57bbb2b24726a57 languageName: node linkType: hard -"@smithy/util-body-length-node@npm:^2.1.0": - version: 2.1.0 - resolution: "@smithy/util-body-length-node@npm:2.1.0" +"@smithy/querystring-parser@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/querystring-parser@npm:2.1.1" dependencies: + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 1b2e3a99811b623d68e800a4c400a0a55eb9ce12f5cfa5b8509a0fdd805a279a931759ff55472983b37dcbcc58221a3bbfef86e5e4304af973a1e2c5f8651078 + checksum: f6bc4e1f6aa5b76440b9b0b249093594f28a4136fc499f698c916df30cb3fb25860cc2f94e3508f39828d95eb0bff644ee9a2e209dbf6c84bf9baf4409a7d03d languageName: node linkType: hard -"@smithy/util-buffer-from@npm:^2.0.0": - version: 2.0.0 - resolution: "@smithy/util-buffer-from@npm:2.0.0" +"@smithy/service-error-classification@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/service-error-classification@npm:2.1.1" dependencies: - "@smithy/is-array-buffer": "npm:^2.0.0" - tslib: "npm:^2.5.0" - checksum: 15326acdb8666ff8c342bfa23ace07ea6a1b7e849b118f5b28f0b93cd775e83c77fa53ab5b04b8f795798d316991042296c3c5522fb68c91df9e921d4c83e398 + "@smithy/types": "npm:^2.9.1" + checksum: bd25500eb5a60aee36b51d6b5a0850f135b332b4cf5f42e35e88610fa695eb8c2f2ad012e244fb82327501b2eb143900026ba9b47365e5b93b4db5a860bf7eb6 languageName: node linkType: hard -"@smithy/util-config-provider@npm:^2.1.0": - version: 2.1.0 - resolution: "@smithy/util-config-provider@npm:2.1.0" +"@smithy/shared-ini-file-loader@npm:^2.3.1": + version: 2.3.1 + resolution: "@smithy/shared-ini-file-loader@npm:2.3.1" dependencies: + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 42f02104e24ae9deadf69b45c2ebee4b7a65a908b7ccfeb85bb6d1036032d36d1c044ff1eab25f43147dc02a15adb8a9f6517ed586a545d4a757985a1530d2ac + checksum: 451570089499a97cc279001433def396fc510a5ee0d2ed687575fc33c2475d0f7a094338a4c5c609e6115d824a2f89eafa34894aff20d054c308571116d7dd5f languageName: node linkType: hard -"@smithy/util-defaults-mode-browser@npm:^2.0.24": - version: 2.0.24 - resolution: "@smithy/util-defaults-mode-browser@npm:2.0.24" +"@smithy/signature-v4@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/signature-v4@npm:2.1.1" dependencies: - "@smithy/property-provider": "npm:^2.0.17" - "@smithy/smithy-client": "npm:^2.2.1" - "@smithy/types": "npm:^2.8.0" + "@smithy/eventstream-codec": "npm:^2.1.1" + "@smithy/is-array-buffer": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-hex-encoding": "npm:^2.1.1" + "@smithy/util-middleware": "npm:^2.1.1" + "@smithy/util-uri-escape": "npm:^2.1.1" + "@smithy/util-utf8": "npm:^2.1.1" + tslib: "npm:^2.5.0" + checksum: 4e4b4ae098af8ed9c09c024b489ef0b15bef3492cbd932ac0f4e59c6de9bc0ea59269baa75b4fe1cc90fdb904161067653da80dc884ca9e4f880f2bed2c8edd4 + languageName: node + linkType: hard + +"@smithy/smithy-client@npm:^2.3.1": + version: 2.3.1 + resolution: "@smithy/smithy-client@npm:2.3.1" + dependencies: + "@smithy/middleware-endpoint": "npm:^2.4.1" + "@smithy/middleware-stack": "npm:^2.1.1" + "@smithy/protocol-http": "npm:^3.1.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-stream": "npm:^2.1.1" + tslib: "npm:^2.5.0" + checksum: c5841a915d95ae3b4402b670f566c2eb78b4e01360d3ec3a54147cb2997e04b489ae7f3c28aea65e1d9c26e40ef17ee915422e91855976cc85a67af97e235f22 + languageName: node + linkType: hard + +"@smithy/types@npm:^2.9.1": + version: 2.9.1 + resolution: "@smithy/types@npm:2.9.1" + dependencies: + tslib: "npm:^2.5.0" + checksum: 82156919fd78814cfe988b8e0eea9d086134583e5d55501429a2cde6f0c5465cdbc274816162cdce3c19f5c81f7d8aed6c5d2edde3a214250760fce794efa4c2 + languageName: node + linkType: hard + +"@smithy/url-parser@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/url-parser@npm:2.1.1" + dependencies: + "@smithy/querystring-parser": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" + tslib: "npm:^2.5.0" + checksum: c6452f923176747fe49d16e449624b7e7436d789faa1d30b5f5b07fd31a66ff624a80210fe6420c840b01903efe2b2492da40dd92ec0818f0358f1c64e97c103 + languageName: node + linkType: hard + +"@smithy/util-base64@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/util-base64@npm:2.1.1" + dependencies: + "@smithy/util-buffer-from": "npm:^2.1.1" + tslib: "npm:^2.5.0" + checksum: 379aa5f1f1c4700e561767f8534ff3921bbacc8bb8afd915a22e242641bbb282ea6b5e19944c64ae014af56a7434354fe26f4387f3c75c5e4d692217ec423582 + languageName: node + linkType: hard + +"@smithy/util-body-length-browser@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/util-body-length-browser@npm:2.1.1" + dependencies: + tslib: "npm:^2.5.0" + checksum: 749b3fcc72f5df40be377e997537a90a67b75b304b14cf141112093a587916c670a6e52e1bb663fff74e8f31129884bc78779b00a2f3549f659815562a304e7a + languageName: node + linkType: hard + +"@smithy/util-body-length-node@npm:^2.2.1": + version: 2.2.1 + resolution: "@smithy/util-body-length-node@npm:2.2.1" + dependencies: + tslib: "npm:^2.5.0" + checksum: 7e8df29ea7f2c08022c4339480ebde68173fb8147082123309253a6aa9a11055fde649483d743cfbac69f0789630e12e8e5afd276f55efe6a9b20bdf0ec6732d + languageName: node + linkType: hard + +"@smithy/util-buffer-from@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/util-buffer-from@npm:2.1.1" + dependencies: + "@smithy/is-array-buffer": "npm:^2.1.1" + tslib: "npm:^2.5.0" + checksum: 5de4cf8b2d9c5347990be5791882947a509ba00a55ee67589f327e4852309dac5278248317929519f5a9d2aa5dc1c11cd54803db962287909e0322b7f73332bc + languageName: node + linkType: hard + +"@smithy/util-config-provider@npm:^2.2.1": + version: 2.2.1 + resolution: "@smithy/util-config-provider@npm:2.2.1" + dependencies: + tslib: "npm:^2.5.0" + checksum: bdca0bdf95cfaf67916e130356f80aa67555c1c423c0b98d283f2852782371b6fa09fee375a0a85eb43732a94733e0da7ad004b01f961dbd88f35a90258f0722 + languageName: node + linkType: hard + +"@smithy/util-defaults-mode-browser@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/util-defaults-mode-browser@npm:2.1.1" + dependencies: + "@smithy/property-provider": "npm:^2.1.1" + "@smithy/smithy-client": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" bowser: "npm:^2.11.0" tslib: "npm:^2.5.0" - checksum: b8cf6f1fecd5765d55557b7656b12a12e8468b9f343ef04dfdededba9d8894172933201ee922547ee5025ba1ca979db2071e6588f9b6df16797087ab065b5690 + checksum: 945ad1472d79d6e85cff706bd7fab7b628b54e112fd1891013a0bc600ed38a762425e1e995d3b67f730434445d428f95165d3cb9cfd20bfcb416c9ca610c5b52 languageName: node linkType: hard -"@smithy/util-defaults-mode-node@npm:^2.0.32": - version: 2.0.32 - resolution: "@smithy/util-defaults-mode-node@npm:2.0.32" +"@smithy/util-defaults-mode-node@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/util-defaults-mode-node@npm:2.1.1" dependencies: - "@smithy/config-resolver": "npm:^2.0.23" - "@smithy/credential-provider-imds": "npm:^2.1.5" - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/property-provider": "npm:^2.0.17" - "@smithy/smithy-client": "npm:^2.2.1" - "@smithy/types": "npm:^2.8.0" + "@smithy/config-resolver": "npm:^2.1.1" + "@smithy/credential-provider-imds": "npm:^2.2.1" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/property-provider": "npm:^2.1.1" + "@smithy/smithy-client": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: d25372e50f91f593ca38c6d2cb722b0d87d6a0334de57d90fdd7364ef91fff227f19579a1734d6fcbd19a60563757ed9ff1afce4eeaf257d915876f832bed2fc + checksum: f51ca2872b338eadcf685ca818372abe2ccd6d1d0599b302c46fc9700ef667b34290da1dc67f3f32442dcc7234b2f3729e91de20f3a5741a5af7aacac87d3d22 languageName: node linkType: hard -"@smithy/util-endpoints@npm:^1.0.8": - version: 1.0.8 - resolution: "@smithy/util-endpoints@npm:1.0.8" +"@smithy/util-endpoints@npm:^1.1.1": + version: 1.1.1 + resolution: "@smithy/util-endpoints@npm:1.1.1" dependencies: - "@smithy/node-config-provider": "npm:^2.1.9" - "@smithy/types": "npm:^2.8.0" + "@smithy/node-config-provider": "npm:^2.2.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 09cdf2178131c323bd69000af9c5ea93654036ccaa04d963f67d86c87bb84875b070b71a6e07e809c30fb7cf1629c9e538516a00cb103f55ba22f2b58ebe0e07 + checksum: 9119baa6f4a3ec89eb424b500ad0bfe635a91be57e1fcb8e5785f12c567d4b12a0310a686bbb44bfce4a5d64c810ef60c67d43d9d0cfaff3b128612e274dae1e languageName: node linkType: hard -"@smithy/util-hex-encoding@npm:^2.0.0": - version: 2.0.0 - resolution: "@smithy/util-hex-encoding@npm:2.0.0" +"@smithy/util-hex-encoding@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/util-hex-encoding@npm:2.1.1" dependencies: tslib: "npm:^2.5.0" - checksum: 196b594d5e4a31fbc6a6ada8e1af307e0af55721685df70e20415733f46d6d2d6f7c52f9d2bf4512f0033cc1adb74f115c68025d9b7d7023342ef6f0514cee2a + checksum: df805a72f6d28fc081c4080f0a9c67f1fa3416f40b45f7491990b10b9ee044c3141fb1963bbdfe03cf599c5fe8bd3ed856f1463c6917a0d9f647bd1f37c72514 languageName: node linkType: hard -"@smithy/util-middleware@npm:^2.0.7, @smithy/util-middleware@npm:^2.0.9": - version: 2.0.9 - resolution: "@smithy/util-middleware@npm:2.0.9" +"@smithy/util-middleware@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/util-middleware@npm:2.1.1" dependencies: - "@smithy/types": "npm:^2.8.0" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 1d379da341488d8d9af31d2b589b2875afa6c12a977934b135fdada30e75eace64fea3b673d090aeb8976d21a836cb146603e88c84b44b39a0547ea7eaa10c94 + checksum: 80067715932c4c90ed79ce10e7cf5906c43f604be7a893a735c66e1d464299fcd4493c7ad6a8f9124f40e509e9f9131dd87a22bd5ed7b7a0d8ab831ffd1fb491 languageName: node linkType: hard -"@smithy/util-retry@npm:^2.0.9": - version: 2.0.9 - resolution: "@smithy/util-retry@npm:2.0.9" +"@smithy/util-retry@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/util-retry@npm:2.1.1" dependencies: - "@smithy/service-error-classification": "npm:^2.0.9" - "@smithy/types": "npm:^2.8.0" + "@smithy/service-error-classification": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: f28f1215cbe2c0eab5de65db21d13092b6b81ac807c08c491c36db9f68e8b1598e4f53f9536299aa770c115cd67bae8d10b1151ff7e253563bc1323ae9a9276e + checksum: b3b2d11cd0579345eb94a73ffd98e8e9cd9b9d64ad3dee12680589018d54f1ac032e72725e4100ff06c59914b8b491b12820fb1003775062d22bf2fa5430cae3 languageName: node linkType: hard -"@smithy/util-stream@npm:^2.0.24": - version: 2.0.24 - resolution: "@smithy/util-stream@npm:2.0.24" +"@smithy/util-stream@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/util-stream@npm:2.1.1" dependencies: - "@smithy/fetch-http-handler": "npm:^2.3.2" - "@smithy/node-http-handler": "npm:^2.2.2" - "@smithy/types": "npm:^2.8.0" - "@smithy/util-base64": "npm:^2.0.1" - "@smithy/util-buffer-from": "npm:^2.0.0" - "@smithy/util-hex-encoding": "npm:^2.0.0" - "@smithy/util-utf8": "npm:^2.0.2" + "@smithy/fetch-http-handler": "npm:^2.4.1" + "@smithy/node-http-handler": "npm:^2.3.1" + "@smithy/types": "npm:^2.9.1" + "@smithy/util-base64": "npm:^2.1.1" + "@smithy/util-buffer-from": "npm:^2.1.1" + "@smithy/util-hex-encoding": "npm:^2.1.1" + "@smithy/util-utf8": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: fa22edcd38385a5b261a678cef976eb24652f0a29f566e79a7503b04a44b698422ba975a27808e11e28f5a61d9d276dae3141cd9bb201ca7e618b74e15ae6a83 + checksum: dc490f6eb5e22ff24afcb374d30002ed404b00044534565813dd567ea3f76d9f473052878a7d5f660c78690600f562c85b1deed549cd494b8531b911ac9b1a74 languageName: node linkType: hard -"@smithy/util-uri-escape@npm:^2.0.0": - version: 2.0.0 - resolution: "@smithy/util-uri-escape@npm:2.0.0" +"@smithy/util-uri-escape@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/util-uri-escape@npm:2.1.1" dependencies: tslib: "npm:^2.5.0" - checksum: 2f121d1fce9878e22fc5eaa0f8f4e47e967fce6d727b4283902d842842c7835b47de08e16b2c6fef389457a6edf2523274019fe511ede98ce0f38a11aea63bc2 + checksum: ca232b27b0ef25b3e3eca141454db1cc6d01b999b57b6b176c2af6578c38dbd1df5cb3d6984f0a30c55ea10b4e7d4e7758387da8ee674de91897b2c632a92995 languageName: node linkType: hard -"@smithy/util-utf8@npm:^2.0.2": - version: 2.0.2 - resolution: "@smithy/util-utf8@npm:2.0.2" +"@smithy/util-utf8@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/util-utf8@npm:2.1.1" dependencies: - "@smithy/util-buffer-from": "npm:^2.0.0" + "@smithy/util-buffer-from": "npm:^2.1.1" tslib: "npm:^2.5.0" - checksum: 9356200ac7ccef414cd924b4fd2bfeb1d0a2e7992b4c924f0328205ab9bb8c688bc4b5c271c237db90ea75fb448f32c1f76c6e8883c2f088ea0559737ea99d9d + checksum: 736992921e50c2c96234dc5eab305a30d29b1cfa29ce5ad2ec0e4b3f2e0dc3e2d29303bd1362bd20fa2e66c5fd494c558f4b1050b91ead5e13a479903bb9686f languageName: node linkType: hard -"@smithy/util-waiter@npm:^2.0.16": - version: 2.0.16 - resolution: "@smithy/util-waiter@npm:2.0.16" +"@smithy/util-waiter@npm:^2.1.1": + version: 2.1.1 + resolution: "@smithy/util-waiter@npm:2.1.1" dependencies: - "@smithy/abort-controller": "npm:^2.0.16" - "@smithy/types": "npm:^2.8.0" + "@smithy/abort-controller": "npm:^2.1.1" + "@smithy/types": "npm:^2.9.1" tslib: "npm:^2.5.0" - checksum: 91cff83f1450cc761ec8a7b77c09af5ffa10619f40d560fd3f14633b63486dad2c274df7fc44fbd80c6e2ea4ec8b0514990ff8b989afa50467296e8cdada611b + checksum: 78aab62c873606478c2e8f0ebae9d02ee7dedd65ea1409aaf2f89ee7dd6cebafe249e6a8f1ed9d86d390bdd75dde068a49fb4bf69d62a3506ef2f36ed7bf62cf languageName: node linkType: hard @@ -12824,11 +13044,11 @@ __metadata: "@affine/debug": "workspace:*" "@affine/env": "workspace:*" "@affine/templates": "workspace:*" - "@blocksuite/blocks": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/lit": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/presets": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" + "@blocksuite/blocks": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/global": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/lit": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/presets": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/store": "npm:0.12.0-nightly-202401290223-b6302df" async-call-rpc: "npm:^6.3.1" jotai: "npm:^2.5.1" jotai-effect: "npm:^0.2.3" @@ -12875,9 +13095,9 @@ __metadata: version: 0.0.0-use.local resolution: "@toeverything/y-indexeddb@workspace:packages/common/y-indexeddb" dependencies: - "@blocksuite/blocks": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/global": "npm:0.12.0-nightly-202401240410-02f373e" - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" + "@blocksuite/blocks": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/global": "npm:0.12.0-nightly-202401290223-b6302df" + "@blocksuite/store": "npm:0.12.0-nightly-202401290223-b6302df" fake-indexeddb: "npm:^5.0.0" idb: "npm:^8.0.0" nanoid: "npm:^5.0.3" @@ -22604,12 +22824,12 @@ __metadata: languageName: node linkType: hard -"husky@npm:^8.0.3": - version: 8.0.3 - resolution: "husky@npm:8.0.3" +"husky@npm:^9.0.6": + version: 9.0.6 + resolution: "husky@npm:9.0.6" bin: - husky: lib/bin.js - checksum: b754cf70fdc97c3b60fec5b80056b9c11436464953b1691bf2b5dcf0081fb6685d2c5f47abb8b2b1c49f504aabea5321fdd6496f8b755d9f6e7525a493406abb + husky: bin.js + checksum: e198c90a59d460cf860c33e0a4c3927ecfb645d4fd4c2de3fbcd5fb56b858a923af452508d549f6ed020bb48de08290912cd77c006dd2a83e551c24c17340d5b languageName: node linkType: hard @@ -35284,7 +35504,7 @@ __metadata: version: 0.0.0-use.local resolution: "y-provider@workspace:packages/common/y-provider" dependencies: - "@blocksuite/store": "npm:0.12.0-nightly-202401240410-02f373e" + "@blocksuite/store": "npm:0.12.0-nightly-202401290223-b6302df" vite: "npm:^5.0.6" vite-plugin-dts: "npm:3.7.0" vitest: "npm:1.1.3"