diff --git a/CHANGELOG.md b/CHANGELOG.md index 839440c1a..2a9cbee49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## v1.0.0-91 + + +### 🩹 Fixes + +- Template create record with referecegst ([b8fe6d7](https://github.com/undb-io/undb/commit/b8fe6d7)) + +### ❤️ Contributors + +- Nichenqin ([@nichenqin](http://github.com/nichenqin)) + ## v1.0.0-90 diff --git a/apps/frontend/src/lib/components/blocks/base/base-detail.svelte b/apps/frontend/src/lib/components/blocks/base/base-detail.svelte index 5a0359aa8..4fa9f7b87 100644 --- a/apps/frontend/src/lib/components/blocks/base/base-detail.svelte +++ b/apps/frontend/src/lib/components/blocks/base/base-detail.svelte @@ -1,5 +1,5 @@ @@ -10,6 +11,7 @@ + diff --git a/apps/frontend/src/lib/components/blocks/template/template-card.svelte b/apps/frontend/src/lib/components/blocks/template/template-card.svelte index c35b2dc76..12707d52a 100644 --- a/apps/frontend/src/lib/components/blocks/template/template-card.svelte +++ b/apps/frontend/src/lib/components/blocks/template/template-card.svelte @@ -8,6 +8,7 @@ import { invalidateAll, goto } from "$app/navigation" import { IMPORT_TEMPLATE_MODAL, closeModal } from "$lib/store/modal.store" import { FullscreenIcon } from "lucide-svelte" + import { LoaderCircleIcon } from "lucide-svelte" import * as Dialog from "$lib/components/ui/dialog" import TemplatePreview from "./template-preview.svelte" import { Checkbox } from "$lib/components/ui/checkbox/index.js" @@ -52,7 +53,7 @@

Card Content

--> - +
diff --git a/apps/frontend/src/lib/components/blocks/template/template-preview.svelte b/apps/frontend/src/lib/components/blocks/template/template-preview.svelte index 95938d800..794bbde08 100644 --- a/apps/frontend/src/lib/components/blocks/template/template-preview.svelte +++ b/apps/frontend/src/lib/components/blocks/template/template-preview.svelte @@ -8,10 +8,13 @@ import { cn } from "$lib/utils" import { HardDriveIcon, DatabaseIcon, ViewIcon, ChevronRightIcon } from "lucide-svelte" import * as Collapsible from "$lib/components/ui/collapsible" + import { setTemplate } from "$lib/store/template.store" export let template: ITemplateDTO - let t = TemplateFactory.create(template.template.template, [], "") + setTemplate(writable(template)) + + let t = TemplateFactory.create(template.template.template, [],"preview") let tables = t.flatMap((base) => base.tables.map(({ table }) => table)) let bases = t.map((base) => base.base) diff --git a/apps/frontend/src/lib/store/template.store.ts b/apps/frontend/src/lib/store/template.store.ts new file mode 100644 index 000000000..da050c638 --- /dev/null +++ b/apps/frontend/src/lib/store/template.store.ts @@ -0,0 +1,15 @@ +import type { ITemplateDTO } from "@undb/template" +import { getContext, setContext } from "svelte" +import { type Writable, derived } from "svelte/store" + +export function setTemplate(template: Writable) { + setContext("template", template) +} + +export function getTemplate() { + return getContext>("template") +} + +export function getIsTemplate() { + return derived([getTemplate()], ([$template]) => !!$template) +} diff --git a/package.json b/package.json index 36d4a2d05..9e1e02b0b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "undb", - "version": "1.0.0-90", + "version": "1.0.0-91", "private": true, "scripts": { "build": "NODE_ENV=production bun --bun turbo build", diff --git a/packages/persistence/src/template/template-data.ts b/packages/persistence/src/template/template-data.ts index a0c07fc5a..57cd8f726 100644 --- a/packages/persistence/src/template/template-data.ts +++ b/packages/persistence/src/template/template-data.ts @@ -46,4 +46,15 @@ export const templateData: ITemplateDTO[] = [ template: templates.officeInventoryManagement as IBaseTemplateDTO, }, }, + { + id: "6ba7b814-9dad-11d1-80b4-00c04fd430c8", + icon: "💼", + name: "CRM", + category: "sales", + description: "A template for managing customer relationships, deals, and activities.", + template: { + type: "base", + template: templates.crm as IBaseTemplateDTO, + }, + }, ] diff --git a/packages/table/src/index.ts b/packages/table/src/index.ts index 2f423d747..01653e06b 100644 --- a/packages/table/src/index.ts +++ b/packages/table/src/index.ts @@ -10,6 +10,7 @@ export * from "./table-id.vo" export * from "./table-name.vo" export * from "./table.builder" export * from "./table.do" +export * from "./table.factory" export * from "./table.outbox-service" export * from "./table.outbox-service.provider" export * from "./table.query-repository.provider" diff --git a/packages/table/src/methods/duplicate-table.method.ts b/packages/table/src/methods/duplicate-table.method.ts index b8e243682..5f714fce2 100644 --- a/packages/table/src/methods/duplicate-table.method.ts +++ b/packages/table/src/methods/duplicate-table.method.ts @@ -2,8 +2,8 @@ import { getNextName } from "@undb/utils" import type { IDuplicateTableDTO } from "../dto/duplicate-table.dto" import { DuplicatedTableSpecification } from "../specifications" import { TableIdVo } from "../table-id.vo" -import { TableFactory } from "../table.builder" import { TableDo } from "../table.do" +import { TableFactory } from "../table.factory" export function duplicateTableMethod( this: TableDo, diff --git a/packages/table/src/modules/records/record/record-values.vo.ts b/packages/table/src/modules/records/record/record-values.vo.ts index 35303070f..9ed542cfc 100644 --- a/packages/table/src/modules/records/record/record-values.vo.ts +++ b/packages/table/src/modules/records/record/record-values.vo.ts @@ -55,14 +55,13 @@ export class RecordValuesVO extends ValueObject { static fromJSON(table: TableDo, dto: IRecordValues) { const values: RecordValues = {} - for (const [id, value] of Object.entries(dto)) { - const fieldId = new FieldIdVo(id) - const field = table.schema.getFieldById(fieldId).into(null) + for (const [idOrName, value] of Object.entries(dto)) { + const field = table.schema.getFieldByIdOrName(idOrName).into(null) if (!field) continue const fieldValue = FieldValueFactory.fromJSON(field, value) if (fieldValue.isSome()) { - Reflect.set(values, fieldId.value, fieldValue.unwrap()) + Reflect.set(values, field.id.value, fieldValue.unwrap()) } } diff --git a/packages/table/src/modules/records/services/methods/create-tables-records.method.ts b/packages/table/src/modules/records/services/methods/create-tables-records.method.ts new file mode 100644 index 000000000..4000db26b --- /dev/null +++ b/packages/table/src/modules/records/services/methods/create-tables-records.method.ts @@ -0,0 +1,37 @@ +import { and, Option } from "@undb/domain" +import type { TableDo } from "../../../../table.do" +import { ReferenceEqual, ReferenceFieldValue } from "../../../schema" +import type { RecordComositeSpecification, RecordDO } from "../../record" +import type { RecordsService } from "../records.service" + +export async function createTablesRecordsMethod( + this: RecordsService, + input: { table: TableDo; records: RecordDO[] }[], +): Promise { + for (const { table, records } of input) { + await this.repo.bulkInsert(table, records) + } + + for (const { table, records } of input) { + const referenceFields = table.schema.getReferenceFields() + for (const record of records) { + let specs: RecordComositeSpecification[] = [] + for (const field of referenceFields) { + const value = record.getValue(field.id) + if (value.isNone()) { + continue + } + const referecneValue = value.unwrap() as ReferenceFieldValue + if (referecneValue.value?.length) { + const spec = new ReferenceEqual(value.unwrap() as ReferenceFieldValue, field.id) + specs.push(spec) + } + } + + if (specs.length) { + const spec = and(...specs) as Option + await this.repo.updateOneById(table, record, spec) + } + } + } +} diff --git a/packages/table/src/modules/records/services/records.service.ts b/packages/table/src/modules/records/services/records.service.ts index 1fc1c3b3e..0eee3cd43 100644 --- a/packages/table/src/modules/records/services/records.service.ts +++ b/packages/table/src/modules/records/services/records.service.ts @@ -1,6 +1,7 @@ import { singleton } from "@undb/di" import type { Option } from "@undb/domain" import type { IUniqueTableDTO } from "../../../dto" +import type { TableDo } from "../../../table.do" import type { ITableRepository } from "../../../table.repository" import { injectTableRepository } from "../../../table.repository.provider" import { @@ -22,6 +23,7 @@ import { bulkduplicateRecordsMethod } from "./methods/bulk-duplicate-records.met import { bulkUpdateRecordsMethod } from "./methods/bulk-update-records.method" import { createRecordMethod } from "./methods/create-record.method" import { createRecordsMethod } from "./methods/create-records.method" +import { createTablesRecordsMethod } from "./methods/create-tables-records.method" import { deleteRecordMethod } from "./methods/delete-record.method" import { duplicateRecordMethod } from "./methods/duplicate-record.method" import { submitFormMethod } from "./methods/submit-form.method" @@ -39,6 +41,7 @@ export interface IRecordsService { bulkDeleteRecords(table: IUniqueTableDTO, dto: IBulkDeleteRecordsDTO): Promise duplicateRecord(table: IUniqueTableDTO, dto: IDuplicateRecordDTO): Promise bulkDuplicateRecords(table: IUniqueTableDTO, dto: IBulkDuplicateRecordsDTO): Promise + createTablesRecords(input: { table: TableDo; records: RecordDO[] }[]): Promise } @singleton() @@ -60,4 +63,5 @@ export class RecordsService implements IRecordsService { bulkDeleteRecords = bulkdeleteRecordsMethod duplicateRecord = duplicateRecordMethod bulkDuplicateRecords = bulkduplicateRecordsMethod + createTablesRecords = createTablesRecordsMethod } diff --git a/packages/table/src/services/table.service.ts b/packages/table/src/services/table.service.ts index 662ed06e3..f533b88e6 100644 --- a/packages/table/src/services/table.service.ts +++ b/packages/table/src/services/table.service.ts @@ -26,8 +26,8 @@ import { type View, } from "../modules" import type { ICreateTableFormDTO } from "../modules/forms/dto/create-form.dto" -import { TableFactory } from "../table.builder" import type { TableDo } from "../table.do" +import { TableFactory } from "../table.factory" import type { ITableRepository } from "../table.repository" import { injectTableRepository } from "../table.repository.provider" import { createTableFieldMethod } from "./methods/create-table-field.method" diff --git a/packages/table/src/table.builder.ts b/packages/table/src/table.builder.ts index 7a0376a3e..fe92e7140 100644 --- a/packages/table/src/table.builder.ts +++ b/packages/table/src/table.builder.ts @@ -1,23 +1,9 @@ -import type { Base } from "@undb/base" -import { None, Some, applyRules } from "@undb/domain" +import { None, Some } from "@undb/domain" import type { ISpaceId } from "@undb/space" -import { getNextName } from "@undb/utils" -import { createTableDTO, type ICreateTableDTO, type ICreateTablesDTO, type ITableDTO } from "./dto" -import { TableCreatedEvent } from "./events" -import { - RecordDO, - ReferenceField, - TableRLSGroup, - type ICreateFieldDTO, - type ICreateFormDTO, - type ICreateReferenceFieldDTO, - type IFormsDTO, - type IRLSGroupDTO, -} from "./modules" +import { TableRLSGroup, type ICreateFormDTO, type IFormsDTO, type IRLSGroupDTO } from "./modules" import { FormsVO } from "./modules/forms/forms.vo" import type { ICreateSchemaDTO } from "./modules/schema/dto/create-schema.dto" import type { ISchemaDTO } from "./modules/schema/dto/schema.dto" -import { FieldNameShouldBeUnique } from "./modules/schema/rules" import { Schema } from "./modules/schema/schema.vo" import type { ICreateViewDTO, IViewsDTO } from "./modules/views/dto" import { Views } from "./modules/views/views.vo" @@ -118,147 +104,3 @@ export class TableBuilder implements ITableBuilder { return this.table } } - -export class TableFactory { - private static get builder() { - return new TableBuilder() - } - - static create(dto: ICreateTableDTO): TableDo { - dto = createTableDTO.parse(dto) - const table = this.builder - .setId(dto.id) - .setBaseId(dto.baseId) - .setSpaceId(dto.spaceId) - .setName(dto.name) - .createSchema(dto.schema) - .createViews(dto.views) - .createForms(dto.forms) - .build() - - applyRules(new FieldNameShouldBeUnique(table.schema)) - - // @ts-ignore - TODO: fix this - table.addDomainEvent(new TableCreatedEvent({ table: table.toJSON() })) - return table - } - - // create many table inside a base - static createMany( - baseNames: string[], - base: Base, - dtos: ICreateTablesDTO[], - ): { table: TableDo; records: RecordDO[] }[] { - const ids = new TablesIdsMap(baseNames, base, dtos) - const baseName = getNextName(baseNames, base.name.value) - - const tables = dtos.map((dto) => { - const schema = dto.schema - .filter((f) => f.type !== "rollup") - .map((field) => { - if (field.type === "reference") { - const id = ids.mustGet(baseName, field.option.foreignTable.tableName) - return { - ...field, - option: { - ...field.option, - foreignTableId: id, - }, - } as ICreateReferenceFieldDTO - } - return field as ICreateFieldDTO - }) as ICreateSchemaDTO - - const id = ids.mustGet(baseName, dto.name) - const table = this.create({ ...dto, id, schema }) - return { table, dto: { ...dto, id: table.id.value } } - }) - - for (const { table } of tables) { - const referenceFields = table.schema.getReferenceFields() - for (const referenceField of referenceFields) { - const foreignTable = tables.find(({ table }) => table.id.value === referenceField.foreignTableId)?.table - if (!foreignTable) { - throw new Error("Foreign table not found") - } - const symmetricField = ReferenceField.createSymmetricField(table, foreignTable, referenceField) - foreignTable.$createFieldSpec(symmetricField) - } - } - - for (const { table, dto } of tables) { - const rollupFieldDTOs = dto.schema.filter((field) => field.type === "rollup") - for (const dto of rollupFieldDTOs) { - let referenceFieldId: string | undefined - if (dto.option.referenceFieldId) { - referenceFieldId = dto.option.referenceFieldId - } else if (dto.option.foreignReferenceField) { - const table = tables.find(({ table }) => table.name.value === dto.option.foreignReferenceField?.tableName) - const field = table?.table.schema.fields.find((f) => f.id.value === dto.option.foreignReferenceField?.fieldId) - if (field?.type === "reference") { - referenceFieldId = field.symmetricFieldId - } - } - - if (referenceFieldId) { - table.$createField({ - ...dto, - option: { - ...dto.option, - referenceFieldId, - }, - }) - } - } - } - - return tables.map(({ table, dto }) => { - const records = dto.records?.map((record) => RecordDO.create(table, record)) ?? [] - return { table, records } - }) - } - - static fromJSON(dto: ITableDTO): TableDo { - return this.builder - .setId(dto.id) - .setBaseId(dto.baseId) - .setName(dto.name) - .setSchema(dto.schema) - .setSpaceId(dto.spaceId) - .setViews(dto.views) - .setForms(dto.forms) - .setRLS(dto.rls) - .build() - } -} - -class TablesIdsMap { - private map = new Map() - - constructor(baseNames: string[], base: Base, dto: ICreateTablesDTO[]) { - for (const table of dto) { - const name = getNextName(baseNames, base.name.value) - this.map.set(this.generateKey(name, table.name), TableIdVo.create().value) - } - } - - private generateKey(baseName: string, tableName: string): string { - return `${baseName}-${tableName}` - } - - set(baseName: string, tableName: string) { - this.map.set(this.generateKey(baseName, tableName), TableIdVo.create().value) - } - - get(baseName: string, tableName: string): string | undefined { - return this.map.get(this.generateKey(baseName, tableName)) - } - - mustGet(baseName: string, tableName: string): string { - const id = this.get(baseName, tableName) - if (!id) { - throw new Error("Cannot get id from table ids map") - } - return id - } -} diff --git a/packages/table/src/table.factory.ts b/packages/table/src/table.factory.ts new file mode 100644 index 000000000..a64008ea0 --- /dev/null +++ b/packages/table/src/table.factory.ts @@ -0,0 +1,170 @@ +import type { Base } from "@undb/base" +import { applyRules } from "@undb/domain" +import { getNextName } from "@undb/utils" +import { createTableDTO, type ICreateTableDTO, type ICreateTablesDTO, type ITableDTO } from "./dto" +import { TableCreatedEvent } from "./events" +import { + FieldIdVo, + RecordDO, + ReferenceField, + type ICreateFieldDTO, + type ICreateReferenceFieldDTO, + type ICreateSchemaDTO, +} from "./modules" +import { FieldNameShouldBeUnique } from "./modules/schema/rules" +import { TableIdVo } from "./table-id.vo" +import { TableBuilder } from "./table.builder" +import type { TableDo } from "./table.do" + +class TablesIdsMap { + private map = new Map() + + constructor(baseNames: string[], base: Base, dto: ICreateTablesDTO[]) { + for (const table of dto) { + const name = getNextName(baseNames, base.name.value) + this.map.set(this.generateKey(name, table.name), TableIdVo.create().value) + } + } + + private generateKey(baseName: string, tableName: string): string { + return `${baseName}-${tableName}` + } + + set(baseName: string, tableName: string) { + this.map.set(this.generateKey(baseName, tableName), TableIdVo.create().value) + } + + get(baseName: string, tableName: string): string | undefined { + return this.map.get(this.generateKey(baseName, tableName)) + } + + mustGet(baseName: string, tableName: string): string { + const id = this.get(baseName, tableName) + if (!id) { + throw new Error("Cannot get id from table ids map") + } + return id + } +} + +export class TableFactory { + private static get builder() { + return new TableBuilder() + } + + static create(dto: ICreateTableDTO): TableDo { + dto = createTableDTO.parse(dto) + const table = this.builder + .setId(dto.id) + .setBaseId(dto.baseId) + .setSpaceId(dto.spaceId) + .setName(dto.name) + .createSchema(dto.schema) + .createViews(dto.views) + .createForms(dto.forms) + .build() + + applyRules(new FieldNameShouldBeUnique(table.schema)) + + // @ts-ignore - TODO: fix this + table.addDomainEvent(new TableCreatedEvent({ table: table.toJSON() })) + return table + } + + // create many table inside a base + static createMany( + baseNames: string[], + base: Base, + dtos: ICreateTablesDTO[], + preview = false, + ): { table: TableDo; records: RecordDO[] }[] { + const ids = new TablesIdsMap(baseNames, base, dtos) + const baseName = getNextName(baseNames, base.name.value) + + const referenceIds = new Set() + const tables = dtos.map((dto) => { + const schema = dto.schema + .filter((f) => f.type !== "rollup") + .map((field) => { + if (field.type === "reference") { + const foreignTableId = ids.mustGet(baseName, field.option.foreignTable.tableName) + if (!field.id) { + field.id = FieldIdVo.create().value + } + if (field.option.createSymmetricField) { + referenceIds.add(field.id!) + } + return { + ...field, + option: { + ...field.option, + foreignTableId: foreignTableId, + }, + } as ICreateReferenceFieldDTO + } + return field as ICreateFieldDTO + }) as ICreateSchemaDTO + + const id = ids.mustGet(baseName, dto.name) + const table = this.create({ ...dto, id, schema }) + return { table, dto: { ...dto, id: table.id.value } } + }) + + for (const { table } of tables) { + const referenceFields = table.schema.getReferenceFields().filter((f) => referenceIds.has(f.id.value)) + + for (const referenceField of referenceFields) { + const foreignTable = tables.find(({ table }) => table.id.value === referenceField.foreignTableId)?.table + if (!foreignTable) { + throw new Error("Foreign table not found") + } + const symmetricField = ReferenceField.createSymmetricField(table, foreignTable, referenceField) + foreignTable.$createFieldSpec(symmetricField) + } + } + + for (const { table, dto } of tables) { + const rollupFieldDTOs = dto.schema.filter((field) => field.type === "rollup") + for (const dto of rollupFieldDTOs) { + let referenceFieldId: string | undefined + if (dto.option.referenceFieldId) { + referenceFieldId = dto.option.referenceFieldId + } else if (dto.option.foreignReferenceField) { + const table = tables.find(({ table }) => table.name.value === dto.option.foreignReferenceField?.tableName) + const field = table?.table.schema.fields.find((f) => f.id.value === dto.option.foreignReferenceField?.fieldId) + if (field?.type === "reference") { + referenceFieldId = field.symmetricFieldId + } + } + + if (referenceFieldId) { + table.$createField({ + ...dto, + option: { + ...dto.option, + referenceFieldId, + }, + }) + } + } + } + + return tables.map(({ table, dto }) => { + const records = dto.records?.map((record) => RecordDO.create(table, record)) ?? [] + return { table, records } + }) + } + + static fromJSON(dto: ITableDTO): TableDo { + return this.builder + .setId(dto.id) + .setBaseId(dto.baseId) + .setName(dto.name) + .setSchema(dto.schema) + .setSpaceId(dto.spaceId) + .setViews(dto.views) + .setForms(dto.forms) + .setRLS(dto.rls) + .build() + } +} diff --git a/packages/template/src/dto/template-schema.dto.ts b/packages/template/src/dto/template-schema.dto.ts index b2f1d28e6..0f05f4efc 100644 --- a/packages/template/src/dto/template-schema.dto.ts +++ b/packages/template/src/dto/template-schema.dto.ts @@ -9,6 +9,7 @@ import { createTablesDurationFieldDTO, createTablesEmailFieldDTO, createTablesJsonFieldDTO, + createTablesLongTextFieldDTO, createTablesNumberFieldDTO, createTablesPercentageFieldDTO, createTablesRatingFieldDTO, @@ -48,6 +49,7 @@ const createTemplateFieldDTO = z.discriminatedUnion("type", [ createTablesUserFieldDTO.omit(omitName), createTablesPercentageFieldDTO.omit(omitName), createTablesDurationFieldDTO.omit(omitName), + createTablesLongTextFieldDTO.omit(omitName), ]) const templateSchemaDTO = z.record(fieldName, createTemplateFieldDTO) diff --git a/packages/template/src/service/template.service.ts b/packages/template/src/service/template.service.ts index a7d373ef9..b97288251 100644 --- a/packages/template/src/service/template.service.ts +++ b/packages/template/src/service/template.service.ts @@ -2,10 +2,12 @@ import { Base, injectBaseRepository, WithBaseSpaceId, type IBaseRepository } fro import { singleton } from "@undb/di" import { injectRecordRepository, + injectRecordsService, injectTableRepository, RecordDO, TableDo, type IRecordRepository, + type IRecordsService, type ITableRepository, } from "@undb/table" import type { ICreateFromTemplateDTO } from "../dto" @@ -30,6 +32,8 @@ export class TemplateService implements ITemplateService { private readonly recordRepository: IRecordRepository, @injectTemplateQueryRepository() private readonly templateQueryRepository: ITemplateQueryRepository, + @injectRecordsService() + private readonly recordsService: IRecordsService, ) {} async createBase( @@ -45,11 +49,10 @@ export class TemplateService implements ITemplateService { for (const { base, tables } of result) { await this.baseRepository.insert(base) await this.tableRepository.insertMany(tables.map((table) => table.table)) - if (includeData) { - for (const { table, records } of tables) { - await this.recordRepository.bulkInsert(table, records) - } + if (!includeData) { + continue } + await this.recordsService.createTablesRecords(tables) } return result diff --git a/packages/template/src/templates/crm.base.json b/packages/template/src/templates/crm.base.json new file mode 100644 index 000000000..94fe081e9 --- /dev/null +++ b/packages/template/src/templates/crm.base.json @@ -0,0 +1,1163 @@ +{ + "CRM": { + "tables": { + "Contacts": { + "schema": { + "Name": { + "id": "name", + "type": "string", + "constraint": { + "required": true + }, + "display": true + }, + "Status": { + "id": "status", + "type": "select", + "constraint": { + "max": 1, + "required": true + }, + "defaultValue": "lead", + "option": { + "options": [ + { + "id": "lead", + "color": "gray", + "name": "Lead" + }, + { + "id": "prospect", + "name": "Prospect", + "color": "blue" + }, + { + "id": "customer", + "name": "Customer", + "color": "green" + } + ] + } + }, + "Email": { + "id": "email", + "type": "email", + "constraint": { + "required": true + } + }, + "Phone": { + "id": "phone", + "type": "string" + }, + "Company": { + "id": "company", + "type": "reference", + "option": { + "createSymmetricField": true, + "foreignTable": { + "tableName": "Companies" + } + } + }, + "Company Name": { + "id": "companyName", + "type": "rollup", + "option": { + "referenceFieldId": "company", + "rollupFieldId": "name", + "fn": "lookup" + } + }, + "Company Industry": { + "id": "companyIndustry", + "type": "rollup", + "option": { + "referenceFieldId": "company", + "rollupFieldId": "industry", + "fn": "lookup" + } + }, + "Deals": { + "id": "deals", + "type": "reference", + "option": { + "foreignTable": { + "tableName": "Deals" + }, + "createSymmetricField": true + } + }, + "Deals Count": { + "type": "rollup", + "option": { + "fn": "count", + "referenceFieldId": "deals", + "rollupFieldId": "id" + } + }, + "Total Deal Value": { + "type": "rollup", + "option": { + "fn": "sum", + "referenceFieldId": "deals", + "rollupFieldId": "value" + } + } + }, + "records": [ + { + "id": "contact-1", + "Name": "John Doe", + "Status": "lead", + "Email": "john.doe@example.com", + "Phone": "+1 123-456-7890", + "Company": ["company-1"] + }, + { + "id": "contact-2", + "Name": "Jane Smith", + "Status": "prospect", + "Email": "jane.smith@example.com", + "Phone": "+1 234-567-8901", + "Company": ["company-2"] + }, + { + "id": "contact-3", + "Name": "Bob Johnson", + "Status": "customer", + "Email": "bob.johnson@example.com", + "Phone": "+1 345-678-9012", + "Company": ["company-3"] + }, + { + "id": "contact-4", + "Name": "Alice Brown", + "Status": "lead", + "Email": "alice.brown@example.com", + "Phone": "+1 456-789-0123", + "Company": ["company-4"] + }, + { + "id": "contact-5", + "Name": "Charlie Wilson", + "Status": "prospect", + "Email": "charlie.wilson@example.com", + "Phone": "+1 567-890-1234", + "Company": ["company-5"] + }, + { + "id": "contact-6", + "Name": "David Lee", + "Status": "customer", + "Email": "david.lee@example.com", + "Phone": "+1 678-901-2345", + "Company": ["company-6"] + }, + { + "id": "contact-7", + "Name": "Emma Davis", + "Status": "lead", + "Email": "emma.davis@example.com", + "Phone": "+1 789-012-3456", + "Company": ["company-7"] + }, + { + "id": "contact-8", + "Name": "Frank Miller", + "Status": "prospect", + "Email": "frank.miller@example.com", + "Phone": "+1 890-123-4567", + "Company": ["company-8"] + }, + { + "id": "contact-9", + "Name": "Grace Taylor", + "Status": "customer", + "Email": "grace.taylor@example.com", + "Phone": "+1 901-234-5678", + "Company": ["company-9"] + }, + { + "id": "contact-10", + "Name": "Henry Wilson", + "Status": "lead", + "Email": "henry.wilson@example.com", + "Phone": "+1 012-345-6789", + "Company": ["company-10"] + }, + { + "id": "contact-11", + "Name": "Isabella Moore", + "Status": "prospect", + "Email": "isabella.moore@example.com", + "Phone": "+1 123-456-7890", + "Company": ["company-1"] + }, + { + "id": "contact-12", + "Name": "Jack Thompson", + "Status": "customer", + "Email": "jack.thompson@example.com", + "Phone": "+1 234-567-8901", + "Company": ["company-2"] + }, + { + "id": "contact-13", + "Name": "Katherine White", + "Status": "lead", + "Email": "katherine.white@example.com", + "Phone": "+1 345-678-9012", + "Company": ["company-3"] + }, + { + "id": "contact-14", + "Name": "Liam Anderson", + "Status": "prospect", + "Email": "liam.anderson@example.com", + "Phone": "+1 456-789-0123", + "Company": ["company-4"] + }, + { + "id": "contact-15", + "Name": "Mia Garcia", + "Status": "customer", + "Email": "mia.garcia@example.com", + "Phone": "+1 567-890-1234", + "Company": ["company-5"] + }, + { + "id": "contact-16", + "Name": "Noah Martinez", + "Status": "lead", + "Email": "noah.martinez@example.com", + "Phone": "+1 678-901-2345", + "Company": ["company-6"] + }, + { + "id": "contact-17", + "Name": "Olivia Robinson", + "Status": "prospect", + "Email": "olivia.robinson@example.com", + "Phone": "+1 789-012-3456", + "Company": ["company-7"] + }, + { + "id": "contact-18", + "Name": "Peter Clark", + "Status": "customer", + "Email": "peter.clark@example.com", + "Phone": "+1 890-123-4567", + "Company": ["company-8"] + }, + { + "id": "contact-19", + "Name": "Quinn Rodriguez", + "Status": "lead", + "Email": "quinn.rodriguez@example.com", + "Phone": "+1 901-234-5678", + "Company": ["company-9"] + }, + { + "id": "contact-20", + "Name": "Rachel Lewis", + "Status": "prospect", + "Email": "rachel.lewis@example.com", + "Phone": "+1 012-345-6789", + "Company": ["company-10"] + }, + { + "id": "contact-21", + "Name": "Samuel Lee", + "Status": "customer", + "Email": "samuel.lee@example.com", + "Phone": "+1 123-456-7890", + "Company": ["company-1"] + }, + { + "id": "contact-22", + "Name": "Tiffany Nguyen", + "Status": "lead", + "Email": "tiffany.nguyen@example.com", + "Phone": "+1 234-567-8901", + "Company": ["company-2"] + }, + { + "id": "contact-23", + "Name": "Ulysses King", + "Status": "prospect", + "Email": "ulysses.king@example.com", + "Phone": "+1 345-678-9012", + "Company": ["company-3"] + }, + { + "id": "contact-24", + "Name": "Victoria Scott", + "Status": "customer", + "Email": "victoria.scott@example.com", + "Phone": "+1 456-789-0123", + "Company": ["company-4"] + }, + { + "id": "contact-25", + "Name": "William Turner", + "Status": "lead", + "Email": "william.turner@example.com", + "Phone": "+1 567-890-1234", + "Company": ["company-5"] + }, + { + "id": "contact-26", + "Name": "Xander Hayes", + "Status": "prospect", + "Email": "xander.hayes@example.com", + "Phone": "+1 678-901-2345", + "Company": ["company-6"] + }, + { + "id": "contact-27", + "Name": "Yasmin Cooper", + "Status": "customer", + "Email": "yasmin.cooper@example.com", + "Phone": "+1 789-012-3456", + "Company": ["company-7"] + }, + { + "id": "contact-28", + "Name": "Zachary Foster", + "Status": "lead", + "Email": "zachary.foster@example.com", + "Phone": "+1 890-123-4567", + "Company": ["company-8"] + }, + { + "id": "contact-29", + "Name": "Abigail Murphy", + "Status": "prospect", + "Email": "abigail.murphy@example.com", + "Phone": "+1 901-234-5678", + "Company": ["company-9"] + }, + { + "id": "contact-30", + "Name": "Benjamin Rivera", + "Status": "customer", + "Email": "benjamin.rivera@example.com", + "Phone": "+1 012-345-6789", + "Company": ["company-10"] + } + ] + }, + "Deals": { + "schema": { + "Name": { + "id": "name", + "type": "string", + "constraint": { + "required": true + }, + "display": true + }, + "Stage": { + "id": "stage", + "type": "select", + "constraint": { + "max": 1, + "required": true + }, + "defaultValue": "qualification", + "option": { + "options": [ + { + "id": "qualification", + "color": "gray", + "name": "Qualification" + }, + { + "id": "proposal", + "name": "Proposal", + "color": "blue" + }, + { + "id": "negotiation", + "name": "Negotiation", + "color": "orange" + }, + { + "id": "closed_won", + "name": "Closed Won", + "color": "green" + }, + { + "id": "closed_lost", + "name": "Closed Lost", + "color": "red" + } + ] + } + }, + "Value": { + "id": "value", + "type": "currency", + "constraint": { + "required": true + }, + "option": { + "symbol": "$" + } + }, + "Close Date": { + "id": "closeDate", + "type": "date" + } + }, + "records": [ + { + "id": "deal-1", + "Name": "Software License Renewal", + "Stage": "proposal", + "Value": 50000, + "Close Date": "2023-12-31", + "Contacts": ["contact-1"] + }, + { + "id": "deal-2", + "Name": "Cloud Migration Project", + "Stage": "negotiation", + "Value": 100000, + "Close Date": "2024-03-15", + "Contacts": ["contact-2"] + }, + { + "id": "deal-3", + "Name": "IT Support Contract", + "Stage": "closed_won", + "Value": 75000, + "Close Date": "2023-11-30", + "Contacts": ["contact-3"] + }, + { + "id": "deal-4", + "Name": "Hardware Upgrade", + "Stage": "qualification", + "Value": 25000, + "Close Date": "2024-02-28", + "Contacts": ["contact-4"] + }, + { + "id": "deal-5", + "Name": "Custom Software Development", + "Stage": "proposal", + "Value": 200000, + "Close Date": "2024-06-30", + "Contacts": ["contact-5"] + }, + { + "id": "deal-6", + "Name": "Network Security Audit", + "Stage": "qualification", + "Value": 30000, + "Close Date": "2024-01-15", + "Contacts": ["contact-6"] + }, + { + "id": "deal-7", + "Name": "Data Analytics Platform", + "Stage": "proposal", + "Value": 150000, + "Close Date": "2024-04-30", + "Contacts": ["contact-7"] + }, + { + "id": "deal-8", + "Name": "Mobile App Development", + "Stage": "negotiation", + "Value": 80000, + "Close Date": "2024-05-31", + "Contacts": ["contact-8"] + }, + { + "id": "deal-9", + "Name": "Cybersecurity Training Program", + "Stage": "closed_won", + "Value": 40000, + "Close Date": "2023-12-15", + "Contacts": ["contact-9"] + }, + { + "id": "deal-10", + "Name": "ERP System Implementation", + "Stage": "proposal", + "Value": 300000, + "Close Date": "2024-08-31", + "Contacts": ["contact-10"] + }, + { + "id": "deal-11", + "Name": "Cloud Storage Expansion", + "Stage": "qualification", + "Value": 60000, + "Close Date": "2024-03-01", + "Contacts": ["contact-11"] + }, + { + "id": "deal-12", + "Name": "AI-powered Chatbot", + "Stage": "negotiation", + "Value": 90000, + "Close Date": "2024-06-15", + "Contacts": ["contact-12"] + }, + { + "id": "deal-13", + "Name": "IT Infrastructure Upgrade", + "Stage": "proposal", + "Value": 250000, + "Close Date": "2024-09-30", + "Contacts": ["contact-13"] + }, + { + "id": "deal-14", + "Name": "Disaster Recovery Plan", + "Stage": "closed_won", + "Value": 55000, + "Close Date": "2023-11-15", + "Contacts": ["contact-14"] + }, + { + "id": "deal-15", + "Name": "IoT Device Management Platform", + "Stage": "qualification", + "Value": 120000, + "Close Date": "2024-07-31", + "Contacts": ["contact-15"] + }, + { + "id": "deal-16", + "Name": "Virtual Reality Training Solution", + "Stage": "proposal", + "Value": 180000, + "Close Date": "2024-10-15", + "Contacts": ["contact-16"] + }, + { + "id": "deal-17", + "Name": "Data Center Relocation", + "Stage": "negotiation", + "Value": 400000, + "Close Date": "2024-11-30", + "Contacts": ["contact-17"] + }, + { + "id": "deal-18", + "Name": "Blockchain Integration Project", + "Stage": "qualification", + "Value": 150000, + "Close Date": "2024-08-15", + "Contacts": ["contact-18"] + }, + { + "id": "deal-19", + "Name": "Customer Relationship Management System", + "Stage": "proposal", + "Value": 100000, + "Close Date": "2024-05-15", + "Contacts": ["contact-19"] + }, + { + "id": "deal-20", + "Name": "Robotic Process Automation", + "Stage": "closed_won", + "Value": 200000, + "Close Date": "2023-12-01", + "Contacts": ["contact-20"] + }, + { + "id": "deal-21", + "Name": "5G Network Implementation", + "Stage": "qualification", + "Value": 500000, + "Close Date": "2024-12-31", + "Contacts": ["contact-21"] + }, + { + "id": "deal-22", + "Name": "Augmented Reality Maintenance System", + "Stage": "proposal", + "Value": 250000, + "Close Date": "2024-09-15", + "Contacts": ["contact-22"] + }, + { + "id": "deal-23", + "Name": "Quantum Computing Research Partnership", + "Stage": "negotiation", + "Value": 1000000, + "Close Date": "2025-06-30", + "Contacts": ["contact-23"] + }, + { + "id": "deal-24", + "Name": "Edge Computing Infrastructure", + "Stage": "qualification", + "Value": 300000, + "Close Date": "2024-10-31", + "Contacts": ["contact-24"] + }, + { + "id": "deal-25", + "Name": "Digital Twin Technology Implementation", + "Stage": "proposal", + "Value": 450000, + "Close Date": "2025-03-15", + "Contacts": ["contact-25"] + }, + { + "id": "deal-26", + "Name": "Predictive Maintenance Solution", + "Stage": "closed_won", + "Value": 180000, + "Close Date": "2023-11-30", + "Contacts": ["contact-26"] + }, + { + "id": "deal-27", + "Name": "Biometric Authentication System", + "Stage": "negotiation", + "Value": 75000, + "Close Date": "2024-04-30", + "Contacts": ["contact-27"] + }, + { + "id": "deal-28", + "Name": "Smart Building Management Platform", + "Stage": "proposal", + "Value": 350000, + "Close Date": "2024-11-15", + "Contacts": ["contact-28"] + }, + { + "id": "deal-29", + "Name": "Autonomous Vehicle Software Development", + "Stage": "qualification", + "Value": 800000, + "Close Date": "2025-09-30", + "Contacts": ["contact-29"] + }, + { + "id": "deal-30", + "Name": "Cybersecurity Incident Response Team", + "Stage": "closed_won", + "Value": 120000, + "Close Date": "2023-12-15", + "Contacts": ["contact-30"] + }, + { + "id": "deal-31", + "Name": "Machine Learning Model Optimization", + "Stage": "proposal", + "Value": 200000, + "Close Date": "2024-07-31", + "Contacts": ["contact-1"] + }, + { + "id": "deal-32", + "Name": "Hybrid Cloud Migration", + "Stage": "negotiation", + "Value": 550000, + "Close Date": "2024-10-31", + "Contacts": ["contact-2"] + }, + { + "id": "deal-33", + "Name": "Supply Chain Visibility Platform", + "Stage": "qualification", + "Value": 275000, + "Close Date": "2024-08-15", + "Contacts": ["contact-3"] + }, + { + "id": "deal-34", + "Name": "Natural Language Processing Engine", + "Stage": "proposal", + "Value": 320000, + "Close Date": "2025-01-31", + "Contacts": ["contact-4"] + }, + { + "id": "deal-35", + "Name": "Drone Fleet Management System", + "Stage": "closed_won", + "Value": 150000, + "Close Date": "2023-12-31", + "Contacts": ["contact-5"] + }, + { + "id": "deal-36", + "Name": "Quantum-resistant Cryptography Implementation", + "Stage": "qualification", + "Value": 400000, + "Close Date": "2025-03-31", + "Contacts": ["contact-6"] + }, + { + "id": "deal-37", + "Name": "Augmented Analytics Platform", + "Stage": "negotiation", + "Value": 280000, + "Close Date": "2024-09-30", + "Contacts": ["contact-7"] + }, + { + "id": "deal-38", + "Name": "Zero Trust Security Architecture", + "Stage": "proposal", + "Value": 350000, + "Close Date": "2024-11-30", + "Contacts": ["contact-8"] + }, + { + "id": "deal-39", + "Name": "Digital Employee Experience Platform", + "Stage": "closed_won", + "Value": 190000, + "Close Date": "2023-12-15", + "Contacts": ["contact-9"] + }, + { + "id": "deal-40", + "Name": "Serverless Computing Adoption", + "Stage": "qualification", + "Value": 100000, + "Close Date": "2024-06-30", + "Contacts": ["contact-10"] + }, + { + "id": "deal-41", + "Name": "Intelligent Document Processing Solution", + "Stage": "proposal", + "Value": 225000, + "Close Date": "2024-08-31", + "Contacts": ["contact-11"] + }, + { + "id": "deal-42", + "Name": "Multi-cloud Orchestration Platform", + "Stage": "negotiation", + "Value": 475000, + "Close Date": "2025-02-28", + "Contacts": ["contact-12"] + }, + { + "id": "deal-43", + "Name": "Industrial IoT Sensor Network", + "Stage": "closed_won", + "Value": 380000, + "Close Date": "2023-11-30", + "Contacts": ["contact-13"] + }, + { + "id": "deal-44", + "Name": "Continuous Integration/Continuous Deployment Pipeline", + "Stage": "qualification", + "Value": 150000, + "Close Date": "2024-05-31", + "Contacts": ["contact-14"] + }, + { + "id": "deal-45", + "Name": "Data Fabric Architecture Implementation", + "Stage": "proposal", + "Value": 520000, + "Close Date": "2025-04-30", + "Contacts": ["contact-15"] + }, + { + "id": "deal-46", + "Name": "Low-code Application Development Platform", + "Stage": "negotiation", + "Value": 200000, + "Close Date": "2024-07-31", + "Contacts": ["contact-16"] + }, + { + "id": "deal-47", + "Name": "Unified Communications as a Service", + "Stage": "closed_won", + "Value": 95000, + "Close Date": "2023-12-31", + "Contacts": ["contact-17"] + }, + { + "id": "deal-48", + "Name": "Hyperautomation Strategy Consulting", + "Stage": "qualification", + "Value": 300000, + "Close Date": "2024-10-31", + "Contacts": ["contact-18"] + }, + { + "id": "deal-49", + "Name": "Confidential Computing Implementation", + "Stage": "proposal", + "Value": 400000, + "Close Date": "2025-01-31", + "Contacts": ["contact-19"] + }, + { + "id": "deal-50", + "Name": "Digital Ethics and Privacy Framework", + "Stage": "negotiation", + "Value": 180000, + "Close Date": "2024-09-30", + "Contacts": ["contact-20"] + } + ] + }, + "Activities": { + "schema": { + "Type": { + "id": "type", + "type": "select", + "constraint": { + "max": 1, + "required": true + }, + "option": { + "options": [ + { + "id": "call", + "color": "blue", + "name": "Call" + }, + { + "id": "meeting", + "name": "Meeting", + "color": "green" + }, + { + "id": "email", + "name": "Email", + "color": "orange" + } + ] + } + }, + "Subject": { + "id": "subject", + "type": "string", + "constraint": { + "required": true + }, + "display": true + }, + "Date": { + "id": "date", + "type": "date", + "constraint": { + "required": true + } + }, + "Notes": { + "id": "notes", + "type": "longText" + }, + "Contact": { + "id": "contact", + "type": "reference", + "option": { + "foreignTable": { + "tableName": "Contacts" + } + } + }, + "Deal": { + "id": "deal", + "type": "reference", + "option": { + "foreignTable": { + "tableName": "Deals" + } + } + } + }, + "records": [ + { + "id": "activity-1", + "Type": "call", + "Subject": "Initial Contact", + "Date": "2023-11-15", + "Notes": "Discussed potential software needs", + "Contact": ["contact-1"], + "Deal": ["deal-1"] + }, + { + "id": "activity-2", + "Type": "meeting", + "Subject": "Project Scope Discussion", + "Date": "2023-11-20", + "Notes": "Reviewed cloud migration requirements", + "Contact": ["contact-2"], + "Deal": ["deal-2"] + }, + { + "id": "activity-3", + "Type": "email", + "Subject": "Contract Sent", + "Date": "2023-11-25", + "Notes": "Sent final IT support contract for signature", + "Contact": ["contact-3"], + "Deal": ["deal-3"] + }, + { + "id": "activity-4", + "Type": "call", + "Subject": "Follow-up on Proposal", + "Date": "2023-11-28", + "Notes": "Answered questions about hardware upgrade options", + "Contact": ["contact-4"], + "Deal": ["deal-4"] + }, + { + "id": "activity-5", + "Type": "meeting", + "Subject": "Requirements Gathering", + "Date": "2023-12-01", + "Notes": "Detailed discussion of custom software features", + "Contact": ["contact-5"], + "Deal": ["deal-5"] + }, + { + "id": "activity-6", + "Type": "email", + "Subject": "Proposal Follow-up", + "Date": "2023-12-05", + "Notes": "Sent additional information on pricing structure", + "Contact": ["contact-1"], + "Deal": ["deal-1"] + }, + { + "id": "activity-7", + "Type": "call", + "Subject": "Technical Consultation", + "Date": "2023-12-10", + "Notes": "Provided technical advice on system integration", + "Contact": ["contact-2"], + "Deal": ["deal-2"] + }, + { + "id": "activity-8", + "Type": "meeting", + "Subject": "Contract Negotiation", + "Date": "2023-12-15", + "Notes": "Discussed terms and conditions of the service agreement", + "Contact": ["contact-3"], + "Deal": ["deal-3"] + }, + { + "id": "activity-9", + "Type": "email", + "Subject": "Project Timeline", + "Date": "2023-12-20", + "Notes": "Sent proposed project timeline for review", + "Contact": ["contact-4"], + "Deal": ["deal-4"] + }, + { + "id": "activity-10", + "Type": "call", + "Subject": "Budget Discussion", + "Date": "2023-12-25", + "Notes": "Reviewed budget allocations for different project phases", + "Contact": ["contact-5"], + "Deal": ["deal-5"] + }, + { + "id": "activity-11", + "Type": "meeting", + "Subject": "Stakeholder Presentation", + "Date": "2023-12-30", + "Notes": "Presented project overview to key stakeholders", + "Contact": ["contact-1"], + "Deal": ["deal-1"] + }, + { + "id": "activity-12", + "Type": "email", + "Subject": "Resource Allocation", + "Date": "2024-01-05", + "Notes": "Discussed resource requirements for project kickoff", + "Contact": ["contact-2"], + "Deal": ["deal-2"] + }, + { + "id": "activity-13", + "Type": "call", + "Subject": "Security Concerns", + "Date": "2024-01-10", + "Notes": "Addressed client's questions about data security measures", + "Contact": ["contact-3"], + "Deal": ["deal-3"] + }, + { + "id": "activity-14", + "Type": "meeting", + "Subject": "User Training Plan", + "Date": "2024-01-15", + "Notes": "Outlined the user training strategy for new software", + "Contact": ["contact-4"], + "Deal": ["deal-4"] + }, + { + "id": "activity-15", + "Type": "email", + "Subject": "Progress Report", + "Date": "2024-01-20", + "Notes": "Sent monthly progress report on ongoing projects", + "Contact": ["contact-5"], + "Deal": ["deal-5"] + }, + { + "id": "activity-16", + "Type": "call", + "Subject": "Feedback Collection", + "Date": "2024-01-25", + "Notes": "Gathered feedback on recently implemented features", + "Contact": ["contact-1"], + "Deal": ["deal-1"] + }, + { + "id": "activity-17", + "Type": "meeting", + "Subject": "Milestone Review", + "Date": "2024-01-30", + "Notes": "Reviewed project milestones and adjusted timelines", + "Contact": ["contact-2"], + "Deal": ["deal-2"] + }, + { + "id": "activity-18", + "Type": "email", + "Subject": "Upsell Opportunity", + "Date": "2024-02-05", + "Notes": "Proposed additional services to enhance current solution", + "Contact": ["contact-3"], + "Deal": ["deal-3"] + }, + { + "id": "activity-19", + "Type": "call", + "Subject": "Issue Resolution", + "Date": "2024-02-10", + "Notes": "Addressed and resolved a critical software bug", + "Contact": ["contact-4"], + "Deal": ["deal-4"] + }, + { + "id": "activity-20", + "Type": "meeting", + "Subject": "Contract Renewal", + "Date": "2024-02-15", + "Notes": "Discussed terms for upcoming contract renewal", + "Contact": ["contact-5"], + "Deal": ["deal-5"] + } + ] + }, + "Companies": { + "schema": { + "Name": { + "id": "name", + "type": "string", + "constraint": { + "required": true + }, + "display": true + }, + "Industry": { + "id": "industry", + "type": "select", + "constraint": { + "max": 1 + }, + "option": { + "options": [ + { "id": "technology", "name": "Technology", "color": "blue" }, + { "id": "finance", "name": "Finance", "color": "green" }, + { "id": "healthcare", "name": "Healthcare", "color": "red" }, + { "id": "manufacturing", "name": "Manufacturing", "color": "orange" }, + { "id": "retail", "name": "Retail", "color": "purple" } + ] + } + }, + "Website": { + "id": "website", + "type": "url" + } + }, + "records": [ + { + "id": "company-1", + "Name": "ABC Corp", + "Industry": "technology", + "Website": "https://www.abccorp.com" + }, + { + "id": "company-2", + "Name": "XYZ Inc", + "Industry": "finance", + "Website": "https://www.xyzinc.com" + }, + { + "id": "company-3", + "Name": "123 Industries", + "Industry": "manufacturing", + "Website": "https://www.123industries.com" + }, + { + "id": "company-4", + "Name": "Tech Solutions", + "Industry": "technology", + "Website": "https://www.techsolutions.com" + }, + { + "id": "company-5", + "Name": "Global Enterprises", + "Industry": "finance", + "Website": "https://www.globalenterprises.com" + }, + { + "id": "company-6", + "Name": "HealthCare Plus", + "Industry": "healthcare", + "Website": "https://www.healthcareplus.com" + }, + { + "id": "company-7", + "Name": "Retail Giants", + "Industry": "retail", + "Website": "https://www.retailgiants.com" + }, + { + "id": "company-8", + "Name": "Innovative Systems", + "Industry": "technology", + "Website": "https://www.innovativesystems.com" + }, + { + "id": "company-9", + "Name": "MediTech Solutions", + "Industry": "healthcare", + "Website": "https://www.meditechsolutions.com" + }, + { + "id": "company-10", + "Name": "EcoManufacture", + "Industry": "manufacturing", + "Website": "https://www.ecomanufacture.com" + } + ] + } + } + } +} diff --git a/packages/template/src/templates/eventPlaning.base.json b/packages/template/src/templates/eventPlaning.base.json index fa81cd29f..ad148f934 100644 --- a/packages/template/src/templates/eventPlaning.base.json +++ b/packages/template/src/templates/eventPlaning.base.json @@ -54,7 +54,7 @@ "id": "speakers", "type": "reference", "option": { - "createSymmetricField": false, + "createSymmetricField": true, "foreignTable": { "tableName": "Speakers" } @@ -75,7 +75,7 @@ "Start": "2021-09-01T08:00:00.000Z", "End": "2021-09-01T09:00:00.000Z", "Location": "Ballroom A", - "Speakers": ["Jane Doe", "John Smith"], + "Speakers": ["speaker-1", "speaker-2"], "Notes": "Breakfast will be served in the ballroom" }, { @@ -84,7 +84,7 @@ "Start": "2021-09-01T09:30:00.000Z", "End": "2021-09-01T10:30:00.000Z", "Location": "Auditorium", - "Speakers": ["Jane Doe"], + "Speakers": ["speaker-1"], "Notes": "Jane will be speaking about the future of technology" } ] @@ -114,6 +114,7 @@ }, "records": [ { + "id": "speaker-1", "Name": "Jane Doe", "Company": "Acme Corp", "Email": "test1@163.com", @@ -121,6 +122,7 @@ "Confirmed": true }, { + "id": "speaker-2", "Name": "John Smith", "Company": "Widgets Co", "Email": "test2@163.com", @@ -128,6 +130,7 @@ "Confirmed": false }, { + "id": "speaker-3", "Name": "Alice Jackson", "Company": "Software LLC", "Email": "test3@163.com", diff --git a/packages/template/src/templates/index.ts b/packages/template/src/templates/index.ts index 780d3f2b8..60eb249f0 100644 --- a/packages/template/src/templates/index.ts +++ b/packages/template/src/templates/index.ts @@ -1,8 +1,15 @@ +import { default as crm } from "./crm.base.json" import { default as eventPlaningList } from "./eventPlaning.base.json" import { default as officeInventoryManagement } from "./officeInventoryManagement.base.json" import { default as projectManagement } from "./projectManagement.base.json" import { default as todoList } from "./todoList.base.json" -const templates = { todoList, projectManagement, officeInventoryManagement, eventPlaningList } as const +const templates = { + todoList, + projectManagement, + officeInventoryManagement, + eventPlaningList, + crm, +} as const export { templates }