From 38cd6b156a78c493e369424c0e1edb2d3c2a1328 Mon Sep 17 00:00:00 2001 From: Richard Tan Date: Mon, 23 Dec 2024 14:16:53 +0800 Subject: [PATCH 1/9] Absolute urls on crm app --- packages/experiments-realm/crm-app.gts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/experiments-realm/crm-app.gts b/packages/experiments-realm/crm-app.gts index 12844a205c..1abf5043ca 100644 --- a/packages/experiments-realm/crm-app.gts +++ b/packages/experiments-realm/crm-app.gts @@ -130,7 +130,8 @@ class CrmAppTemplate extends Component { } const lastIndex = summary.id.lastIndexOf('/'); let cardRef = { - module: summary.id.substring(0, lastIndex), + module: new URL(summary.id.substring(0, lastIndex), import.meta.url) + .href, name: summary.id.substring(lastIndex + 1), }; filter.cardRef = cardRef; From 0b269b56cb0ece4027ed0167078ed3235908dd3b Mon Sep 17 00:00:00 2001 From: Richard Tan Date: Mon, 23 Dec 2024 14:39:33 +0800 Subject: [PATCH 2/9] Crm app clean up --- packages/experiments-realm/crm-app.gts | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/packages/experiments-realm/crm-app.gts b/packages/experiments-realm/crm-app.gts index 1abf5043ca..d11bd9b694 100644 --- a/packages/experiments-realm/crm-app.gts +++ b/packages/experiments-realm/crm-app.gts @@ -23,12 +23,7 @@ import { } from '@cardstack/boxel-ui/components'; import { IconPlus } from '@cardstack/boxel-ui/icons'; import { AppCard, Tab } from './app-card'; -import { - Query, - CardError, - SupportedMimeType, - codeRefWithAbsoluteURL, -} from '@cardstack/runtime-common'; +import { Query, CardError, SupportedMimeType } from '@cardstack/runtime-common'; import ContactIcon from '@cardstack/boxel-icons/contact'; import HeartHandshakeIcon from '@cardstack/boxel-icons/heart-handshake'; import TargetArrowIcon from '@cardstack/boxel-icons/target-arrow'; @@ -173,15 +168,6 @@ class CrmAppTemplate extends Component { return this.activeTab?.tabId ? this.activeTab.tabId.toLowerCase() : ''; } - get activeTabRef() { - if (!this.activeTab?.ref?.name || !this.activeTab.ref.module) { - return; - } - if (!this.currentRealm) { - return; - } - return codeRefWithAbsoluteURL(this.activeTab.ref, this.currentRealm); - } setTabs(tabs: Tab[]) { this.args.model.tabs = tabs ?? []; } From e3435d0cf45f9b13e6cb675dc73fb54c7ec4d9c1 Mon Sep 17 00:00:00 2001 From: Richard Tan Date: Mon, 23 Dec 2024 15:37:32 +0800 Subject: [PATCH 3/9] Absolute urls on crm app --- packages/experiments-realm/crm-app.gts | 6 ++++-- packages/experiments-realm/crm/deal.gts | 12 ++---------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/experiments-realm/crm-app.gts b/packages/experiments-realm/crm-app.gts index d11bd9b694..6e301cea17 100644 --- a/packages/experiments-realm/crm-app.gts +++ b/packages/experiments-realm/crm-app.gts @@ -125,8 +125,10 @@ class CrmAppTemplate extends Component { } const lastIndex = summary.id.lastIndexOf('/'); let cardRef = { - module: new URL(summary.id.substring(0, lastIndex), import.meta.url) - .href, + module: new URL( + `./${summary.id.substring(0, lastIndex)}`, + import.meta.url, + ).href, name: summary.id.substring(lastIndex + 1), }; filter.cardRef = cardRef; diff --git a/packages/experiments-realm/crm/deal.gts b/packages/experiments-realm/crm/deal.gts index 89b0ec1c11..908e1e469b 100644 --- a/packages/experiments-realm/crm/deal.gts +++ b/packages/experiments-realm/crm/deal.gts @@ -55,7 +55,6 @@ class IsolatedTemplate extends Component { ); } get primaryContactName() { - console.log(this.args.fields.account?.primaryContact); return this.args.model.account?.primaryContact?.name; } @@ -84,10 +83,6 @@ class IsolatedTemplate extends Component { return this.args.model[realmURL]!; } - get realmHref() { - return this.realmURL.href; - } - get realmHrefs() { return [this.realmURL?.href]; } @@ -96,7 +91,7 @@ class IsolatedTemplate extends Component { return { filter: { type: { - module: `${this.realmHref}crm/deal`, + module: new URL('./crm/deal', import.meta.url).href, name: 'Deal', }, }, @@ -116,14 +111,11 @@ class IsolatedTemplate extends Component { (acc, deal: Deal) => acc + deal.computedValue.amount, 0, ); - nonZeroDeals.map((d) => console.log(d.computedValue.amount)); - console.log('totalDealRevenue', totalDealRevenue); let avgDealSize = totalDealRevenue / nonZeroDeals.length; - console.log('avgDealSize', avgDealSize); + if (this.args.model.computedValue?.amount) { let percentDiff = (this.args.model.computedValue?.amount - avgDealSize) / avgDealSize; - console.log('percentDiff', percentDiff); let positive = percentDiff >= 0 ? true : false; let summary = `${percentDiff.toFixed(2)}% ${ positive ? 'above' : 'below' From 8c973f4fa6d72c3bbdf377e199c01c9da76c8af3 Mon Sep 17 00:00:00 2001 From: Richard Tan Date: Thu, 26 Dec 2024 16:58:51 +0800 Subject: [PATCH 4/9] Revert filter need absolute url since app card handled --- packages/experiments-realm/crm-app.gts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/experiments-realm/crm-app.gts b/packages/experiments-realm/crm-app.gts index 6e301cea17..22069dcee9 100644 --- a/packages/experiments-realm/crm-app.gts +++ b/packages/experiments-realm/crm-app.gts @@ -125,10 +125,7 @@ class CrmAppTemplate extends Component { } const lastIndex = summary.id.lastIndexOf('/'); let cardRef = { - module: new URL( - `./${summary.id.substring(0, lastIndex)}`, - import.meta.url, - ).href, + module: summary.id.substring(0, lastIndex), name: summary.id.substring(lastIndex + 1), }; filter.cardRef = cardRef; From 22e030b419ea7f755a56e0d63d2662ead6eeb04a Mon Sep 17 00:00:00 2001 From: Richard Tan Date: Thu, 26 Dec 2024 16:59:03 +0800 Subject: [PATCH 5/9] Rename display name --- packages/experiments-realm/crm-app.gts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/experiments-realm/crm-app.gts b/packages/experiments-realm/crm-app.gts index 22069dcee9..cbe93db585 100644 --- a/packages/experiments-realm/crm-app.gts +++ b/packages/experiments-realm/crm-app.gts @@ -449,7 +449,7 @@ class CrmAppTemplate extends Component { } export class CrmApp extends AppCard { - static displayName = 'Crm App'; + static displayName = 'CRM App'; static prefersWideFormat = true; static headerColor = '#4D3FE8'; static isolated = CrmAppTemplate; From 16b9a53c5a7aef1513c058f404fe1c49deb1207b Mon Sep 17 00:00:00 2001 From: Hassan Abdel-Rahman Date: Thu, 26 Dec 2024 12:59:31 -0500 Subject: [PATCH 6/9] Refactor indexing to get mtimes for entire realm in a single HTTP request --- packages/host/app/lib/current-run.ts | 47 +++++++---------- packages/realm-server/tests/helpers/index.ts | 38 ++++++++++++-- .../realm-server/tests/realm-server-test.ts | 52 ++++++++++++++++++- packages/runtime-common/realm.ts | 52 +++++++++++++++++++ packages/runtime-common/router.ts | 1 + packages/runtime-common/worker.ts | 36 ++++--------- 6 files changed, 167 insertions(+), 59 deletions(-) diff --git a/packages/host/app/lib/current-run.ts b/packages/host/app/lib/current-run.ts index 5a8ab028ba..e5348c10dd 100644 --- a/packages/host/app/lib/current-run.ts +++ b/packages/host/app/lib/current-run.ts @@ -228,7 +228,7 @@ export class CurrentRun { private async discoverInvalidations( url: URL, - mtimes: LastModifiedTimes, + indexMtimes: LastModifiedTimes, ): Promise { log.debug(`discovering invalidations in dir ${url.href}`); let ignorePatterns = await this.#reader.readFile( @@ -239,35 +239,26 @@ export class CurrentRun { this.#ignoreData[url.href] = ignorePatterns.content; } - let entries = await this.#reader.directoryListing(url); - - for (let { url, kind, lastModified } of entries) { - let innerURL = new URL(url); - if (isIgnored(this.#realmURL, this.ignoreMap, innerURL)) { + let filesystemMtimes = await this.#reader.mtimes(); + for (let [url, lastModified] of Object.entries(filesystemMtimes)) { + if (!url.endsWith('.json') && !hasExecutableExtension(url)) { + // Only allow json and executable files to be invalidated so that we + // don't end up with invalidated files that weren't meant to be indexed + // (images, etc) continue; } - - if (kind === 'directory') { - await this.discoverInvalidations(innerURL, mtimes); - } else { - if (!url.endsWith('.json') && !hasExecutableExtension(url)) { - // Only allow json and executable files to be invalidated so that we don't end up with invalidated files that weren't meant to be indexed (images, etc) - continue; - } - - let indexEntry = mtimes.get(innerURL.href); - if ( - !indexEntry || - indexEntry.type === 'error' || - indexEntry.lastModified == null - ) { - await this.batch.invalidate(innerURL); - continue; - } - - if (lastModified !== indexEntry.lastModified) { - await this.batch.invalidate(innerURL); - } + let indexEntry = indexMtimes.get(url); + + if ( + !indexEntry || + indexEntry.type === 'error' || + indexEntry.lastModified == null + ) { + await this.batch.invalidate(new URL(url)); + continue; + } + if (lastModified !== indexEntry.lastModified) { + await this.batch.invalidate(new URL(url)); } } } diff --git a/packages/realm-server/tests/helpers/index.ts b/packages/realm-server/tests/helpers/index.ts index 084dd8411d..ee57575503 100644 --- a/packages/realm-server/tests/helpers/index.ts +++ b/packages/realm-server/tests/helpers/index.ts @@ -1,4 +1,4 @@ -import { writeFileSync, writeJSONSync } from 'fs-extra'; +import { writeFileSync, writeJSONSync, readdirSync, statSync } from 'fs-extra'; import { NodeAdapter } from '../../node-realm'; import { resolve, join } from 'path'; import { @@ -14,14 +14,16 @@ import { maybeHandleScopedCSSRequest, insertPermissions, IndexWriter, - type MatrixConfig, - type QueuePublisher, - type QueueRunner, - type IndexRunner, asExpressions, query, insert, param, + unixTime, + RealmPaths, + type MatrixConfig, + type QueuePublisher, + type QueueRunner, + type IndexRunner, } from '@cardstack/runtime-common'; import { dirSync } from 'tmp'; import { getLocalConfig as getSynapseConfig } from '../../synapse'; @@ -401,6 +403,7 @@ export async function runTestRealmServer({ let testRealmHttpServer = testRealmServer.listen(parseInt(realmURL.port)); await testRealmServer.start(); return { + testRealmDir, testRealm, testRealmServer, testRealmHttpServer, @@ -494,3 +497,28 @@ export async function fetchSubscriptionsByUserId( stripeSubscriptionId: result.stripe_subscription_id, })); } + +export function mtimes( + path: string, + realmURL: URL, +): { [path: string]: number } { + const mtimes: { [path: string]: number } = {}; + let paths = new RealmPaths(realmURL); + + function traverseDir(currentPath: string) { + const entries = readdirSync(currentPath, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = join(currentPath, entry.name); + if (entry.isDirectory()) { + traverseDir(fullPath); + } else if (entry.isFile()) { + const stats = statSync(fullPath); + mtimes[paths.fileURL(fullPath.substring(path.length)).href] = unixTime( + stats.mtime.getTime(), + ); + } + } + } + traverseDir(path); + return mtimes; +} diff --git a/packages/realm-server/tests/realm-server-test.ts b/packages/realm-server/tests/realm-server-test.ts index 400fdbd557..f892a1f5ca 100644 --- a/packages/realm-server/tests/realm-server-test.ts +++ b/packages/realm-server/tests/realm-server-test.ts @@ -54,6 +54,7 @@ import { testRealmInfo, insertUser, insertPlan, + mtimes, fetchSubscriptionsByUserId, cleanWhiteSpace, } from './helpers'; @@ -152,6 +153,7 @@ module('Realm Server', function (hooks) { } let testRealm: Realm; + let testRealmPath: string; let testRealmHttpServer: Server; let request: SuperTest; let dir: DirResult; @@ -173,7 +175,11 @@ module('Realm Server', function (hooks) { copySync(join(__dirname, 'cards'), testRealmDir); } let virtualNetwork = createVirtualNetwork(); - ({ testRealm, testRealmHttpServer } = await runTestRealmServer({ + ({ + testRealm, + testRealmHttpServer, + testRealmDir: testRealmPath, + } = await runTestRealmServer({ virtualNetwork, testRealmDir, realmsRootPath: join(dir.name, 'realm_server_1'), @@ -210,6 +216,50 @@ module('Realm Server', function (hooks) { resetCatalogRealms(); }); + module('mtimes requests', function (hooks) { + setupPermissionedRealm(hooks, { + mary: ['read'], + }); + + test('non read permission GET /_mtimes', async function (assert) { + let response = await request + .get('/_mtimes') + .set('Accept', 'application/vnd.api+json') + .set('Authorization', `Bearer ${createJWT(testRealm, 'not-mary')}`); + + assert.strictEqual(response.status, 403, 'HTTP 403 status'); + }); + + test('read permission GET /_mtimes', async function (assert) { + let expectedMtimes = mtimes(testRealmPath, testRealmURL); + delete expectedMtimes[`${testRealmURL}.realm.json`]; + + let response = await request + .get('/_mtimes') + .set('Accept', 'application/vnd.api+json') + .set( + 'Authorization', + `Bearer ${createJWT(testRealm, 'mary', ['read'])}`, + ); + + assert.strictEqual(response.status, 200, 'HTTP 200 status'); + let json = response.body; + assert.deepEqual( + json, + { + data: { + type: 'mtimes', + id: testRealmHref, + attributes: { + mtimes: expectedMtimes, + }, + }, + }, + 'mtimes response is correct', + ); + }); + }); + module('permissions requests', function (hooks) { setupPermissionedRealm(hooks, { mary: ['read', 'write', 'realm-owner'], diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index f93bf128f2..8d9c6768ad 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -349,6 +349,7 @@ export class Realm { this.patchCard.bind(this), ) .get('/_info', SupportedMimeType.RealmInfo, this.realmInfo.bind(this)) + .get('/_mtimes', SupportedMimeType.Mtimes, this.realmMtimes.bind(this)) .get('/_search', SupportedMimeType.CardJson, this.search.bind(this)) .get( '/_search-prerendered', @@ -1654,6 +1655,57 @@ export class Realm { }); } + private async realmMtimes( + _request: Request, + requestContext: RequestContext, + ): Promise { + let mtimes: { [path: string]: number } = {}; + let traverse = async (currentPath = '') => { + const entries = this.#adapter.readdir(currentPath); + + for await (const entry of entries) { + let innerPath = join(currentPath, entry.name); + let innerURL = + entry.kind === 'directory' + ? this.paths.directoryURL(innerPath) + : this.paths.fileURL(innerPath); + if (await this.isIgnored(innerURL)) { + continue; + } + if (entry.kind === 'directory') { + await traverse(innerPath); + } else if (entry.kind === 'file') { + let mtime = await this.#adapter.lastModified(innerPath); + if (mtime != null) { + mtimes[innerURL.href] = mtime; + } + } + } + }; + + await traverse(); + + return createResponse({ + body: JSON.stringify( + { + data: { + id: this.url, + type: 'mtimes', + attributes: { + mtimes, + }, + }, + }, + null, + 2, + ), + init: { + headers: { 'content-type': SupportedMimeType.Mtimes }, + }, + requestContext, + }); + } + private async getRealmPermissions( _request: Request, requestContext: RequestContext, diff --git a/packages/runtime-common/router.ts b/packages/runtime-common/router.ts index dbc47276ab..68aa62aacd 100644 --- a/packages/runtime-common/router.ts +++ b/packages/runtime-common/router.ts @@ -21,6 +21,7 @@ export enum SupportedMimeType { CardSource = 'application/vnd.card+source', DirectoryListing = 'application/vnd.api+json', RealmInfo = 'application/vnd.api+json', + Mtimes = 'application/vnd.api+json', Permissions = 'application/vnd.api+json', Session = 'application/json', EventStream = 'text/event-stream', diff --git a/packages/runtime-common/worker.ts b/packages/runtime-common/worker.ts index c93445d571..767bacfbb1 100644 --- a/packages/runtime-common/worker.ts +++ b/packages/runtime-common/worker.ts @@ -15,7 +15,6 @@ import { type QueueRunner, type TextFileRef, type VirtualNetwork, - type Relationship, type ResponseWithNodeStream, } from '.'; import { MatrixClient } from './matrix-client'; @@ -36,11 +35,7 @@ export interface IndexResults { export interface Reader { readFile: (url: URL) => Promise; - directoryListing: ( - url: URL, - ) => Promise< - { kind: 'directory' | 'file'; url: string; lastModified: number | null }[] - >; + mtimes: () => Promise<{ [url: string]: number }>; } export type RunnerRegistration = ( @@ -342,29 +337,20 @@ export function getReader( }; }, - directoryListing: async (url: URL) => { - let response = await _fetch(url, { + mtimes: async () => { + let response = await _fetch(`${realmURL.href}_mtimes`, { headers: { - Accept: SupportedMimeType.DirectoryListing, + Accept: SupportedMimeType.Mtimes, }, }); let { - data: { relationships: _relationships }, - } = await response.json(); - let relationships = _relationships as Record; - return Object.values(relationships).map((entry) => - entry.meta!.kind === 'file' - ? { - url: entry.links.related!, - kind: 'file', - lastModified: (entry.meta?.lastModified ?? null) as number | null, - } - : { - url: entry.links.related!, - kind: 'directory', - lastModified: null, - }, - ); + data: { + attributes: { mtimes }, + }, + } = (await response.json()) as { + data: { attributes: { mtimes: { [url: string]: number } } }; + }; + return mtimes; }, }; } From 28f3e02adb317e97b2759895dc4690304130e1a6 Mon Sep 17 00:00:00 2001 From: Hassan Abdel-Rahman Date: Thu, 26 Dec 2024 13:03:40 -0500 Subject: [PATCH 7/9] cleanup logic --- packages/host/app/lib/current-run.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/host/app/lib/current-run.ts b/packages/host/app/lib/current-run.ts index e5348c10dd..e3d2d6f8c3 100644 --- a/packages/host/app/lib/current-run.ts +++ b/packages/host/app/lib/current-run.ts @@ -252,13 +252,10 @@ export class CurrentRun { if ( !indexEntry || indexEntry.type === 'error' || - indexEntry.lastModified == null + indexEntry.lastModified == null || + lastModified !== indexEntry.lastModified ) { await this.batch.invalidate(new URL(url)); - continue; - } - if (lastModified !== indexEntry.lastModified) { - await this.batch.invalidate(new URL(url)); } } } From ae61a051732dc0c463bad3c0ba60a5bca2c16489 Mon Sep 17 00:00:00 2001 From: Hassan Abdel-Rahman Date: Thu, 26 Dec 2024 13:38:57 -0500 Subject: [PATCH 8/9] update test --- .../tests/integration/realm-indexing-and-querying-test.gts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/host/tests/integration/realm-indexing-and-querying-test.gts b/packages/host/tests/integration/realm-indexing-and-querying-test.gts index 717db00fc0..7cba0ce45f 100644 --- a/packages/host/tests/integration/realm-indexing-and-querying-test.gts +++ b/packages/host/tests/integration/realm-indexing-and-querying-test.gts @@ -3401,6 +3401,12 @@ module(`Integration | realm indexing and querying`, function (hooks) { { id: mangoID }, { id: vanGoghID, + firstName: 'Van Gogh', + friends: [ + { + id: hassanID, + }, + ], }, ], }, From 71f2711d3db0530f331de116788038337810ddc8 Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 27 Dec 2024 16:06:40 +0800 Subject: [PATCH 9/9] seperate thumbnail and icon block for clearer readability (#1979) * seperte thumbnail and icon block for clearer readability * split entity-display to two seperate component --- packages/experiments-realm/address.gts | 13 +- .../components/activity-card.gts | 6 +- .../components/contact-row.gts | 9 +- .../components/entity-display.gts | 93 ------------- .../components/entity-icon-display.gts | 126 +++++++++++++++++ .../components/entity-thumbnail-display.gts | 130 ++++++++++++++++++ packages/experiments-realm/crm/account.gts | 41 +++--- packages/experiments-realm/crm/company.gts | 13 +- packages/experiments-realm/crm/contact.gts | 11 +- packages/experiments-realm/crm/deal.gts | 17 +-- packages/experiments-realm/email.gts | 13 +- packages/experiments-realm/phone-number.gts | 18 +-- packages/experiments-realm/website.gts | 13 +- 13 files changed, 323 insertions(+), 180 deletions(-) delete mode 100644 packages/experiments-realm/components/entity-display.gts create mode 100644 packages/experiments-realm/components/entity-icon-display.gts create mode 100644 packages/experiments-realm/components/entity-thumbnail-display.gts diff --git a/packages/experiments-realm/address.gts b/packages/experiments-realm/address.gts index 0cee00fa53..d640b9c18b 100644 --- a/packages/experiments-realm/address.gts +++ b/packages/experiments-realm/address.gts @@ -7,7 +7,7 @@ import { import StringField from 'https://cardstack.com/base/string'; import { CountryField } from './country'; import MapPinIcon from '@cardstack/boxel-icons/map-pin'; -import { EntityDisplay } from './components/entity-display'; +import EntityDisplayWithIcon from './components/entity-icon-display'; function getAddressRows( addressLine1: string | undefined, @@ -39,14 +39,11 @@ class Atom extends Component { ); } } diff --git a/packages/experiments-realm/components/activity-card.gts b/packages/experiments-realm/components/activity-card.gts index 76222830ea..b5277ff520 100644 --- a/packages/experiments-realm/components/activity-card.gts +++ b/packages/experiments-realm/components/activity-card.gts @@ -1,5 +1,5 @@ import GlimmerComponent from '@glimmer/component'; -import { EntityDisplay } from './entity-display'; +import EntityDisplayWithThumbnail from './entity-thumbnail-display'; interface ActivityCardArgs { Blocks: { @@ -17,7 +17,7 @@ export default class ActivityCard extends GlimmerComponent {
- + <:title> {{yield to='title'}} @@ -28,7 +28,7 @@ export default class ActivityCard extends GlimmerComponent { {{yield to='thumbnail'}} - + {{#if (has-block 'description')}}

diff --git a/packages/experiments-realm/components/contact-row.gts b/packages/experiments-realm/components/contact-row.gts index 92b8f3e4c2..db8545180b 100644 --- a/packages/experiments-realm/components/contact-row.gts +++ b/packages/experiments-realm/components/contact-row.gts @@ -1,5 +1,5 @@ import { Avatar, Pill } from '@cardstack/boxel-ui/components'; -import { EntityDisplay } from './entity-display'; +import EntityDisplayWithThumbnail from './entity-thumbnail-display'; import GlimmerComponent from '@glimmer/component'; interface ContactRowArgs { @@ -15,10 +15,7 @@ interface ContactRowArgs { export class ContactRow extends GlimmerComponent { -} diff --git a/packages/experiments-realm/components/entity-icon-display.gts b/packages/experiments-realm/components/entity-icon-display.gts new file mode 100644 index 0000000000..73cc4142d1 --- /dev/null +++ b/packages/experiments-realm/components/entity-icon-display.gts @@ -0,0 +1,126 @@ +import GlimmerComponent from '@glimmer/component'; +import { concat } from '@ember/helper'; + +interface EntityDisplayWithIconArgs { + Args: { + title?: string; //prefer using args.title if the title is just a string + center?: boolean; + underline?: boolean; + }; + Blocks: { + title?: []; //we can choose use this to pass instead of using args.title if the title block HTML is complex + icon?: []; + tag?: []; + content?: []; + }; + Element: HTMLElement; +} + +export default class EntityDisplayWithIcon extends GlimmerComponent { + get shouldAlignCenter() { + return this.args.center; + } + + get shouldUnderlineText() { + return this.args.underline; + } + + +} diff --git a/packages/experiments-realm/components/entity-thumbnail-display.gts b/packages/experiments-realm/components/entity-thumbnail-display.gts new file mode 100644 index 0000000000..26aac840e9 --- /dev/null +++ b/packages/experiments-realm/components/entity-thumbnail-display.gts @@ -0,0 +1,130 @@ +import GlimmerComponent from '@glimmer/component'; +import { concat } from '@ember/helper'; + +interface EntityDisplayWithThumbnailArgs { + Args: { + title?: string; //prefer using args.title if the title is just a string + center?: boolean; + underline?: boolean; + }; + Blocks: { + title?: []; //we can choose use this to pass instead of using args.title if the title block HTML is complex + thumbnail?: []; + tag?: []; + content?: []; + }; + Element: HTMLElement; +} + +export default class EntityDisplayWithThumbnail extends GlimmerComponent { + get shouldAlignCenter() { + return this.args.center; + } + + get shouldUnderlineText() { + return this.args.underline; + } + + +} diff --git a/packages/experiments-realm/crm/account.gts b/packages/experiments-realm/crm/account.gts index 446426fc90..c51f4489fe 100644 --- a/packages/experiments-realm/crm/account.gts +++ b/packages/experiments-realm/crm/account.gts @@ -26,7 +26,8 @@ import CalendarExclamation from '@cardstack/boxel-icons/calendar-exclamation'; import { LooseGooseyField } from '../loosey-goosey'; import { StatusPill } from '../components/status-pill'; import { Avatar, Pill, BoxelButton } from '@cardstack/boxel-ui/components'; -import { EntityDisplay } from '../components/entity-display'; +import EntityDisplayWithIcon from '../components/entity-icon-display'; +import EntityDisplayWithThumbnail from '../components/entity-thumbnail-display'; import ActivityCard from '../components/activity-card'; import PlusIcon from '@cardstack/boxel-icons/plus'; import PhoneIcon from '@cardstack/boxel-icons/phone'; @@ -204,41 +205,36 @@ class IsolatedTemplate extends Component { <:content>

- - <:thumbnail> + + <:icon> - - <:title> - Dmitri Petrov - + <:content> Technova - - + + <:thumbnail> - <:title> - Rep: Janus Dios - <:content> Sales Associate - - - <:thumbnail> + + + <:icon> - - <:title> - May 15, 2024 - + <:content> 3:15pm - +
@@ -328,6 +324,11 @@ class IsolatedTemplate extends Component { color: var(--boxel-color-gray); margin-left: auto; } + .avatar { + --profile-avatar-icon-size: 20px; + --profile-avatar-icon-border: 0px; + flex-shrink: 0; + } @container activities-summary-card (max-width: 447px) { .activity-button-mobile { diff --git a/packages/experiments-realm/crm/company.gts b/packages/experiments-realm/crm/company.gts index fe64a3a1c5..70af9f19ff 100644 --- a/packages/experiments-realm/crm/company.gts +++ b/packages/experiments-realm/crm/company.gts @@ -2,7 +2,7 @@ import StringField from 'https://cardstack.com/base/string'; import NumberField from 'https://cardstack.com/base/number'; import { WebsiteField } from '../website'; import { Address } from '../address'; -import { EntityDisplay } from '../components/entity-display'; +import EntityDisplayWithIcon from '../components/entity-icon-display'; import { Component, @@ -15,14 +15,11 @@ import BuildingIcon from '@cardstack/boxel-icons/building'; class ViewCompanyTemplate extends Component { } diff --git a/packages/experiments-realm/crm/contact.gts b/packages/experiments-realm/crm/contact.gts index e043c105f0..8d29b1c062 100644 --- a/packages/experiments-realm/crm/contact.gts +++ b/packages/experiments-realm/crm/contact.gts @@ -19,7 +19,7 @@ import Email from '@cardstack/boxel-icons/mail'; import Linkedin from '@cardstack/boxel-icons/linkedin'; import XIcon from '@cardstack/boxel-icons/brand-x'; import { LooseGooseyField } from '../loosey-goosey'; -import { EntityDisplay } from '../components/entity-display'; +import EntityDisplayWithThumbnail from '../components/entity-thumbnail-display'; export class SocialLinkField extends ContactLinkField { static displayName = 'social-link'; @@ -186,7 +186,7 @@ class FittedTemplate extends Component { grid-area: avatar-group-container; } .avatar-group-container - :where(.avatar-info .company-group .entity-name-tag) { + :where(.avatar-info .company-group .entity-title-tag-container) { overflow: hidden; text-overflow: ellipsis; display: -webkit-box; @@ -610,10 +610,7 @@ class AtomTemplate extends Component { }