Added better display of bread crums and side bar menus for apps and objects

This commit is contained in:
Francisco Gaona
2025-12-22 11:01:53 +01:00
parent db9848cce7
commit be6e34914e
8 changed files with 224 additions and 7 deletions

View File

@@ -0,0 +1,11 @@
exports.up = function (knex) {
return knex.schema.table('object_definitions', (table) => {
table.string('nameField', 255).comment('API name of the field to use as record display name');
});
};
exports.down = function (knex) {
return knex.schema.table('object_definitions', (table) => {
table.dropColumn('nameField');
});
};

View File

@@ -0,0 +1,22 @@
exports.up = function (knex) {
return knex.schema.table('object_definitions', (table) => {
table.uuid('app_id').nullable()
.comment('Optional: App that this object belongs to');
table
.foreign('app_id')
.references('id')
.inTable('apps')
.onDelete('SET NULL');
table.index(['app_id']);
});
};
exports.down = function (knex) {
return knex.schema.table('object_definitions', (table) => {
table.dropForeign('app_id');
table.dropIndex('app_id');
table.dropColumn('app_id');
});
};

View File

@@ -0,0 +1,72 @@
import { getCentralPrisma } from '../src/prisma/central-prisma.service';
import * as knex from 'knex';
import * as crypto from 'crypto';
function decrypt(text: string): string {
const parts = text.split(':');
const iv = Buffer.from(parts.shift()!, 'hex');
const encryptedText = Buffer.from(parts.join(':'), 'hex');
const key = Buffer.from(process.env.ENCRYPTION_KEY, 'hex');
const decipher = crypto.createDecipheriv(
'aes-256-cbc',
key,
iv,
);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
async function updateNameField() {
const centralPrisma = getCentralPrisma();
try {
// Find tenant1
const tenant = await centralPrisma.tenant.findFirst({
where: {
OR: [
{ id: 'tenant1' },
{ slug: 'tenant1' },
],
},
});
if (!tenant) {
console.error('❌ Tenant tenant1 not found');
process.exit(1);
}
console.log(`📋 Tenant: ${tenant.name} (${tenant.slug})`);
console.log(`📊 Database: ${tenant.dbName}`);
// Decrypt password
const password = decrypt(tenant.dbPassword);
// Create connection
const tenantKnex = knex.default({
client: 'mysql2',
connection: {
host: tenant.dbHost,
port: tenant.dbPort,
user: tenant.dbUsername,
password: password,
database: tenant.dbName,
},
});
// Update Account object
await tenantKnex('object_definitions')
.where({ apiName: 'Account' })
.update({ nameField: 'name' });
console.log('✅ Updated Account object nameField to "name"');
await tenantKnex.destroy();
await centralPrisma.$disconnect();
} catch (error) {
console.error('❌ Error:', error);
process.exit(1);
}
}
updateNameField();

View File

@@ -8,9 +8,23 @@ export class ObjectService {
// Setup endpoints - Object metadata management
async getObjectDefinitions(tenantId: string) {
const knex = await this.tenantDbService.getTenantKnex(tenantId);
return knex('object_definitions')
.select('*')
const objects = await knex('object_definitions')
.select('object_definitions.*')
.orderBy('label', 'asc');
// Fetch app information for objects that have app_id
for (const obj of objects) {
if (obj.app_id) {
const app = await knex('apps')
.where({ id: obj.app_id })
.select('id', 'slug', 'label', 'description')
.first();
obj.app = app;
}
}
return objects;
}
async getObjectDefinition(tenantId: string, apiName: string) {
@@ -29,9 +43,19 @@ export class ObjectService {
.where({ objectDefinitionId: obj.id })
.orderBy('label', 'asc');
// Get app information if object belongs to an app
let app = null;
if (obj.app_id) {
app = await knex('apps')
.where({ id: obj.app_id })
.select('id', 'slug', 'label', 'description')
.first();
}
return {
...obj,
fields,
app,
};
}