From 04a9c52d48aa9ee087533a72fcd6e25e3a12878e Mon Sep 17 00:00:00 2001 From: Andrey Sobolev Date: Wed, 10 Sep 2025 02:00:08 +0700 Subject: [PATCH 1/2] qfix: Fix github measurements (#9816) 1. Fix github measurements 2. A bit more proper fix for caching of Octokit references Signed-off-by: Andrey Sobolev --- services/github/pod-github/src/platform.ts | 7 +- .../github/pod-github/src/sync/comments.ts | 10 +- .../github/pod-github/src/sync/issueBase.ts | 76 ++++++----- services/github/pod-github/src/sync/issues.ts | 40 +++--- .../pod-github/src/sync/pullrequests.ts | 25 ++-- .../pod-github/src/sync/reviewComments.ts | 15 ++- .../pod-github/src/sync/reviewThreads.ts | 11 +- .../github/pod-github/src/sync/reviews.ts | 20 ++- services/github/pod-github/src/sync/utils.ts | 21 ++- services/github/pod-github/src/types.ts | 2 + services/github/pod-github/src/users.ts | 9 ++ services/github/pod-github/src/worker.ts | 126 +++++++++++------- 12 files changed, 238 insertions(+), 124 deletions(-) diff --git a/services/github/pod-github/src/platform.ts b/services/github/pod-github/src/platform.ts index db46bcc20c..36892bb5d3 100644 --- a/services/github/pod-github/src/platform.ts +++ b/services/github/pod-github/src/platform.ts @@ -90,7 +90,7 @@ export class PlatformWorker { readonly ctx: MeasureContext, readonly app: App, readonly brandingMap: BrandingMap, - readonly periodicSyncInterval = 10 * 60 * 1000 // 10 minutes + readonly periodicSyncInterval = 24 * 60 * 60 * 1000 // 24 hours ) { registerLoaders() } @@ -732,7 +732,7 @@ export class PlatformWorker { } } - async checkRefreshToken (ctx: MeasureContext, auth: GithubUserRecord, force: boolean = false): Promise { + async checkRefreshToken (ctx: MeasureContext, auth: GithubUserRecord, force: boolean = false): Promise { if (auth.refreshToken != null && auth.expiresIn != null && auth.expiresIn < Date.now() / 1000) { const uri = 'https://github.com/login/oauth/access_token?' + @@ -754,6 +754,7 @@ export class PlatformWorker { if (resultJson.error !== undefined) { // We need to clear github integration info. await this.revokeUserAuth(ctx, auth) + return false } else { // Update okit const nowTime = Date.now() / 1000 @@ -774,8 +775,10 @@ export class PlatformWorker { auth.scope = dta.scope await this.userManager.updateUser(dta) + return true } } + return true } async getAccount (login: string): Promise { diff --git a/services/github/pod-github/src/sync/comments.ts b/services/github/pod-github/src/sync/comments.ts index baf8ebf439..c5dfe2f39d 100644 --- a/services/github/pod-github/src/sync/comments.ts +++ b/services/github/pod-github/src/sync/comments.ts @@ -80,8 +80,14 @@ export class CommentSyncManager implements DocSyncManager { await this.eventSync.get(event.issue.url) const promise = this.processEvent(ctx, event, derivedClient, integration) this.eventSync.set(event.issue.url, promise) - await promise - this.eventSync.delete(event.issue.url) + try { + await promise + this.eventSync.delete(event.issue.url) + } catch (err: any) { + ctx.error('Error processing event', { error: err }) + } finally { + this.eventSync.delete(event.issue.url) + } } async handleDelete ( diff --git a/services/github/pod-github/src/sync/issueBase.ts b/services/github/pod-github/src/sync/issueBase.ts index 0ef7e42bcb..1cd2872dd0 100644 --- a/services/github/pod-github/src/sync/issueBase.ts +++ b/services/github/pod-github/src/sync/issueBase.ts @@ -22,7 +22,8 @@ import core, { Ref, Space, TxOperations, - makeDocCollabId + makeDocCollabId, + withContext } from '@hcengineering/core' import github, { DocSyncInfo, GithubIntegrationRepository, GithubIssue, GithubProject } from '@hcengineering/github' import { IntlString } from '@hcengineering/platform' @@ -112,6 +113,7 @@ export abstract class IssueSyncManagerBase { return socialIds.map((it) => it.attachedTo) } + @withContext('issues-handleUpdate') async handleUpdate ( ctx: MeasureContext, external: IssueExternalData, @@ -135,12 +137,16 @@ export abstract class IssueSyncManagerBase { syncData = syncData ?? - (await this.client.findOne(github.class.DocSyncInfo, { space: prj._id, url: (external.url ?? '').toLowerCase() })) + (await ctx.with('findDocInfo', {}, (ctx) => + this.client.findOne(github.class.DocSyncInfo, { space: prj._id, url: (external.url ?? '').toLowerCase() }) + )) if (syncData !== undefined) { - const doc: Issue | undefined = await this.client.findOne(syncData.objectClass, { - _id: syncData._id as unknown as Ref - }) + const doc: Issue | undefined = await ctx.with('find pull request', {}, (ctx) => + this.client.findOne(syncData.objectClass, { + _id: syncData._id as unknown as Ref + }) + ) // Use now as modified date for events. const lastModified = new Date().getTime() @@ -153,6 +159,7 @@ export abstract class IssueSyncManagerBase { ) { try { const collabId = makeDocCollabId(doc, 'description') + await this.collaborator.updateMarkup(collabId, update.description) } catch (err: any) { Analytics.handleError(err) @@ -184,35 +191,39 @@ export abstract class IssueSyncManagerBase { await updateTodos.commit() } - await derivedClient.diffUpdate( - syncData, - { - external, - externalVersion: githubExternalSyncVersion, - current: { ...syncData.current, ...update }, - needSync: needSync ? '' : githubSyncVersion, // No need to sync after operation. - derivedVersion: '', // Check derived changes - lastModified, - lastGithubUser: account, - ...extraSyncUpdate - }, - lastModified + await ctx.with('diffUpdate syncData', {}, (ctx) => + derivedClient.diffUpdate( + syncData, + { + external, + externalVersion: githubExternalSyncVersion, + current: { ...syncData.current, ...update }, + needSync: needSync ? '' : githubSyncVersion, // No need to sync after operation. + derivedVersion: '', // Check derived changes + lastModified, + lastGithubUser: account, + ...extraSyncUpdate + }, + lastModified + ) ) - await this.client.diffUpdate(doc, issueData, lastModified, account) + await ctx.with('diffUpdate-issue', {}, (ctx) => this.client.diffUpdate(doc, issueData, lastModified, account)) this.provider.sync() } else if (doc === undefined) { - await derivedClient.diffUpdate( - syncData, - { - external, - externalVersion: githubExternalSyncVersion, - needSync: '', - derivedVersion: '', // Check derived changes - lastModified, - lastGithubUser: account, - ...extraSyncUpdate - }, - lastModified + await ctx.with('diffUpdate-syncData', {}, (ctx) => + derivedClient.diffUpdate( + syncData, + { + external, + externalVersion: githubExternalSyncVersion, + needSync: '', + derivedVersion: '', // Check derived changes + lastModified, + lastGithubUser: account, + ...extraSyncUpdate + }, + lastModified + ) ) } } @@ -267,6 +278,7 @@ export abstract class IssueSyncManagerBase { info: DocSyncInfo ): Promise + @withContext('issues-handleDiffUpdate') async handleDiffUpdate ( ctx: MeasureContext, container: ContainerFocus, @@ -282,7 +294,7 @@ export abstract class IssueSyncManagerBase { await ctx.with( 'create mixin issue: GithubIssue', {}, - async () => { + async (ctx) => { await this.client.createMixin( existing._id as Ref, existing._class, diff --git a/services/github/pod-github/src/sync/issues.ts b/services/github/pod-github/src/sync/issues.ts index 19410d4249..84d9ac68db 100644 --- a/services/github/pod-github/src/sync/issues.ts +++ b/services/github/pod-github/src/sync/issues.ts @@ -111,11 +111,16 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan const urlId = issueEvent.issue.url await syncRunner.exec(urlId, async () => { - await this.processEvent(ctx, issueEvent, derivedClient, repository, integration, project) + try { + await this.processEvent(ctx, issueEvent, derivedClient, repository, integration, project) + } catch (err: any) { + ctx.error('Error processing event', { error: err }) + } }) } } + @withContext('issues-processEvent') private async processEvent ( ctx: MeasureContext, event: IssuesEvent, @@ -129,8 +134,9 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan let externalData: IssueExternalData | undefined if (event.action !== 'deleted') { try { - const response: any = await integration.octokit?.graphql( - `query listIssue($name: String!, $owner: String!, $issue: Int!) { + const response: any = await ctx.with('graphql', {}, (ctx) => + integration.octokit?.graphql( + `query listIssue($name: String!, $owner: String!, $issue: Int!) { repository(name: $name, owner: $owner) { issue(number: $issue) { ${issueDetails(true)} @@ -138,11 +144,12 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan } } `, - { - name: repo.name, - owner: repo.owner?.login, - issue: event.issue.number - } + { + name: repo.name, + owner: repo.owner?.login, + issue: event.issue.number + } + ) ) externalData = response.repository.issue } catch (err: any) { @@ -351,7 +358,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan const description = await ctx.with( 'query collaborative description', {}, - async () => { + async (ctx) => { const collabId = makeDocCollabId(existing, 'description') return await this.collaborator.getMarkup(collabId, (existing as Issue).description) }, @@ -367,7 +374,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan const createdIssueData = await ctx.with( 'create github issue', {}, - async () => { + async (ctx) => { this.createPromise = this.createGithubIssue( ctx, container, @@ -501,10 +508,11 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan await ctx.with( 'create platform issue', {}, - async () => { + async (ctx) => { const st = (await guessStatus(issueExternal, statuses))._id as Ref await this.createNewIssue( + ctx, info, accountGH, { @@ -555,7 +563,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan const updateResult = await ctx.with( 'diff update', {}, - async () => + async (ctx) => await this.handleDiffUpdate( ctx, container, @@ -655,7 +663,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan await ctx.with( '==> updateIssue', {}, - async () => { + async (ctx) => { ctx.info('update fields', { url: issueExternal.url, ...issueUpdate, @@ -696,7 +704,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan await ctx.with( '==> updateIssue', {}, - async () => { + async (ctx) => { ctx.info('update fields', { ...issueUpdate, workspace: this.provider.getWorkspaceId() }) if (isGHWriteAllowed()) { const hasOtherChanges = Object.keys(issueUpdate).length > 0 @@ -807,7 +815,9 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan } } + @withContext('issues-createNewIssue') private async createNewIssue ( + ctx: MeasureContext, info: DocSyncInfo, account: PersonId, issueData: GithubIssueData & { status: Issue['status'] }, @@ -930,7 +940,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan const response: any = await ctx.with( 'graphql.listIssue', {}, - () => + (ctx) => integration.octokit.graphql( `query listIssues { nodes(ids: [${idsp}] ) { diff --git a/services/github/pod-github/src/sync/pullrequests.ts b/services/github/pod-github/src/sync/pullrequests.ts index 314a6e9750..a179b18fc5 100644 --- a/services/github/pod-github/src/sync/pullrequests.ts +++ b/services/github/pod-github/src/sync/pullrequests.ts @@ -122,11 +122,16 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS const url = event.pull_request.issue_url await syncRunner.exec(url, async () => { - await this.processEvent(ctx, event, derivedClient, repository, integration, project) + try { + await this.processEvent(ctx, event, derivedClient, repository, integration, project) + } catch (err: any) { + ctx.error('Error processing event', { error: err }) + } }) } } + @withContext('pullrequests-processEvent') private async processEvent ( ctx: MeasureContext, event: PullRequestEvent, @@ -139,8 +144,9 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS let externalData: PullRequestExternalData try { - const response: any = await integration.octokit?.graphql( - `query listIssue($name: String!, $owner: String!, $issue: Int!) { + const response: any = await ctx.with('graphql', {}, (ctx) => + integration.octokit?.graphql( + `query listIssue($name: String!, $owner: String!, $issue: Int!) { repository(name: $name, owner: $owner) { pullRequest(number: $issue) { ${pullRequestDetails} @@ -148,11 +154,12 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS } } `, - { - name: repo.name, - owner: repo.owner?.login, - issue: event.pull_request.number - } + { + name: repo.name, + owner: repo.owner?.login, + issue: event.pull_request.number + } + ) ) externalData = response.repository.pullRequest } catch (err: any) { @@ -496,7 +503,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS } // To sync reviews/review threads in case they are created before us. - await syncChilds(info, this.client, derivedClient) + await syncChilds(ctx, info, this.client, derivedClient) return { needSync: '', diff --git a/services/github/pod-github/src/sync/reviewComments.ts b/services/github/pod-github/src/sync/reviewComments.ts index 5cf98b349b..5685daf810 100644 --- a/services/github/pod-github/src/sync/reviewComments.ts +++ b/services/github/pod-github/src/sync/reviewComments.ts @@ -88,8 +88,13 @@ export class ReviewCommentSyncManager implements DocSyncManager { await this.eventSync.get(event.comment.html_url) const promise = this.processEvent(ctx, event, derivedClient, repository, integration) this.eventSync.set(event.comment.html_url, promise) - await promise - this.eventSync.delete(event.comment.html_url) + try { + await promise + } catch (err: any) { + ctx.error('Error processing event', { error: err }) + } finally { + this.eventSync.delete(event.comment.html_url) + } } async handleDelete ( @@ -364,7 +369,7 @@ export class ReviewCommentSyncManager implements DocSyncManager { } if (existing === undefined) { try { - await this.createReviewComment(info, messageData, parent, reviewComment, account) + await this.createReviewComment(ctx, info, messageData, parent, reviewComment, account) return { needSync: githubSyncVersion, current: messageData } } catch (err: any) { ctx.error('Error', { err }) @@ -387,6 +392,7 @@ export class ReviewCommentSyncManager implements DocSyncManager { return { current: messageData, needSync: githubSyncVersion } } + @withContext('handleDiffUpdate-comment') private async handleDiffUpdate ( ctx: MeasureContext, existing: Doc, @@ -458,7 +464,9 @@ export class ReviewCommentSyncManager implements DocSyncManager { } } + @withContext('review-comments-createReviewComment') private async createReviewComment ( + ctx: MeasureContext, info: DocSyncInfo, messageData: ReviewCommentData, parent: DocSyncInfo, @@ -482,6 +490,7 @@ export class ReviewCommentSyncManager implements DocSyncManager { ) } + @withContext('review-comments-create') async createGithubReviewComment ( ctx: MeasureContext, container: ContainerFocus, diff --git a/services/github/pod-github/src/sync/reviewThreads.ts b/services/github/pod-github/src/sync/reviewThreads.ts index b146b0dcb3..762392f159 100644 --- a/services/github/pod-github/src/sync/reviewThreads.ts +++ b/services/github/pod-github/src/sync/reviewThreads.ts @@ -108,8 +108,13 @@ export class ReviewThreadSyncManager implements DocSyncManager { await this.eventSync.get(event.thread.node_id) const promise = this.processEvent(ctx, event, derivedClient, repository, integration) this.eventSync.set(event.thread.node_id, promise) - await promise - this.eventSync.delete(event.thread.node_id) + try { + await promise + } catch (err: any) { + ctx.error('Error processing event', { error: err }) + } finally { + this.eventSync.delete(event.thread.node_id) + } } async handleDelete ( @@ -311,7 +316,7 @@ export class ReviewThreadSyncManager implements DocSyncManager { await this.createReviewThread(info, messageData, parent, review, account) // We need trigger comments, if their sync data created before - await syncChilds(info, this.client, derivedClient) + await syncChilds(ctx, info, this.client, derivedClient) return { needSync: githubSyncVersion, current: messageData } } catch (err: any) { ctx.error('Error', { err }) diff --git a/services/github/pod-github/src/sync/reviews.ts b/services/github/pod-github/src/sync/reviews.ts index cee3e178ee..5361480787 100644 --- a/services/github/pod-github/src/sync/reviews.ts +++ b/services/github/pod-github/src/sync/reviews.ts @@ -86,8 +86,13 @@ export class ReviewSyncManager implements DocSyncManager { await this.eventSync.get(event.review.html_url) const promise = this.processEvent(ctx, event, derivedClient, repository, integration) this.eventSync.set(event.review.html_url, promise) - await promise - this.eventSync.delete(event.review.html_url) + try { + await promise + } catch (err: any) { + ctx.error('Error processing event', { error: err }) + } finally { + this.eventSync.delete(event.review.html_url) + } } async handleDelete ( @@ -318,9 +323,9 @@ export class ReviewSyncManager implements DocSyncManager { } if (existing === undefined) { try { - await this.createReview(info, messageData, parent, review, account) + await this.createReview(ctx, info, messageData, parent, review, account) - await syncChilds(info, this.client, derivedClient) + await syncChilds(ctx, info, this.client, derivedClient) return { needSync: githubSyncVersion, current: messageData } } catch (err: any) { ctx.error('Error', { err }) @@ -328,12 +333,14 @@ export class ReviewSyncManager implements DocSyncManager { return { needSync: githubSyncVersion, error: errorToObj(err) } } } else { - await this.handleDiffUpdate(existing, info, messageData, container, parent, review, account) + await this.handleDiffUpdate(ctx, existing, info, messageData, container, parent, review, account) } return { current: messageData, needSync: githubSyncVersion } } + @withContext('reviews-handleDiffUpdate') private async handleDiffUpdate ( + ctx: MeasureContext, existing: Doc, info: DocSyncInfo, reviewData: ReviewData, @@ -379,7 +386,9 @@ export class ReviewSyncManager implements DocSyncManager { } } + @withContext('reviews-createReview') private async createReview ( + ctx: MeasureContext, info: DocSyncInfo, messageData: ReviewData, parent: DocSyncInfo, @@ -403,6 +412,7 @@ export class ReviewSyncManager implements DocSyncManager { ) } + @withContext('reviews-createGithubReview') async createGithubReview ( ctx: MeasureContext, container: ContainerFocus, diff --git a/services/github/pod-github/src/sync/utils.ts b/services/github/pod-github/src/sync/utils.ts index f22edc33e2..342224b53f 100644 --- a/services/github/pod-github/src/sync/utils.ts +++ b/services/github/pod-github/src/sync/utils.ts @@ -196,9 +196,11 @@ export class SyncRunner { id, promise.then(() => {}) ) - const result = await promise - this.eventSync.delete(id) - return result + try { + return await promise + } finally { + this.eventSync.delete(id) + } } } @@ -328,13 +330,20 @@ export function compareMarkdown (a: string, b: string): boolean { return na === nb } -export async function syncChilds (info: DocSyncInfo, client: TxOperations, derivedClient: TxOperations): Promise { - const childInfos = await client.findAll(github.class.DocSyncInfo, { parent: info.url.toLowerCase() }) +export async function syncChilds ( + ctx: MeasureContext, + info: DocSyncInfo, + client: TxOperations, + derivedClient: TxOperations +): Promise { + const childInfos = await ctx.with('syncChilds-find', {}, () => + client.findAll(github.class.DocSyncInfo, { parent: info.url.toLowerCase() }) + ) if (childInfos.length > 0) { const ops = derivedClient.apply() for (const child of childInfos) { await ops?.update(child, { needSync: '' }) } - await ops.commit() + await ctx.with('sync-child-trigger', {}, () => ops.commit()) } } diff --git a/services/github/pod-github/src/types.ts b/services/github/pod-github/src/types.ts index 8957035d14..80e9f4ceed 100644 --- a/services/github/pod-github/src/types.ts +++ b/services/github/pod-github/src/types.ts @@ -224,4 +224,6 @@ export interface GithubUserRecord { scope?: string error?: string | null accounts: Record + + octokit?: Octokit } diff --git a/services/github/pod-github/src/users.ts b/services/github/pod-github/src/users.ts index 4a6a562db8..3771cd52be 100644 --- a/services/github/pod-github/src/users.ts +++ b/services/github/pod-github/src/users.ts @@ -45,6 +45,15 @@ export class UserManager { } failedRefs = new Set() + + cacheRecord (workspace: WorkspaceUuid, ref: PersonId, record: GithubUserRecord): void { + if (this.refUserCache.size > 1000) { + this.refUserCache.clear() + } + const key = `${workspace}.${ref}` + this.refUserCache.set(key, record) + } + async getAccountByRef ( ctx: MeasureContext, workspace: WorkspaceUuid, diff --git a/services/github/pod-github/src/worker.ts b/services/github/pod-github/src/worker.ts index 9780b2a976..d1ff76ebfb 100644 --- a/services/github/pod-github/src/worker.ts +++ b/services/github/pod-github/src/worker.ts @@ -560,13 +560,19 @@ export class GithubWorker implements IntegrationManager { async syncUserData (ctx: MeasureContext): Promise { // Let's sync information about users and send some details - const accounts = await this._client.findAll(contact.class.SocialIdentity, { - type: SocialIdType.GITHUB - }) - const userAuths = await this._client.findAll(github.class.GithubAuthentication, {}) - const persons = await this._client.findAll(contact.class.Person, { - _id: { $in: accounts.map((it) => it.attachedTo) } - }) + const accounts = await ctx.with('find-social-id', {}, () => + this._client.findAll(contact.class.SocialIdentity, { + type: SocialIdType.GITHUB + }) + ) + const userAuths = await ctx.with('find-github-auths', {}, () => + this._client.findAll(github.class.GithubAuthentication, {}) + ) + const persons = await ctx.with('find-persons', {}, () => + this._client.findAll(contact.class.Person, { + _id: { $in: accounts.map((it) => it.attachedTo) } + }) + ) for (const account of accounts) { const userAuth = userAuths.find((it) => it.login === account.value) const person = persons.find((it) => account?.attachedTo) @@ -611,13 +617,18 @@ export class GithubWorker implements IntegrationManager { async getOctokit (ctx: MeasureContext, account: PersonId): Promise { let record = await this.platform.getAccountByRef(this.workspace.uuid, account) - const accountRef = await this._client.findOne(contact.class.SocialIdentity, { _id: account as any }) if (record === undefined) { + const accountRef = await ctx.with('find-social-id', {}, () => + this._client.findOne(contact.class.SocialIdentity, { _id: account as any }) + ) if (accountRef !== undefined) { - const accounts = await this._client.findAll(contact.class.SocialIdentity, { attachedTo: accountRef.attachedTo }) + const accounts = await ctx.with('find-accounts', {}, () => + this._client.findAll(contact.class.SocialIdentity, { attachedTo: accountRef.attachedTo }) + ) for (const aa of accounts) { record = await this.platform.getAccountByRef(this.workspace.uuid, aa._id) if (record !== undefined) { + this.platform.userManager.cacheRecord(this.workspace.uuid, account, record) break } } @@ -625,33 +636,55 @@ export class GithubWorker implements IntegrationManager { } // Check and refresh token if required. if (record !== undefined) { - this.ctx.info('get octokit', { account, recordId: record._id, workspace: this.workspace.uuid }) - await this.platform.checkRefreshToken(ctx, record) - return new Octokit({ - auth: record.token, - client_id: config.ClientID, - client_secret: config.ClientSecret - }) + ctx.info('get octokit', { account, recordId: record._id, workspace: this.workspace.uuid }) + if (!(await this.platform.checkRefreshToken(ctx, record))) { + record.octokit = undefined + } + if (record.octokit !== undefined) { + return record.octokit + } + + record.octokit = ctx.withSync( + 'create-octokit', + {}, + () => + new Octokit({ + auth: record.token, + client_id: config.ClientID, + client_secret: config.ClientSecret + }) + ) + return record.octokit } // We need to inform user, he need to authorize this account with github. // TODO: Inform user it need authenticsion if (!this.authRequestSend.has(account)) { this.authRequestSend.add(account) - const socialId = await this._client.findOne(contact.class.SocialIdentity, { _id: account as any }) + const socialId = await ctx.with('find-social-id', {}, () => + this._client.findOne(contact.class.SocialIdentity, { _id: account as any }) + ) if (socialId !== undefined) { - const personSpace = await this.liveQuery.findOne(contact.class.PersonSpace, { person: socialId.attachedTo }) - const person = await this._client.findOne(contact.mixin.Employee, { _id: socialId.attachedTo as Ref }) + const personSpace = await ctx.with('find-person-space', {}, () => + this.liveQuery.findOne(contact.class.PersonSpace, { person: socialId.attachedTo }) + ) + const person = await ctx.with('find-person', {}, () => + this._client.findOne(contact.mixin.Employee, { _id: socialId.attachedTo as Ref }) + ) if (personSpace !== undefined && person !== undefined) { // We need to remove if user has authentication in workspace but doesn't have a record. - const allSocialId = await this._client.findAll(contact.class.SocialIdentity, { - attachedTo: personSpace.person - }) + const allSocialId = await ctx.with('find-all-social-ids', {}, () => + this._client.findAll(contact.class.SocialIdentity, { + attachedTo: personSpace.person + }) + ) - const authentications = await this.liveQuery.findAll(github.class.GithubAuthentication, { - createdBy: { $in: allSocialId.map((it) => it._id) } - }) + const authentications = await ctx.with('find-authentications', {}, () => + this.liveQuery.findAll(github.class.GithubAuthentication, { + createdBy: { $in: allSocialId.map((it) => it._id) } + }) + ) for (const auth of authentications) { await this._client.remove(auth) } @@ -1026,7 +1059,7 @@ export class GithubWorker implements IntegrationManager { continue } - this.ctx.info('External Syncing', { + ctx.info('External Syncing', { name: repo.name, prj: prj.name, field, @@ -1042,7 +1075,7 @@ export class GithubWorker implements IntegrationManager { await mapper?.externalSync(ctx, integration, derivedClient, field, _docs, repo, prj) } catch (err: any) { Analytics.handleError(err) - this.ctx.error('failed to perform external sync', err) + ctx.error('failed to perform external sync', err) } } } @@ -1578,10 +1611,10 @@ export class GithubWorker implements IntegrationManager { if (this.closing) { break } - await this.ctx.with( + await ctx.with( 'external sync', {}, - async () => { + async (ctx) => { const enabled = integration.enabled && integration.octokit !== undefined const upd: DocumentUpdate = {} @@ -1622,10 +1655,8 @@ export class GithubWorker implements IntegrationManager { if (this.closing) { break } - const withError = await derivedClient.findAll( - github.class.DocSyncInfo, - { error: { $ne: null }, url: null }, - { limit: 50 } + const withError = await ctx.with('find-docSyncInfo', {}, () => + derivedClient.findAll(github.class.DocSyncInfo, { error: { $ne: null }, url: null }, { limit: 50 }) ) if (withError.length === 0) { @@ -1642,10 +1673,8 @@ export class GithubWorker implements IntegrationManager { if (this.closing) { break } - const withError = await derivedClient.findAll( - github.class.DocSyncInfo, - { error: { $ne: null } }, - { limit: 50 } + const withError = await ctx.with('find-docSyncInfo-errors', {}, () => + derivedClient.findAll(github.class.DocSyncInfo, { error: { $ne: null } }, { limit: 50 }) ) if (withError.length === 0) { @@ -1666,17 +1695,17 @@ export class GithubWorker implements IntegrationManager { await ops.update(d, { error: null, needSync: skipError ? githubSyncVersion : '' }) } - await ops.commit() + await ctx.with('commit-errors-docsync-info', {}, () => ops.commit()) } for (const { _class, mapper } of this.mappers) { if (this.closing) { break } - await this.ctx.with( - 'external sync', - { _class: _class.join(', ') }, - async () => { + await ctx.with( + 'mapper external sync', + {}, + async (ctx) => { await mapper.externalFullSync(ctx, integration, derivedClient, _projects, _repositories) }, { installation: integration.installationName, workspace: this.workspace.uuid }, @@ -1810,11 +1839,14 @@ export async function syncUser ( client: TxOperations, account: PersonId ): Promise { - const okit = new Octokit({ - auth: record.token, - client_id: config.ClientID, - client_secret: config.ClientSecret - }) + const okit = + record.octokit ?? + new Octokit({ + auth: record.token, + client_id: config.ClientID, + client_secret: config.ClientSecret + }) + record.octokit = okit const details = await fetchViewerDetails(okit) From c62c4b932db0986e2bbfe642d5887946c04c2e69 Mon Sep 17 00:00:00 2001 From: Artyom Savchenko Date: Wed, 10 Sep 2025 11:52:33 +0700 Subject: [PATCH 2/2] Add Home application (#9811) * Add Home application Signed-off-by: Artem Savchenko * Update labels and clean up Signed-off-by: Artem Savchenko * Revert version Signed-off-by: Artem Savchenko * Move home page Signed-off-by: Artem Savchenko * Fix thread icon and translations Signed-off-by: Artem Savchenko * Remove home from chat Signed-off-by: Artem Savchenko * Fix typo Signed-off-by: Artem Savchenko * Disable Home by default Signed-off-by: Artem Savchenko --------- Signed-off-by: Artem Savchenko --- common/config/rush/pnpm-lock.yaml | 150 +++++++++++++++++- dev/prod/package.json | 3 + dev/prod/src/platform.ts | 4 + models/all/package.json | 3 +- models/all/src/index.ts | 6 + models/home/.eslintrc.js | 7 + models/home/.npmignore | 4 + models/home/config/rig.json | 5 + models/home/jest.config.js | 7 + models/home/package.json | 50 ++++++ models/home/src/index.ts | 42 +++++ models/home/src/migration.ts | 21 +++ models/home/src/plugin.ts | 26 +++ models/home/tsconfig.json | 12 ++ plugins/card-assets/lang/cs.json | 4 - plugins/card-assets/lang/de.json | 4 - plugins/card-assets/lang/en.json | 4 - plugins/card-assets/lang/es.json | 4 - plugins/card-assets/lang/fr.json | 4 - plugins/card-assets/lang/it.json | 4 - plugins/card-assets/lang/ja.json | 4 - plugins/card-assets/lang/pt.json | 4 - plugins/card-assets/lang/ru.json | 4 - plugins/card-assets/lang/zh.json | 4 - plugins/card-resources/package.json | 1 + .../src/components/NewCardForm.svelte | 3 +- .../navigator-next/Navigator.svelte | 17 -- plugins/card-resources/src/index.ts | 7 +- plugins/card-resources/src/plugin.ts | 4 - plugins/card-resources/src/types.ts | 1 - .../src/components/ChatApplication.svelte | 25 +-- .../src/components/ChatNavigation.svelte | 9 +- plugins/chat-resources/src/location.ts | 14 -- plugins/home-assets/.eslintrc.js | 7 + plugins/home-assets/assets/icons.svg | 17 ++ plugins/home-assets/config/rig.json | 5 + plugins/home-assets/jest.config.js | 7 + plugins/home-assets/lang/cs.json | 11 ++ plugins/home-assets/lang/de.json | 11 ++ plugins/home-assets/lang/en.json | 11 ++ plugins/home-assets/lang/es.json | 11 ++ plugins/home-assets/lang/fr.json | 11 ++ plugins/home-assets/lang/it.json | 11 ++ plugins/home-assets/lang/ja.json | 11 ++ plugins/home-assets/lang/pt.json | 11 ++ plugins/home-assets/lang/ru.json | 11 ++ plugins/home-assets/lang/zh.json | 11 ++ plugins/home-assets/package.json | 39 +++++ .../home-assets/src/__tests__/lang.test.ts | 21 +++ plugins/home-assets/src/index.ts | 24 +++ plugins/home-assets/tsconfig.json | 13 ++ plugins/home-resources/.eslintrc.js | 4 + plugins/home-resources/.prettierrc | 22 +++ plugins/home-resources/config/rig.json | 5 + plugins/home-resources/jest.config.js | 5 + plugins/home-resources/package.json | 60 +++++++ plugins/home-resources/postcss.config.js | 5 + .../src/components/Home.svelte | 36 ++++- .../src/components/HomeApplication.svelte | 87 ++++++++++ .../src/components/HomeCardPresenter.svelte | 5 +- .../src/components/HomeSettings.svelte | 8 +- .../src/components/Navigator.svelte | 54 +++++++ .../src/home.ts | 0 plugins/home-resources/src/index.ts | 24 +++ plugins/home-resources/src/plugin.ts | 32 ++++ plugins/home-resources/src/types.ts | 25 +++ plugins/home-resources/svelte.config.js | 5 + plugins/home-resources/tsconfig.json | 11 ++ plugins/home/.eslintrc.js | 7 + plugins/home/.npmignore | 4 + plugins/home/config/rig.json | 4 + plugins/home/jest.config.js | 7 + plugins/home/package.json | 47 ++++++ plugins/home/src/index.ts | 31 ++++ plugins/home/tsconfig.json | 12 ++ rush.json | 22 ++- 76 files changed, 1096 insertions(+), 130 deletions(-) create mode 100644 models/home/.eslintrc.js create mode 100644 models/home/.npmignore create mode 100644 models/home/config/rig.json create mode 100644 models/home/jest.config.js create mode 100644 models/home/package.json create mode 100644 models/home/src/index.ts create mode 100644 models/home/src/migration.ts create mode 100644 models/home/src/plugin.ts create mode 100644 models/home/tsconfig.json create mode 100644 plugins/home-assets/.eslintrc.js create mode 100644 plugins/home-assets/assets/icons.svg create mode 100644 plugins/home-assets/config/rig.json create mode 100644 plugins/home-assets/jest.config.js create mode 100644 plugins/home-assets/lang/cs.json create mode 100644 plugins/home-assets/lang/de.json create mode 100644 plugins/home-assets/lang/en.json create mode 100644 plugins/home-assets/lang/es.json create mode 100644 plugins/home-assets/lang/fr.json create mode 100644 plugins/home-assets/lang/it.json create mode 100644 plugins/home-assets/lang/ja.json create mode 100644 plugins/home-assets/lang/pt.json create mode 100644 plugins/home-assets/lang/ru.json create mode 100644 plugins/home-assets/lang/zh.json create mode 100644 plugins/home-assets/package.json create mode 100644 plugins/home-assets/src/__tests__/lang.test.ts create mode 100644 plugins/home-assets/src/index.ts create mode 100644 plugins/home-assets/tsconfig.json create mode 100644 plugins/home-resources/.eslintrc.js create mode 100644 plugins/home-resources/.prettierrc create mode 100644 plugins/home-resources/config/rig.json create mode 100644 plugins/home-resources/jest.config.js create mode 100644 plugins/home-resources/package.json create mode 100644 plugins/home-resources/postcss.config.js rename plugins/{card-resources => home-resources}/src/components/Home.svelte (81%) create mode 100644 plugins/home-resources/src/components/HomeApplication.svelte rename plugins/{card-resources => home-resources}/src/components/HomeCardPresenter.svelte (96%) rename plugins/{card-resources => home-resources}/src/components/HomeSettings.svelte (96%) create mode 100644 plugins/home-resources/src/components/Navigator.svelte rename plugins/{card-resources => home-resources}/src/home.ts (100%) create mode 100644 plugins/home-resources/src/index.ts create mode 100644 plugins/home-resources/src/plugin.ts create mode 100644 plugins/home-resources/src/types.ts create mode 100644 plugins/home-resources/svelte.config.js create mode 100644 plugins/home-resources/tsconfig.json create mode 100644 plugins/home/.eslintrc.js create mode 100644 plugins/home/.npmignore create mode 100644 plugins/home/config/rig.json create mode 100644 plugins/home/jest.config.js create mode 100644 plugins/home/package.json create mode 100644 plugins/home/src/index.ts create mode 100644 plugins/home/tsconfig.json diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 4a798d6f9d..caf92c04a0 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -436,6 +436,15 @@ importers: '@rush-temp/hls': specifier: file:./projects/hls.tgz version: file:projects/hls.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)))(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)) + '@rush-temp/home': + specifier: file:./projects/home.tgz + version: file:projects/home.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)) + '@rush-temp/home-assets': + specifier: file:./projects/home-assets.tgz + version: file:projects/home-assets.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)) + '@rush-temp/home-resources': + specifier: file:./projects/home-resources.tgz + version: file:projects/home-resources.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)))(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)) '@rush-temp/hr': specifier: file:./projects/hr.tgz version: file:projects/hr.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)) @@ -634,6 +643,9 @@ importers: '@rush-temp/model-guest': specifier: file:./projects/model-guest.tgz version: file:projects/model-guest.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)) + '@rush-temp/model-home': + specifier: file:./projects/model-home.tgz + version: file:projects/model-home.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)) '@rush-temp/model-hr': specifier: file:./projects/model-hr.tgz version: file:projects/model-hr.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)) @@ -4638,7 +4650,7 @@ packages: version: 0.0.0 '@rush-temp/card-resources@file:projects/card-resources.tgz': - resolution: {integrity: sha512-FT20KjpbhUpBVFihXnJGGQkLUxjFchfrJ+oC3We3JjaRBjDhidsTHulxPduQuOck/WJlbtzTG+gO8y6OO/E5/g==, tarball: file:projects/card-resources.tgz} + resolution: {integrity: sha512-p+B23RR9oPlR1KyH7v+7hk96bvthfpEXpmWExh8Qit7cjDMeAlMFD8QCaGh6PDPnNhgmuZU1Jr12B/L4jI2feA==, tarball: file:projects/card-resources.tgz} version: 0.0.0 '@rush-temp/card@file:projects/card.tgz': @@ -4921,6 +4933,18 @@ packages: resolution: {integrity: sha512-8NM5s9LUxNU+flsQvDz5oEGzVSNX1MZnoMBG0Qk+Jb0LJ/9aUIRkuaTOQMX6r+7s4NJbvkQxElKx0kJ0SWDFXw==, tarball: file:projects/hls.tgz} version: 0.0.0 + '@rush-temp/home-assets@file:projects/home-assets.tgz': + resolution: {integrity: sha512-X70gK5STU72BH7qpbGG+7dBGczEpfZzWnm63zvnKEudhx7t2uf9mLzQKiP+U3NfVhySBneAjM43Q+hJICV7wsA==, tarball: file:projects/home-assets.tgz} + version: 0.0.0 + + '@rush-temp/home-resources@file:projects/home-resources.tgz': + resolution: {integrity: sha512-MHRW0L8AY2bNYpzrm3LhHwRgEOwqIeWc7C83SIqZme2435Fu8zSSGd73GPbcb+juw770tiNQ5DNbcg/bhEc7WQ==, tarball: file:projects/home-resources.tgz} + version: 0.0.0 + + '@rush-temp/home@file:projects/home.tgz': + resolution: {integrity: sha512-rdekzJmsD0T3s8W31vA9GLHkXz3euNTjv9EvOluzkS7bK8WTcKmgtS2DfmyrxwfIo8W9zXjD/ju1AOMP9qwRgA==, tarball: file:projects/home.tgz} + version: 0.0.0 + '@rush-temp/hr-assets@file:projects/hr-assets.tgz': resolution: {integrity: sha512-hGQa+GtCy/Zp3WxkkmI9bnoB0chnNA1OilG8C8Q9OdIrIBkE6bJUYgECwSxXsvxYNR02DVGfj45pKSwM+caw+w==, tarball: file:projects/hr-assets.tgz} version: 0.0.0 @@ -5090,7 +5114,7 @@ packages: version: 0.0.0 '@rush-temp/model-all@file:projects/model-all.tgz': - resolution: {integrity: sha512-Z9BGAkUiWoTbDM2Bd0AHJSCAb094NOeXknL1TZ1P9hS6waq7OJ4J3NSi6/8Ls7RRSblp0Gm0bHKYe7GOSFbhmQ==, tarball: file:projects/model-all.tgz} + resolution: {integrity: sha512-vgCC7/2H8W8807BRBFsSvMGmaVmhuGu+ATwdtPzDHcEUlm3NTZbPKMGQ5q3/0mtSgmQziDQR30MRVsINNqkLiw==, tarball: file:projects/model-all.tgz} version: 0.0.0 '@rush-temp/model-analytics-collector@file:projects/model-analytics-collector.tgz': @@ -5181,6 +5205,10 @@ packages: resolution: {integrity: sha512-kKs3ou5CtoDanrPvhLK/PPbvL38gGOyy9kf3/IOtmV5E+cBZ7+4NmaY44sLgUrv2+s4LBytAJDFTrWaEMjG46g==, tarball: file:projects/model-guest.tgz} version: 0.0.0 + '@rush-temp/model-home@file:projects/model-home.tgz': + resolution: {integrity: sha512-TPps1Rv4wE6cg/cslfxtJPveWIGnZWj4tnWBkVDCwVvuvvVzkh85+I+pPx93gzVdBHkICD8tJP1xZdhORE9G4A==, tarball: file:projects/model-home.tgz} + version: 0.0.0 + '@rush-temp/model-hr@file:projects/model-hr.tgz': resolution: {integrity: sha512-84aXICE02BHlrNiYDoUaZkO23jI1I77JaWcLOQPIKWXyh781IJyaNAnz8dSzeNQ9OW2GVoGXy/3oGErqcmNIeg==, tarball: file:projects/model-hr.tgz} version: 0.0.0 @@ -5670,7 +5698,7 @@ packages: version: 0.0.0 '@rush-temp/prod@file:projects/prod.tgz': - resolution: {integrity: sha512-hS9pkkwUUUYlP3t7orkFEAS8lv3TkOZ2iTgxaikc2u7AQSI+SfuD+HaNQ26onEwftVJOhrcXEYapPq1eCHMoPg==, tarball: file:projects/prod.tgz} + resolution: {integrity: sha512-zVqv+QwGQtWZZL7J2DVfTGiAZAnOlf2qMqg9ANofYnIfkItKQOr3Nj+uu5C7h7PnthtYNWeEtKwxfTK2WA9X8w==, tarball: file:projects/prod.tgz} version: 0.0.0 '@rush-temp/products-assets@file:projects/products-assets.tgz': @@ -20915,6 +20943,97 @@ snapshots: - supports-color - ts-node + '@rush-temp/home-assets@file:projects/home-assets.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))': + dependencies: + '@types/jest': 29.5.12 + '@types/node': 22.15.29 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.8.3) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.8.3) + eslint-plugin-import: 2.29.1(eslint@8.56.0) + eslint-plugin-n: 15.7.0(eslint@8.56.0) + eslint-plugin-promise: 6.1.1(eslint@8.56.0) + jest: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)) + prettier: 3.2.5 + ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)))(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - babel-jest + - babel-plugin-macros + - esbuild + - node-notifier + - supports-color + - ts-node + + '@rush-temp/home-resources@file:projects/home-resources.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)))(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))': + dependencies: + '@types/jest': 29.5.12 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.8.3) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.8.3) + eslint-plugin-import: 2.29.1(eslint@8.56.0) + eslint-plugin-n: 15.7.0(eslint@8.56.0) + eslint-plugin-promise: 6.1.1(eslint@8.56.0) + eslint-plugin-svelte: 2.35.1(eslint@8.56.0)(svelte@4.2.19)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)) + fast-equals: 5.2.2 + jest: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)) + prettier: 3.2.5 + prettier-plugin-svelte: 3.2.2(prettier@3.2.5)(svelte@4.2.19) + sass: 1.71.1 + svelte: 4.2.19 + svelte-check: 3.6.9(@babel/core@7.23.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)))(postcss@8.5.3)(sass@1.71.1)(svelte@4.2.19) + svelte-eslint-parser: 0.33.1(svelte@4.2.19) + svelte-loader: 3.2.0(svelte@4.2.19) + svelte-preprocess: 5.1.3(@babel/core@7.23.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)))(postcss@8.5.3)(sass@1.71.1)(svelte@4.2.19)(typescript@5.8.3) + ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)))(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - '@types/node' + - babel-jest + - babel-plugin-macros + - coffeescript + - esbuild + - less + - node-notifier + - postcss + - postcss-load-config + - pug + - stylus + - sugarss + - supports-color + - ts-node + + '@rush-temp/home@file:projects/home.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))': + dependencies: + '@types/jest': 29.5.12 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.8.3) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.8.3) + eslint-plugin-import: 2.29.1(eslint@8.56.0) + eslint-plugin-n: 15.7.0(eslint@8.56.0) + eslint-plugin-promise: 6.1.1(eslint@8.56.0) + jest: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)) + prettier: 3.2.5 + ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)))(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - '@types/node' + - babel-jest + - babel-plugin-macros + - esbuild + - node-notifier + - supports-color + - ts-node + '@rush-temp/hr-assets@file:projects/hr-assets.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))': dependencies: '@types/jest': 29.5.12 @@ -22775,6 +22894,31 @@ snapshots: - supports-color - ts-node + '@rush-temp/model-home@file:projects/model-home.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))': + dependencies: + '@types/jest': 29.5.12 + '@types/node': 22.15.29 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.8.3) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.8.3) + eslint-plugin-import: 2.29.1(eslint@8.56.0) + eslint-plugin-n: 15.7.0(eslint@8.56.0) + eslint-plugin-promise: 6.1.1(eslint@8.56.0) + jest: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)) + prettier: 3.2.5 + ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)))(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - babel-jest + - babel-plugin-macros + - esbuild + - node-notifier + - supports-color + - ts-node + '@rush-temp/model-hr@file:projects/model-hr.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))': dependencies: '@types/jest': 29.5.12 diff --git a/dev/prod/package.json b/dev/prod/package.json index 3663c64cf7..62b00c010c 100644 --- a/dev/prod/package.json +++ b/dev/prod/package.json @@ -282,6 +282,9 @@ "@hcengineering/huly-mail": "^0.6.0", "@hcengineering/huly-mail-assets": "^0.6.0", "@hcengineering/huly-mail-resources": "^0.6.0", + "@hcengineering/home": "^0.6.0", + "@hcengineering/home-assets": "^0.6.0", + "@hcengineering/home-resources": "^0.6.0", "@sentry/svelte": "^9.22.0", "posthog-js": "^1.246.0", "readable-stream": "^4.7.0", diff --git a/dev/prod/src/platform.ts b/dev/prod/src/platform.ts index 101791c8a6..71075124f0 100644 --- a/dev/prod/src/platform.ts +++ b/dev/prod/src/platform.ts @@ -78,6 +78,7 @@ import communication, { communicationId } from '@hcengineering/communication' import {emojiId} from '@hcengineering/emoji' import billingPlugin, {billingId} from '@hcengineering/billing' import { hulyMailId } from '@hcengineering/huly-mail' +import {homeId} from '@hcengineering/home' import '@hcengineering/activity-assets' import '@hcengineering/analytics-collector-assets' @@ -135,6 +136,7 @@ import '@hcengineering/communication-assets' import '@hcengineering/emoji-assets' import '@hcengineering/billing-assets' import '@hcengineering/huly-mail-assets' +import '@hcengineering/home-assets' import { coreId } from '@hcengineering/core' import presentation, { @@ -377,6 +379,7 @@ function configureI18n(): void { addStringsLoader(emojiId, async (lang: string) => await import(`@hcengineering/emoji-assets/lang/${lang}.json`)) addStringsLoader(billingId, async (lang: string) => await import(`@hcengineering/billing-assets/lang/${lang}.json`)) addStringsLoader(hulyMailId, async (lang: string) => await import(`@hcengineering/huly-mail-assets/lang/${lang}.json`)) + addStringsLoader(homeId, async (lang: string) => await import(`@hcengineering/home-assets/lang/${lang}.json`)) } export async function configurePlatform() { @@ -587,6 +590,7 @@ export async function configurePlatform() { addLocation(emojiId, () => import(/* webpackChunkName: "achievement" */ '@hcengineering/emoji-resources')) addLocation(billingId, () => import(/* webpackChunkName: "achievement" */ '@hcengineering/billing-resources')) addLocation(hulyMailId, () => import(/* webpackChunkName: "achievement" */ '@hcengineering/huly-mail-resources')) + addLocation(homeId, () => import(/* webpackChunkName: "home" */ '@hcengineering/home-resources')) setMetadata(client.metadata.FilterModel, 'ui') setMetadata(client.metadata.ExtraPlugins, ['preference' as Plugin]) diff --git a/models/all/package.json b/models/all/package.json index 6a6569f252..0eae0f0a9d 100644 --- a/models/all/package.json +++ b/models/all/package.json @@ -133,6 +133,7 @@ "@hcengineering/model-communication": "^0.6.0", "@hcengineering/model-emoji": "^0.6.0", "@hcengineering/model-billing": "^0.6.0", - "@hcengineering/model-huly-mail": "^0.6.0" + "@hcengineering/model-huly-mail": "^0.6.0", + "@hcengineering/model-home": "^0.6.0" } } diff --git a/models/all/src/index.ts b/models/all/src/index.ts index 92a64c581f..c323e38c33 100644 --- a/models/all/src/index.ts +++ b/models/all/src/index.ts @@ -118,6 +118,7 @@ import { presenceId, createModel as presenceModel } from '@hcengineering/model-p import chat, { chatId, createModel as chatModel } from '@hcengineering/model-chat' import processes, { processId, createModel as processModel } from '@hcengineering/model-process' import inbox, { createModel as inboxModel, inboxId } from '@hcengineering/model-inbox' +import home, { createModel as homeModel, homeId } from '@hcengineering/model-home' import { achievementId, createModel as achievementModel } from '@hcengineering/model-achievement' import { emojiId, createModel as emojiModel } from '@hcengineering/model-emoji' import { billingId, createModel as billingModel } from '@hcengineering/model-billing' @@ -487,6 +488,11 @@ export default function buildModel (): Builder { [mailModel, mailId], [billingModel, billingId, { beta: false, hidden: true, enabled: true }], [hulyMailModel, hulyMailId], + [ + homeModel, + homeId, + { label: home.string.Home, hidden: true, enabled: false, beta: true, classFilter: defaultFilter } + ], [serverCoreModel, serverCoreId], [serverAttachmentModel, serverAttachmentId], diff --git a/models/home/.eslintrc.js b/models/home/.eslintrc.js new file mode 100644 index 0000000000..c1cf82cba0 --- /dev/null +++ b/models/home/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: ['./node_modules/@hcengineering/platform-rig/profiles/model/eslint.config.json'], + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig.json' + } +} diff --git a/models/home/.npmignore b/models/home/.npmignore new file mode 100644 index 0000000000..e3ec093c38 --- /dev/null +++ b/models/home/.npmignore @@ -0,0 +1,4 @@ +* +!/lib/** +!CHANGELOG.md +/lib/**/__tests__/ diff --git a/models/home/config/rig.json b/models/home/config/rig.json new file mode 100644 index 0000000000..2f6be36605 --- /dev/null +++ b/models/home/config/rig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + "rigPackageName": "@hcengineering/platform-rig", + "rigProfile": "model" +} diff --git a/models/home/jest.config.js b/models/home/jest.config.js new file mode 100644 index 0000000000..2cfd408b67 --- /dev/null +++ b/models/home/jest.config.js @@ -0,0 +1,7 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'], + roots: ["./src"], + coverageReporters: ["text-summary", "html"] +} diff --git a/models/home/package.json b/models/home/package.json new file mode 100644 index 0000000000..8e40399c2c --- /dev/null +++ b/models/home/package.json @@ -0,0 +1,50 @@ +{ + "name": "@hcengineering/model-home", + "version": "0.6.0", + "main": "lib/index.js", + "svelte": "src/index.ts", + "types": "types/index.d.ts", + "author": "Hardcore Engineering Inc", + "template": "@hcengineering/model-package", + "license": "EPL-2.0", + "scripts": { + "build": "compile", + "build:watch": "compile", + "format": "format src", + "_phase:build": "compile transpile src", + "_phase:format": "format src", + "_phase:validate": "compile validate", + "_phase:test": "jest --passWithNoTests --silent --forceExit", + "test": "jest --passWithNoTests --silent --forceExit" + }, + "devDependencies": { + "@hcengineering/platform-rig": "^0.6.0", + "@typescript-eslint/eslint-plugin": "^6.11.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-n": "^15.4.0", + "eslint": "^8.54.0", + "@typescript-eslint/parser": "^6.11.0", + "eslint-config-standard-with-typescript": "^40.0.0", + "prettier": "^3.1.0", + "typescript": "^5.8.3", + "@types/node": "^22.15.29", + "jest": "^29.7.0", + "@types/jest": "^29.5.5", + "ts-jest": "^29.1.1" + }, + "dependencies": { + "@hcengineering/card": "^0.6.0", + "@hcengineering/home": "^0.6.0", + "@hcengineering/home-resources": "^0.6.0", + "@hcengineering/core": "^0.6.32", + "@hcengineering/model": "^0.6.11", + "@hcengineering/model-core": "^0.6.0", + "@hcengineering/model-workbench": "^0.6.1", + "@hcengineering/platform": "^0.6.11", + "@hcengineering/setting": "^0.6.17", + "@hcengineering/ui": "^0.6.15", + "@hcengineering/view": "^0.6.13", + "@hcengineering/workbench": "^0.6.16" + } +} diff --git a/models/home/src/index.ts b/models/home/src/index.ts new file mode 100644 index 0000000000..f0df505511 --- /dev/null +++ b/models/home/src/index.ts @@ -0,0 +1,42 @@ +// +// Copyright © 2025 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { type Builder } from '@hcengineering/model' +import core from '@hcengineering/model-core' +import workbench from '@hcengineering/model-workbench' +import { homeId } from '@hcengineering/home' + +import home from './plugin' + +export { homeId } from '@hcengineering/home' +export { homeOperation } from './migration' +export default home + +export function createModel (builder: Builder): void { + builder.createDoc( + workbench.class.Application, + core.space.Model, + { + label: home.string.Home, + icon: home.icon.Home, + alias: homeId, + hidden: false, + component: home.component.HomeApplication, + position: 'top', + order: 90 + }, + home.app.Home + ) +} diff --git a/models/home/src/migration.ts b/models/home/src/migration.ts new file mode 100644 index 0000000000..5c011f3e1a --- /dev/null +++ b/models/home/src/migration.ts @@ -0,0 +1,21 @@ +// +// Copyright © 2025 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { type MigrateOperation, type MigrationClient, type MigrationUpgradeClient } from '@hcengineering/model' + +export const homeOperation: MigrateOperation = { + async migrate (client: MigrationClient, mode): Promise {}, + async upgrade (state: Map>, client: () => Promise, mode): Promise {} +} diff --git a/models/home/src/plugin.ts b/models/home/src/plugin.ts new file mode 100644 index 0000000000..a982fe61a1 --- /dev/null +++ b/models/home/src/plugin.ts @@ -0,0 +1,26 @@ +// +// Copyright © 2025 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { homeId } from '@hcengineering/home' +import home from '@hcengineering/home-resources/src/plugin' +import { type Ref } from '@hcengineering/core' +import { type Application } from '@hcengineering/model-workbench' +import { mergeIds } from '@hcengineering/platform' + +export default mergeIds(homeId, home, { + app: { + Home: '' as Ref + } +}) diff --git a/models/home/tsconfig.json b/models/home/tsconfig.json new file mode 100644 index 0000000000..367a8578c9 --- /dev/null +++ b/models/home/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "./node_modules/@hcengineering/platform-rig/profiles/model/tsconfig.json", + + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "declarationDir": "./types", + "tsBuildInfoFile": ".build/build.tsbuildinfo" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "lib", "dist", "types", "bundle"] +} \ No newline at end of file diff --git a/plugins/card-assets/lang/cs.json b/plugins/card-assets/lang/cs.json index 9a116e78dc..5e75614650 100644 --- a/plugins/card-assets/lang/cs.json +++ b/plugins/card-assets/lang/cs.json @@ -42,12 +42,8 @@ "NoChildren": "Žádné děti", "ConfigDescription": "Rozšíření pro správu znalostí ve stylu databáze.", "AddCollaborators": "Přidat spolupracovníky", - "Home": "Domů", "CardTitle": "Název", "Post": "Přidat", - "Compact": "Kompaktní", - "Comfortable": "Komfortní", - "Comfortable2": "Komfortní 2", "GetIndividualPublicLink": "Získat personalizovaný veřejný odkaz", "ShowLess": "Skrýt detaily", "CardContent": "Co chcete sdílet?" diff --git a/plugins/card-assets/lang/de.json b/plugins/card-assets/lang/de.json index ebeeefd4c4..9d5c56e480 100644 --- a/plugins/card-assets/lang/de.json +++ b/plugins/card-assets/lang/de.json @@ -42,12 +42,8 @@ "NoChildren": "Keine Kinder", "ConfigDescription": "Erweiterung für Datenbank-basiertes Wissensmanagement.", "AddCollaborators": "Mitarbeiter hinzufügen", - "Home": "Startseite", "CardTitle": "Titel", "Post": "Beitrag", - "Compact": "Kompakt", - "Comfortable": "Komfortabel", - "Comfortable2": "Komfortabel 2", "GetIndividualPublicLink": "Personalisierten öffentlichen Link erhalten", "ShowLess": "Weniger anzeigen", "CardContent": "Was möchten Sie teilen?" diff --git a/plugins/card-assets/lang/en.json b/plugins/card-assets/lang/en.json index 0804c8e012..3eb2c7edd1 100644 --- a/plugins/card-assets/lang/en.json +++ b/plugins/card-assets/lang/en.json @@ -42,12 +42,8 @@ "NoChildren": "No children", "ConfigDescription": "Extension for database-style knowledge management.", "AddCollaborators": "Add collaborators", - "Home": "Home", "CardTitle": "Title", "Post": "Post", - "Compact": "Compact", - "Comfortable": "Comfortable", - "Comfortable2": "Comfortable 2", "GetIndividualPublicLink": "Get personalized public link", "ShowLess": "Show less", "CardContent": "What do you want to share?" diff --git a/plugins/card-assets/lang/es.json b/plugins/card-assets/lang/es.json index d5abde8139..0fb87c2905 100644 --- a/plugins/card-assets/lang/es.json +++ b/plugins/card-assets/lang/es.json @@ -42,12 +42,8 @@ "NoChildren": "No hay hijos", "ConfigDescription": "Extensión para la gestión del conocimiento al estilo de una base de datos.", "AddCollaborators": "Agregar colaboradores", - "Home": "Inicio", "CardTitle": "Título", "Post": "Publicar", - "Compact": "Compacto", - "Comfortable": "Confortable", - "Comfortable2": "Confortable 2", "GetIndividualPublicLink": "Obtener enlace público personalizado", "ShowLess": "Mostrar menos", "CardContent": "¿Qué quieres compartir?" diff --git a/plugins/card-assets/lang/fr.json b/plugins/card-assets/lang/fr.json index 28e9762341..c13b0481b9 100644 --- a/plugins/card-assets/lang/fr.json +++ b/plugins/card-assets/lang/fr.json @@ -42,12 +42,8 @@ "NoChildren": "Pas d'enfants", "ConfigDescription": "Extension pour la gestion des connaissances de style base de données.", "AddCollaborators": "Ajouter des collaborateurs", - "Home": "Accueil", "CardTitle": "Titre", "Post": "Publier", - "Compact": "Compact", - "Comfortable": "Confortable", - "Comfortable2": "Confortable 2", "GetIndividualPublicLink": "Obtenir un lien public personnalisé", "ShowLess": "Afficher moins", "CardContent": "Que voulez-vous partager ?" diff --git a/plugins/card-assets/lang/it.json b/plugins/card-assets/lang/it.json index a642912077..71af7757a4 100644 --- a/plugins/card-assets/lang/it.json +++ b/plugins/card-assets/lang/it.json @@ -42,12 +42,8 @@ "NumberTypes": "{count, plural, one {# tipo} other {# tipi}}", "ConfigDescription": "Estensione per la gestione della conoscenza in stile database.", "AddCollaborators": "Aggiungi collaboratori", - "Home": "Home", "CardTitle": "Titolo", "Post": "Pubblica", - "Compact": "Compatto", - "Comfortable": "Confortabile", - "Comfortable2": "Confortabile 2", "GetIndividualPublicLink": "Ottieni link pubblico personalizzato", "ShowLess": "Mostra meno", "CardContent": "Cosa vuoi condividere?" diff --git a/plugins/card-assets/lang/ja.json b/plugins/card-assets/lang/ja.json index 48620e3d41..025bc981e6 100644 --- a/plugins/card-assets/lang/ja.json +++ b/plugins/card-assets/lang/ja.json @@ -42,12 +42,8 @@ "NoChildren": "子がありません", "ConfigDescription": "データベーススタイルのナレッジマネジメント用の拡張機能。", "AddCollaborators": "コラボレーターを追加", - "Home": "ホーム", "CardTitle": "タイトル", "Post": "投稿", - "Compact": "コンパクト", - "Comfortable": "コンファンティブ", - "Comfortable2": "コンファンティブ 2", "GetIndividualPublicLink": "パーソナライズされた公開リンクを取得", "ShowLess": "詳細を隠す", "CardContent": "何を共有しますか?" diff --git a/plugins/card-assets/lang/pt.json b/plugins/card-assets/lang/pt.json index a86bf51b8c..5ff8dacb99 100644 --- a/plugins/card-assets/lang/pt.json +++ b/plugins/card-assets/lang/pt.json @@ -42,12 +42,8 @@ "NoChildren": "Sem filhos", "ConfigDescription": "Extensão para gerenciamento de conhecimento no estilo de banco de dados.", "AddCollaborators": "Adicionar colaboradores", - "Home": "Início", "CardTitle": "Título", "Post": "Publicar", - "Compact": "Compacto", - "Comfortable": "Confortável", - "Comfortable2": "Confortável 2", "GetIndividualPublicLink": "Obter link público personalizado", "ShowLess": "Mostrar menos", "CardContent": "O que você quer compartilhar?" diff --git a/plugins/card-assets/lang/ru.json b/plugins/card-assets/lang/ru.json index 5bc7380bb0..5a433d631f 100644 --- a/plugins/card-assets/lang/ru.json +++ b/plugins/card-assets/lang/ru.json @@ -42,12 +42,8 @@ "NoChildren": "Нет потомков", "ConfigDescription": "Расширение для управления знаниями в стиле базы данных.", "AddCollaborators": "Добавить сотрудников", - "Home": "Дом", "CardTitle": "Название", "Post": "Опубликовать", - "Compact": "Компактный", - "Comfortable": "Комфортный", - "Comfortable2": "Комфортный 2", "GetIndividualPublicLink": "Получить персональную публичную ссылку", "ShowLess": "Скрыть детали", "CardContent": "Чем вы хотите поделиться?" diff --git a/plugins/card-assets/lang/zh.json b/plugins/card-assets/lang/zh.json index a84bf00df9..dfe45cbfc5 100644 --- a/plugins/card-assets/lang/zh.json +++ b/plugins/card-assets/lang/zh.json @@ -42,12 +42,8 @@ "NoChildren": "没有子级", "ConfigDescription": "用于数据库风格知识管理的扩展。", "AddCollaborators": "添加协作者", - "Home": "主页", "CardTitle": "标题", "Post": "发布", - "Compact": "紧凑", - "Comfortable": "舒适", - "Comfortable2": "舒适 2", "GetIndividualPublicLink": "获取个性化公共链接", "ShowLess": "收起详情", "CardContent": "你想分享什么?" diff --git a/plugins/card-resources/package.json b/plugins/card-resources/package.json index 512609ba84..b07dd45a74 100644 --- a/plugins/card-resources/package.json +++ b/plugins/card-resources/package.json @@ -73,6 +73,7 @@ "@hcengineering/communication": "^0.6.0", "@hcengineering/preference": "^0.6.13", "@hcengineering/account-client": "^0.6.0", + "@hcengineering/chat": "^0.6.0", "fast-equals": "^5.2.2", "svelte": "^4.2.19" } diff --git a/plugins/card-resources/src/components/NewCardForm.svelte b/plugins/card-resources/src/components/NewCardForm.svelte index 9330493957..507ec88ac7 100644 --- a/plugins/card-resources/src/components/NewCardForm.svelte +++ b/plugins/card-resources/src/components/NewCardForm.svelte @@ -30,13 +30,14 @@ import { markupToMarkdown } from '@hcengineering/text-markdown' import textEditor, { type RefAction } from '@hcengineering/text-editor' import { defaultMessageInputActions } from '@hcengineering/communication-resources' + import chat from '@hcengineering/chat' import EditorActions from './EditorActions.svelte' const dispatch = createEventDispatcher() const communicationClient = getCommunicationClient() - const threadMasterTag = 'chat:masterTag:Thread' as Ref + const threadMasterTag = chat.masterTag.Thread let title: string = '' let space: Ref | undefined = undefined diff --git a/plugins/card-resources/src/components/navigator-next/Navigator.svelte b/plugins/card-resources/src/components/navigator-next/Navigator.svelte index f9bc49f8e2..01358f8281 100644 --- a/plugins/card-resources/src/components/navigator-next/Navigator.svelte +++ b/plugins/card-resources/src/components/navigator-next/Navigator.svelte @@ -20,7 +20,6 @@ import { createEventDispatcher } from 'svelte' import { SavedView } from '@hcengineering/workbench-resources' import { getCurrentAccount, SortingOrder, Ref } from '@hcengineering/core' - import { TreeItem } from '@hcengineering/view-resources' import { type NavigatorConfig } from '../../types' import NavigatorSpace from './NavigatorSpace.svelte' @@ -97,13 +96,6 @@ selectedSpecial = 'favorites' dispatch('favorites') } - - function onHomeClick (): void { - selectedCard = undefined - selectedType = undefined - selectedSpecial = 'home' - dispatch('home') - } @@ -111,15 +103,6 @@ {#if config.savedViews} {/if} - {#if config.home} - - {/if} {#if config.groupBySpace} {#each spaces as space (space._id)} => ({ component: { diff --git a/plugins/card-resources/src/plugin.ts b/plugins/card-resources/src/plugin.ts index ad9506b5dd..d283fbb5e2 100644 --- a/plugins/card-resources/src/plugin.ts +++ b/plugins/card-resources/src/plugin.ts @@ -101,13 +101,9 @@ export default mergeIds(cardId, card, { Properties: '' as IntlString, NoChildren: '' as IntlString, AddCollaborators: '' as IntlString, - Home: '' as IntlString, CardTitle: '' as IntlString, CardContent: '' as IntlString, Post: '' as IntlString, - Compact: '' as IntlString, - Comfortable: '' as IntlString, - Comfortable2: '' as IntlString, ShowLess: '' as IntlString } }) diff --git a/plugins/card-resources/src/types.ts b/plugins/card-resources/src/types.ts index 0eb2670f26..49eebc6df2 100644 --- a/plugins/card-resources/src/types.ts +++ b/plugins/card-resources/src/types.ts @@ -18,7 +18,6 @@ import { type Heading } from '@hcengineering/text-editor' interface BaseNavigatorConfig { types: Array> - home?: boolean groupBySpace?: boolean savedViews?: boolean allowCreate?: boolean diff --git a/plugins/chat-resources/src/components/ChatApplication.svelte b/plugins/chat-resources/src/components/ChatApplication.svelte index 35f89fde70..9ce56562ee 100644 --- a/plugins/chat-resources/src/components/ChatApplication.svelte +++ b/plugins/chat-resources/src/components/ChatApplication.svelte @@ -30,7 +30,7 @@ import { chatId } from '@hcengineering/chat' import { Ref } from '@hcengineering/core' import view from '@hcengineering/view' - import { Favorites, Home } from '@hcengineering/card-resources' + import { Favorites } from '@hcengineering/card-resources' import ChatNavigation from './ChatNavigation.svelte' import { @@ -39,9 +39,7 @@ navigateToType, getTypeIdFromLocation, isFavoritesLocation, - navigateToFavorites, - navigateToHome, - isHomeLocation + navigateToFavorites } from '../location' import ChatNavigationCategoryList from './ChatNavigationCategoryList.svelte' @@ -57,7 +55,6 @@ doc: MasterTag } | { type: 'favorites' } - | { type: 'home' } const client = getClient() const hierarchy = client.getHierarchy() @@ -77,18 +74,12 @@ const typeId = getTypeIdFromLocation(loc) const cardId = getCardIdFromLocation(loc) const isFavorites = isFavoritesLocation(loc) - const isHome = isHomeLocation(loc) if (isFavorites) { selection = { type: 'favorites' } return } - if (isHome) { - selection = { type: 'home' } - return - } - const type = typeId != null ? await client.findOne(cardPlugin.class.MasterTag, { _id: typeId }) : undefined if (type != null) { @@ -136,13 +127,6 @@ navigateToFavorites() } - function selectHome (): void { - if (selection?.type === 'home') return - closePanel(false) - selection = { type: 'home' } - navigateToHome() - } - function getSelectedCard (selection: Selection | undefined): Card | undefined { if (selection?.type !== 'card') return undefined return selection.doc @@ -184,7 +168,6 @@ on:selectCard={selectCard} on:selectType={selectType} on:favorites={selectFavorites} - on:home={selectHome} /> {#if !($deviceInfo.isMobile && $deviceInfo.isPortrait && $deviceInfo.minWidth)} @@ -205,10 +188,6 @@ {#key selection.type} {/key} - {:else if selection?.type === 'home'} - {#key selection.type} - - {/key} {:else if selectedCard} {@const panelComponent = hierarchy.classHierarchyMixin(selectedCard._class, view.mixin.ObjectPanel)} {@const comp = panelComponent?.component ?? view.component.EditDoc} diff --git a/plugins/chat-resources/src/components/ChatNavigation.svelte b/plugins/chat-resources/src/components/ChatNavigation.svelte index 4dd42bf442..bb4018fd52 100644 --- a/plugins/chat-resources/src/components/ChatNavigation.svelte +++ b/plugins/chat-resources/src/components/ChatNavigation.svelte @@ -23,15 +23,12 @@ export let card: Card | undefined = undefined export let type: Ref | undefined = undefined - export let special: 'home' | 'favorites' | string | undefined = undefined + export let special: 'favorites' | string | undefined = undefined - function getSpecial (special: 'home' | 'favorites' | string | undefined): string | undefined { + function getSpecial (special: 'favorites' | string | undefined): string | undefined { if (special === 'favorites') { return 'favorites' } - if (special === 'home') { - return 'home' - } return undefined } @@ -44,7 +41,6 @@ groupBySpace: false, hideEmpty: true, limit: 5, - home: true, labelFilter: [SubscriptionLabelID], preorder: [ { type: chat.masterTag.Thread, order: 1 }, @@ -67,5 +63,4 @@ on:selectType on:selectCard on:favorites - on:home /> diff --git a/plugins/chat-resources/src/location.ts b/plugins/chat-resources/src/location.ts index df6e7ed8b7..6441ce02c5 100644 --- a/plugins/chat-resources/src/location.ts +++ b/plugins/chat-resources/src/location.ts @@ -26,10 +26,6 @@ export function isFavoritesLocation (loc: Location): boolean { return loc.path[2] === chatId && loc.path[3] === 'favorites' } -export function isHomeLocation (loc: Location): boolean { - return loc.path[2] === chatId && loc.path[3] === 'home' -} - export function getCardIdFromLocation (loc: Location): Ref | undefined { if (loc.path[2] !== chatId) { return undefined @@ -82,16 +78,6 @@ export function navigateToFavorites (): void { navigate(loc) } -export function navigateToHome (): void { - const loc = getCurrentResolvedLocation() - - loc.path[2] = chatId - loc.path[3] = 'home' - delete loc.query?.message - - navigate(loc) -} - export async function resolveLocation (loc: Location): Promise { if (loc.path[2] !== chatId) { return undefined diff --git a/plugins/home-assets/.eslintrc.js b/plugins/home-assets/.eslintrc.js new file mode 100644 index 0000000000..e73094bc7e --- /dev/null +++ b/plugins/home-assets/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: ['./node_modules/@hcengineering/platform-rig/profiles/assets/eslint.config.json'], + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig.json' + } +} diff --git a/plugins/home-assets/assets/icons.svg b/plugins/home-assets/assets/icons.svg new file mode 100644 index 0000000000..0521d38daa --- /dev/null +++ b/plugins/home-assets/assets/icons.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/plugins/home-assets/config/rig.json b/plugins/home-assets/config/rig.json new file mode 100644 index 0000000000..b75800b9b7 --- /dev/null +++ b/plugins/home-assets/config/rig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + "rigPackageName": "@hcengineering/platform-rig", + "rigProfile": "assets" +} diff --git a/plugins/home-assets/jest.config.js b/plugins/home-assets/jest.config.js new file mode 100644 index 0000000000..2cfd408b67 --- /dev/null +++ b/plugins/home-assets/jest.config.js @@ -0,0 +1,7 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'], + roots: ["./src"], + coverageReporters: ["text-summary", "html"] +} diff --git a/plugins/home-assets/lang/cs.json b/plugins/home-assets/lang/cs.json new file mode 100644 index 0000000000..009730fce9 --- /dev/null +++ b/plugins/home-assets/lang/cs.json @@ -0,0 +1,11 @@ +{ + "string": { + "Home": "Domov", + "All": "Všechny aktualizace", + "CreatedByMe": "Vytvořeno mnou", + "Threads": "Vlákna", + "Compact": "Kompaktní", + "Comfortable": "Komfortní", + "Comfortable2": "Komfortní 2" + } +} diff --git a/plugins/home-assets/lang/de.json b/plugins/home-assets/lang/de.json new file mode 100644 index 0000000000..569bc8ab1e --- /dev/null +++ b/plugins/home-assets/lang/de.json @@ -0,0 +1,11 @@ +{ + "string": { + "Home": "Startseite", + "All": "Alle Updates", + "CreatedByMe": "Von mir erstellt", + "Threads": "Threads", + "Compact": "Kompakt", + "Comfortable": "Komfortabel", + "Comfortable2": "Komfortabel 2" + } +} diff --git a/plugins/home-assets/lang/en.json b/plugins/home-assets/lang/en.json new file mode 100644 index 0000000000..ec5fc0b66b --- /dev/null +++ b/plugins/home-assets/lang/en.json @@ -0,0 +1,11 @@ +{ + "string": { + "Home": "Home", + "All": "All updates", + "CreatedByMe": "Created by me", + "Threads": "Threads", + "Compact": "Compact", + "Comfortable": "Comfortable", + "Comfortable2": "Comfortable 2" + } +} diff --git a/plugins/home-assets/lang/es.json b/plugins/home-assets/lang/es.json new file mode 100644 index 0000000000..b7186b52ee --- /dev/null +++ b/plugins/home-assets/lang/es.json @@ -0,0 +1,11 @@ +{ + "string": { + "Home": "Inicio", + "All": "Todas las actualizaciones", + "CreatedByMe": "Creado por mí", + "Threads": "Hilos", + "Compact": "Compacto", + "Comfortable": "Confortable", + "Comfortable2": "Confortable 2" + } +} diff --git a/plugins/home-assets/lang/fr.json b/plugins/home-assets/lang/fr.json new file mode 100644 index 0000000000..3ab9219f42 --- /dev/null +++ b/plugins/home-assets/lang/fr.json @@ -0,0 +1,11 @@ +{ + "string": { + "Home": "Accueil", + "All": "Toutes les mises à jour", + "CreatedByMe": "Créé par moi", + "Threads": "Fils", + "Compact": "Compact", + "Comfortable": "Confortable", + "Comfortable2": "Confortable 2" + } +} diff --git a/plugins/home-assets/lang/it.json b/plugins/home-assets/lang/it.json new file mode 100644 index 0000000000..c8f0d1160d --- /dev/null +++ b/plugins/home-assets/lang/it.json @@ -0,0 +1,11 @@ +{ + "string": { + "Home": "Casa", + "All": "Tutti gli aggiornamenti", + "CreatedByMe": "Creato da me", + "Threads": "Thread", + "Compact": "Compatto", + "Comfortable": "Comodo", + "Comfortable2": "Comodo 2" + } +} diff --git a/plugins/home-assets/lang/ja.json b/plugins/home-assets/lang/ja.json new file mode 100644 index 0000000000..3f83fb4d43 --- /dev/null +++ b/plugins/home-assets/lang/ja.json @@ -0,0 +1,11 @@ +{ + "string": { + "Home": "ホーム", + "All": "すべての更新", + "CreatedByMe": "自分が作成", + "Threads": "スレッド", + "Compact": "コンパクト", + "Comfortable": "快適", + "Comfortable2": "快適2" + } +} diff --git a/plugins/home-assets/lang/pt.json b/plugins/home-assets/lang/pt.json new file mode 100644 index 0000000000..1a8a058e6d --- /dev/null +++ b/plugins/home-assets/lang/pt.json @@ -0,0 +1,11 @@ +{ + "string": { + "Home": "Início", + "All": "Todas as atualizações", + "CreatedByMe": "Criado por mim", + "Threads": "Threads", + "Compact": "Compacto", + "Comfortable": "Confortável", + "Comfortable2": "Confortável 2" + } +} diff --git a/plugins/home-assets/lang/ru.json b/plugins/home-assets/lang/ru.json new file mode 100644 index 0000000000..1b81325e22 --- /dev/null +++ b/plugins/home-assets/lang/ru.json @@ -0,0 +1,11 @@ +{ + "string": { + "Home": "Главная", + "All": "Все обновления", + "CreatedByMe": "Созданные мной", + "Threads": "Потоки", + "Compact": "Компактный", + "Comfortable": "Комфортный", + "Comfortable2": "Комфортный 2" + } +} diff --git a/plugins/home-assets/lang/zh.json b/plugins/home-assets/lang/zh.json new file mode 100644 index 0000000000..74c7f44398 --- /dev/null +++ b/plugins/home-assets/lang/zh.json @@ -0,0 +1,11 @@ +{ + "string": { + "Home": "主页", + "All": "所有更新", + "CreatedByMe": "我创建的", + "Threads": "主题", + "Compact": "紧凑", + "Comfortable": "舒适", + "Comfortable2": "舒适2" + } +} diff --git a/plugins/home-assets/package.json b/plugins/home-assets/package.json new file mode 100644 index 0000000000..21e6a68617 --- /dev/null +++ b/plugins/home-assets/package.json @@ -0,0 +1,39 @@ +{ + "name": "@hcengineering/home-assets", + "version": "0.6.0", + "main": "src/index.ts", + "author": "Hardcore Engineering Inc", + "template": "@hcengineering/assets-package", + "license": "EPL-2.0", + "scripts": { + "build": "compile", + "test": "jest --passWithNoTests --silent", + "build:docs": "", + "format": "format src", + "build:watch": "compile", + "_phase:build": "compile transpile src", + "_phase:test": "jest --passWithNoTests --silent", + "_phase:format": "format src", + "_phase:validate": "compile validate" + }, + "devDependencies": { + "@hcengineering/platform-rig": "^0.6.0", + "@typescript-eslint/eslint-plugin": "^6.11.0", + "@typescript-eslint/parser": "^6.11.0", + "eslint-config-standard-with-typescript": "^40.0.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.4.0", + "eslint-plugin-promise": "^6.1.1", + "eslint": "^8.54.0", + "prettier": "^3.1.0", + "@types/node": "^22.15.29", + "jest": "^29.7.0", + "ts-jest": "^29.1.1", + "@types/jest": "^29.5.5", + "typescript": "^5.8.3" + }, + "dependencies": { + "@hcengineering/platform": "^0.6.11", + "@hcengineering/home": "^0.6.0" + } +} diff --git a/plugins/home-assets/src/__tests__/lang.test.ts b/plugins/home-assets/src/__tests__/lang.test.ts new file mode 100644 index 0000000000..49a0581296 --- /dev/null +++ b/plugins/home-assets/src/__tests__/lang.test.ts @@ -0,0 +1,21 @@ +// +// Copyright © 2025 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { makeLocalesTest } from '@hcengineering/platform' + +it( + 'Locales are equal', + makeLocalesTest((lang) => import(`../../lang/${lang}.json`)) +) diff --git a/plugins/home-assets/src/index.ts b/plugins/home-assets/src/index.ts new file mode 100644 index 0000000000..f9903fe7c5 --- /dev/null +++ b/plugins/home-assets/src/index.ts @@ -0,0 +1,24 @@ +// +// Copyright © 2025 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { loadMetadata } from '@hcengineering/platform' +import home from '@hcengineering/home' + +const icons = require('../assets/icons.svg') as string // eslint-disable-line +loadMetadata(home.icon, { + Home: `${icons}#home`, + Person: `${icons}#person`, + Thread: `${icons}#thread` +}) diff --git a/plugins/home-assets/tsconfig.json b/plugins/home-assets/tsconfig.json new file mode 100644 index 0000000000..2857a41ad2 --- /dev/null +++ b/plugins/home-assets/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "./node_modules/@hcengineering/platform-rig/profiles/assets/tsconfig.json", + + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "declarationDir": "./types", + "types": ["node", "jest"], + "tsBuildInfoFile": ".build/build.tsbuildinfo" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "lib", "dist", "types", "bundle"] +} \ No newline at end of file diff --git a/plugins/home-resources/.eslintrc.js b/plugins/home-resources/.eslintrc.js new file mode 100644 index 0000000000..bb8fd7450d --- /dev/null +++ b/plugins/home-resources/.eslintrc.js @@ -0,0 +1,4 @@ +module.exports = { + extends: ['./node_modules/@hcengineering/platform-rig/profiles/ui/eslint.config.json'], + parserOptions: { tsconfigRootDir: __dirname } +} diff --git a/plugins/home-resources/.prettierrc b/plugins/home-resources/.prettierrc new file mode 100644 index 0000000000..792942803a --- /dev/null +++ b/plugins/home-resources/.prettierrc @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "trailingComma": "none", + "tabWidth": 2, + "semi": false, + "singleQuote": true, + "printWidth": 120, + "useTabs": false, + "bracketSpacing": true, + "proseWrap": "preserve", + "plugins": [ + "prettier-plugin-svelte" + ], + "overrides": [ + { + "files": "*.svelte", + "options": { + "parser": "svelte" + } + } + ] +} \ No newline at end of file diff --git a/plugins/home-resources/config/rig.json b/plugins/home-resources/config/rig.json new file mode 100644 index 0000000000..bcad6f7c33 --- /dev/null +++ b/plugins/home-resources/config/rig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + "rigPackageName": "@hcengineering/platform-rig", + "rigProfile": "ui" +} diff --git a/plugins/home-resources/jest.config.js b/plugins/home-resources/jest.config.js new file mode 100644 index 0000000000..3656e284d3 --- /dev/null +++ b/plugins/home-resources/jest.config.js @@ -0,0 +1,5 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'] +} diff --git a/plugins/home-resources/package.json b/plugins/home-resources/package.json new file mode 100644 index 0000000000..74dd0db03a --- /dev/null +++ b/plugins/home-resources/package.json @@ -0,0 +1,60 @@ +{ + "name": "@hcengineering/home-resources", + "version": "0.6.0", + "main": "src/index.ts", + "author": "Hardcore Engineering Inc", + "license": "EPL-2.0", + "scripts": { + "build": "compile ui", + "build:docs": "api-extractor run --local", + "format": "format src", + "svelte-check": "do-svelte-check", + "_phase:svelte-check": "do-svelte-check", + "build:watch": "compile ui", + "_phase:build": "compile ui", + "_phase:format": "format src", + "_phase:validate": "compile validate" + }, + "devDependencies": { + "@hcengineering/platform-rig": "^0.6.0", + "@types/jest": "^29.5.5", + "@typescript-eslint/eslint-plugin": "^6.11.0", + "@typescript-eslint/parser": "^6.11.0", + "eslint": "^8.54.0", + "eslint-config-standard-with-typescript": "^40.0.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.4.0", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-svelte": "^2.35.1", + "jest": "^29.7.0", + "prettier": "^3.1.0", + "prettier-plugin-svelte": "^3.2.2", + "sass": "^1.53.0", + "svelte-check": "^3.6.9", + "svelte-eslint-parser": "^0.33.1", + "svelte-loader": "^3.2.0", + "svelte-preprocess": "^5.1.3", + "ts-jest": "^29.1.1", + "typescript": "^5.8.3" + }, + "dependencies": { + "@hcengineering/analytics": "^0.6.0", + "@hcengineering/card": "^0.6.0", + "@hcengineering/card-resources": "^0.6.0", + "@hcengineering/chat": "^0.6.0", + "@hcengineering/core": "^0.6.32", + "@hcengineering/contact": "^0.6.24", + "@hcengineering/contact-resources": "^0.6.0", + "@hcengineering/communication-types": "^0.1.0", + "@hcengineering/communication-resources": "^0.6.0", + "@hcengineering/home": "^0.6.0", + "@hcengineering/platform": "^0.6.11", + "@hcengineering/presentation": "^0.6.3", + "@hcengineering/ui": "^0.6.15", + "@hcengineering/view": "^0.6.13", + "@hcengineering/view-resources": "^0.6.0", + "@hcengineering/workbench-resources": "^0.6.1", + "fast-equals": "^5.2.2", + "svelte": "^4.2.19" + } +} diff --git a/plugins/home-resources/postcss.config.js b/plugins/home-resources/postcss.config.js new file mode 100644 index 0000000000..88752c6cb0 --- /dev/null +++ b/plugins/home-resources/postcss.config.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: [ + require('autoprefixer') + ] +} diff --git a/plugins/card-resources/src/components/Home.svelte b/plugins/home-resources/src/components/Home.svelte similarity index 81% rename from plugins/card-resources/src/components/Home.svelte rename to plugins/home-resources/src/components/Home.svelte index cbcefc89a4..671c96e713 100644 --- a/plugins/card-resources/src/components/Home.svelte +++ b/plugins/home-resources/src/components/Home.svelte @@ -11,9 +11,9 @@ + +
+ {#if $deviceInfo.navigator.visible} + + + {/if} + +
+ +
+
diff --git a/plugins/card-resources/src/components/HomeCardPresenter.svelte b/plugins/home-resources/src/components/HomeCardPresenter.svelte similarity index 96% rename from plugins/card-resources/src/components/HomeCardPresenter.svelte rename to plugins/home-resources/src/components/HomeCardPresenter.svelte index e74b0e0f1b..5b3c09a02a 100644 --- a/plugins/card-resources/src/components/HomeCardPresenter.svelte +++ b/plugins/home-resources/src/components/HomeCardPresenter.svelte @@ -22,12 +22,9 @@ import { Button, IconMoreH, tooltip } from '@hcengineering/ui' import { showMenu } from '@hcengineering/view-resources' import { getEmbeddedLabel } from '@hcengineering/platform' + import { CardTagsColored, CardPathPresenter, CardTimestamp, openCardInSidebar } from '@hcengineering/card-resources' import { isHomeSettingEnabled, compactSettingId, homeSettingsStore, comfortableSettingId2 } from '../home' - import { openCardInSidebar } from '../utils' - import CardTagsColored from './CardTagsColored.svelte' - import CardPathPresenter from './CardPathPresenter.svelte' - import CardTimestamp from './CardTimestamp.svelte' import SystemAvatar from '@hcengineering/contact-resources/src/components/SystemAvatar.svelte' export let card: WithLookup diff --git a/plugins/card-resources/src/components/HomeSettings.svelte b/plugins/home-resources/src/components/HomeSettings.svelte similarity index 96% rename from plugins/card-resources/src/components/HomeSettings.svelte rename to plugins/home-resources/src/components/HomeSettings.svelte index 9b9adcf698..31086613a8 100644 --- a/plugins/card-resources/src/components/HomeSettings.svelte +++ b/plugins/home-resources/src/components/HomeSettings.svelte @@ -16,7 +16,7 @@ import { createEventDispatcher } from 'svelte' import { createFocusManager, FocusHandler, Label, ListView, ModernToggle, resizeObserver } from '@hcengineering/ui' - import card from '../plugin' + import home from '../plugin' import { updateHomeSetting, @@ -35,15 +35,15 @@ const items = [ { id: compactSettingId, - label: card.string.Compact + label: home.string.Compact }, { id: comfortableSettingId, - label: card.string.Comfortable + label: home.string.Comfortable }, { id: comfortableSettingId2, - label: card.string.Comfortable2 + label: home.string.Comfortable2 } ] diff --git a/plugins/home-resources/src/components/Navigator.svelte b/plugins/home-resources/src/components/Navigator.svelte new file mode 100644 index 0000000000..46cf2959ad --- /dev/null +++ b/plugins/home-resources/src/components/Navigator.svelte @@ -0,0 +1,54 @@ + + + +
+
+ + {#each specials as special} + + + + {/each} + + (menuSelection = res.detail)} /> + +
+ + +
+
diff --git a/plugins/card-resources/src/home.ts b/plugins/home-resources/src/home.ts similarity index 100% rename from plugins/card-resources/src/home.ts rename to plugins/home-resources/src/home.ts diff --git a/plugins/home-resources/src/index.ts b/plugins/home-resources/src/index.ts new file mode 100644 index 0000000000..cee80121b6 --- /dev/null +++ b/plugins/home-resources/src/index.ts @@ -0,0 +1,24 @@ +// +// Copyright © 2025 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { type Resources } from '@hcengineering/platform' + +import HomeApplication from './components/HomeApplication.svelte' + +export default async (): Promise => ({ + component: { + HomeApplication + } +}) diff --git a/plugins/home-resources/src/plugin.ts b/plugins/home-resources/src/plugin.ts new file mode 100644 index 0000000000..262a58f2c9 --- /dev/null +++ b/plugins/home-resources/src/plugin.ts @@ -0,0 +1,32 @@ +// +// Copyright © 2025 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import home, { homeId } from '@hcengineering/home' +import { type IntlString, mergeIds } from '@hcengineering/platform' +import type { AnyComponent } from '@hcengineering/ui' + +export default mergeIds(homeId, home, { + component: { + HomeApplication: '' as AnyComponent + }, + string: { + All: '' as IntlString, + CreatedByMe: '' as IntlString, + Threads: '' as IntlString, + Compact: '' as IntlString, + Comfortable: '' as IntlString, + Comfortable2: '' as IntlString + } +}) diff --git a/plugins/home-resources/src/types.ts b/plugins/home-resources/src/types.ts new file mode 100644 index 0000000000..55cd23c586 --- /dev/null +++ b/plugins/home-resources/src/types.ts @@ -0,0 +1,25 @@ +// Copyright © 2025 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { Card, MasterTag } from '@hcengineering/card' +import { type DocumentQuery, type Ref } from '@hcengineering/core' +import { type IntlString, type Asset } from '@hcengineering/platform' +import type { AnySvelteComponent } from '@hcengineering/ui' + +export interface Special { + _id: string + label: IntlString + icon: Asset | AnySvelteComponent + baseQuery: DocumentQuery + baseClass?: Ref +} diff --git a/plugins/home-resources/svelte.config.js b/plugins/home-resources/svelte.config.js new file mode 100644 index 0000000000..944a06f73e --- /dev/null +++ b/plugins/home-resources/svelte.config.js @@ -0,0 +1,5 @@ +const sveltePreprocess = require('svelte-preprocess') + +module.exports = { + preprocess: sveltePreprocess() +}; \ No newline at end of file diff --git a/plugins/home-resources/tsconfig.json b/plugins/home-resources/tsconfig.json new file mode 100644 index 0000000000..14ada1dc34 --- /dev/null +++ b/plugins/home-resources/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "./node_modules/@hcengineering/platform-rig/profiles/ui/tsconfig.json", + + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "declarationDir": "./types" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "lib", "dist", "types", "bundle"] +} \ No newline at end of file diff --git a/plugins/home/.eslintrc.js b/plugins/home/.eslintrc.js new file mode 100644 index 0000000000..72235dc283 --- /dev/null +++ b/plugins/home/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'], + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig.json' + } +} diff --git a/plugins/home/.npmignore b/plugins/home/.npmignore new file mode 100644 index 0000000000..e3ec093c38 --- /dev/null +++ b/plugins/home/.npmignore @@ -0,0 +1,4 @@ +* +!/lib/** +!CHANGELOG.md +/lib/**/__tests__/ diff --git a/plugins/home/config/rig.json b/plugins/home/config/rig.json new file mode 100644 index 0000000000..0110930f55 --- /dev/null +++ b/plugins/home/config/rig.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + "rigPackageName": "@hcengineering/platform-rig" +} diff --git a/plugins/home/jest.config.js b/plugins/home/jest.config.js new file mode 100644 index 0000000000..2cfd408b67 --- /dev/null +++ b/plugins/home/jest.config.js @@ -0,0 +1,7 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'], + roots: ["./src"], + coverageReporters: ["text-summary", "html"] +} diff --git a/plugins/home/package.json b/plugins/home/package.json new file mode 100644 index 0000000000..2226d38782 --- /dev/null +++ b/plugins/home/package.json @@ -0,0 +1,47 @@ +{ + "name": "@hcengineering/home", + "version": "0.6.0", + "main": "lib/index.js", + "svelte": "src/index.ts", + "types": "types/index.d.ts", + "files": [ + "lib/**/*", + "types/**/*", + "tsconfig.json" + ], + "author": "Hardcore Engineering Inc", + "license": "EPL-2.0", + "scripts": { + "build": "compile", + "build:watch": "compile", + "format": "format src", + "test": "jest --passWithNoTests --silent", + "_phase:build": "compile transpile src", + "_phase:test": "jest --passWithNoTests --silent", + "_phase:format": "format src", + "_phase:validate": "compile validate" + }, + "devDependencies": { + "@hcengineering/platform-rig": "^0.6.0", + "@typescript-eslint/eslint-plugin": "^6.11.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-n": "^15.4.0", + "eslint": "^8.54.0", + "@typescript-eslint/parser": "^6.11.0", + "eslint-config-standard-with-typescript": "^40.0.0", + "prettier": "^3.1.0", + "typescript": "^5.8.3", + "jest": "^29.7.0", + "ts-jest": "^29.1.1", + "@types/jest": "^29.5.5" + }, + "dependencies": { + "@hcengineering/core": "^0.6.32", + "@hcengineering/platform": "^0.6.11" + }, + "repository": "https://github.com/hcengineering/platform", + "publishConfig": { + "registry": "https://npm.pkg.github.com" + } +} diff --git a/plugins/home/src/index.ts b/plugins/home/src/index.ts new file mode 100644 index 0000000000..8da22af43a --- /dev/null +++ b/plugins/home/src/index.ts @@ -0,0 +1,31 @@ +// +// Copyright © 2025 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { Asset, IntlString, type Plugin, plugin } from '@hcengineering/platform' + +export const homeId = 'home' as Plugin + +const home = plugin(homeId, { + string: { + Home: '' as IntlString + }, + icon: { + Home: '' as Asset, + Person: '' as Asset, + Thread: '' as Asset + } +}) + +export default home diff --git a/plugins/home/tsconfig.json b/plugins/home/tsconfig.json new file mode 100644 index 0000000000..b5ae22f6e4 --- /dev/null +++ b/plugins/home/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json", + + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "declarationDir": "./types", + "tsBuildInfoFile": ".build/build.tsbuildinfo" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "lib", "dist", "types", "bundle"] +} \ No newline at end of file diff --git a/rush.json b/rush.json index 33787b5ff3..372ba7b7a4 100644 --- a/rush.json +++ b/rush.json @@ -2697,6 +2697,26 @@ "packageName": "@hcengineering/pod-worker", "projectFolder": "services/worker", "shouldPublish": false - } + }, + { + "packageName": "@hcengineering/home", + "projectFolder": "plugins/home", + "shouldPublish": false + }, + { + "packageName": "@hcengineering/home-assets", + "projectFolder": "plugins/home-assets", + "shouldPublish": false + }, + { + "packageName": "@hcengineering/home-resources", + "projectFolder": "plugins/home-resources", + "shouldPublish": false + }, + { + "packageName": "@hcengineering/model-home", + "projectFolder": "models/home", + "shouldPublish": false + }, ] }