Merge pull request #2110 from automatisch/aut-1293
test(app-config): write model tests
This commit is contained in:
@@ -10,11 +10,11 @@ export default async (request, response) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const appConfigParams = (request) => {
|
const appConfigParams = (request) => {
|
||||||
const { allowCustomConnection, shared, disabled } = request.body;
|
const { customConnectionAllowed, shared, disabled } = request.body;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
key: request.params.appKey,
|
key: request.params.appKey,
|
||||||
allowCustomConnection,
|
customConnectionAllowed,
|
||||||
shared,
|
shared,
|
||||||
disabled,
|
disabled,
|
||||||
};
|
};
|
||||||
|
@@ -23,7 +23,7 @@ describe('POST /api/v1/admin/apps/:appKey/config', () => {
|
|||||||
|
|
||||||
it('should return created app config', async () => {
|
it('should return created app config', async () => {
|
||||||
const appConfig = {
|
const appConfig = {
|
||||||
allowCustomConnection: true,
|
customConnectionAllowed: true,
|
||||||
shared: true,
|
shared: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
};
|
};
|
||||||
@@ -44,7 +44,7 @@ describe('POST /api/v1/admin/apps/:appKey/config', () => {
|
|||||||
it('should return HTTP 422 for already existing app config', async () => {
|
it('should return HTTP 422 for already existing app config', async () => {
|
||||||
const appConfig = {
|
const appConfig = {
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
allowCustomConnection: true,
|
customConnectionAllowed: true,
|
||||||
shared: true,
|
shared: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
};
|
};
|
||||||
|
@@ -8,16 +8,19 @@ export default async (request, response) => {
|
|||||||
})
|
})
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
await appConfig.$query().patchAndFetch(appConfigParams(request));
|
await appConfig.$query().patchAndFetch({
|
||||||
|
...appConfigParams(request),
|
||||||
|
key: request.params.appKey,
|
||||||
|
});
|
||||||
|
|
||||||
renderObject(response, appConfig);
|
renderObject(response, appConfig);
|
||||||
};
|
};
|
||||||
|
|
||||||
const appConfigParams = (request) => {
|
const appConfigParams = (request) => {
|
||||||
const { allowCustomConnection, shared, disabled } = request.body;
|
const { customConnectionAllowed, shared, disabled } = request.body;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
allowCustomConnection,
|
customConnectionAllowed,
|
||||||
shared,
|
shared,
|
||||||
disabled,
|
disabled,
|
||||||
};
|
};
|
||||||
|
@@ -24,7 +24,7 @@ describe('PATCH /api/v1/admin/apps/:appKey/config', () => {
|
|||||||
it('should return updated app config', async () => {
|
it('should return updated app config', async () => {
|
||||||
const appConfig = {
|
const appConfig = {
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
allowCustomConnection: true,
|
customConnectionAllowed: true,
|
||||||
shared: true,
|
shared: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
};
|
};
|
||||||
@@ -34,7 +34,7 @@ describe('PATCH /api/v1/admin/apps/:appKey/config', () => {
|
|||||||
const newAppConfigValues = {
|
const newAppConfigValues = {
|
||||||
shared: false,
|
shared: false,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
allowCustomConnection: false,
|
customConnectionAllowed: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
@@ -55,7 +55,7 @@ describe('PATCH /api/v1/admin/apps/:appKey/config', () => {
|
|||||||
const appConfig = {
|
const appConfig = {
|
||||||
shared: false,
|
shared: false,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
allowCustomConnection: false,
|
customConnectionAllowed: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
await request(app)
|
await request(app)
|
||||||
@@ -68,7 +68,7 @@ describe('PATCH /api/v1/admin/apps/:appKey/config', () => {
|
|||||||
it('should return HTTP 422 for invalid app config data', async () => {
|
it('should return HTTP 422 for invalid app config data', async () => {
|
||||||
const appConfig = {
|
const appConfig = {
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
allowCustomConnection: true,
|
customConnectionAllowed: true,
|
||||||
shared: true,
|
shared: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
};
|
};
|
||||||
|
@@ -155,7 +155,7 @@ describe('POST /api/v1/apps/:appKey/connections', () => {
|
|||||||
await createAppConfig({
|
await createAppConfig({
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
allowCustomConnection: true,
|
customConnectionAllowed: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ describe('POST /api/v1/apps/:appKey/connections', () => {
|
|||||||
await createAppConfig({
|
await createAppConfig({
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
allowCustomConnection: false,
|
customConnectionAllowed: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -17,7 +17,7 @@ describe('GET /api/v1/apps/:appKey/config', () => {
|
|||||||
|
|
||||||
appConfig = await createAppConfig({
|
appConfig = await createAppConfig({
|
||||||
key: 'deepl',
|
key: 'deepl',
|
||||||
allowCustomConnection: true,
|
customConnectionAllowed: true,
|
||||||
shared: true,
|
shared: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
});
|
});
|
||||||
|
@@ -0,0 +1,37 @@
|
|||||||
|
export async function up(knex) {
|
||||||
|
await knex.schema.alterTable('app_configs', (table) => {
|
||||||
|
table.boolean('connection_allowed').defaultTo(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
const appConfigs = await knex('app_configs').select('*');
|
||||||
|
|
||||||
|
for (const appConfig of appConfigs) {
|
||||||
|
const appAuthClients = await knex('app_auth_clients').where(
|
||||||
|
'app_key',
|
||||||
|
appConfig.key
|
||||||
|
);
|
||||||
|
|
||||||
|
const hasSomeActiveAppAuthClients = !!appAuthClients?.some(
|
||||||
|
(appAuthClient) => appAuthClient.active
|
||||||
|
);
|
||||||
|
const shared = appConfig.shared;
|
||||||
|
const active = appConfig.disabled === false;
|
||||||
|
|
||||||
|
const connectionAllowedConditions = [
|
||||||
|
hasSomeActiveAppAuthClients,
|
||||||
|
shared,
|
||||||
|
active,
|
||||||
|
];
|
||||||
|
const connectionAllowed = connectionAllowedConditions.every(Boolean);
|
||||||
|
|
||||||
|
await knex('app_configs')
|
||||||
|
.where('id', appConfig.id)
|
||||||
|
.update({ connection_allowed: connectionAllowed });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex) {
|
||||||
|
await knex.schema.alterTable('app_configs', (table) => {
|
||||||
|
table.dropColumn('connection_allowed');
|
||||||
|
});
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
export async function up(knex) {
|
||||||
|
return knex.schema.alterTable('app_configs', (table) => {
|
||||||
|
table.renameColumn('allow_custom_connection', 'custom_connection_allowed');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex) {
|
||||||
|
return knex.schema.alterTable('app_configs', (table) => {
|
||||||
|
table.renameColumn('custom_connection_allowed', 'allow_custom_connection');
|
||||||
|
});
|
||||||
|
}
|
@@ -0,0 +1,13 @@
|
|||||||
|
export async function up(knex) {
|
||||||
|
return knex.schema.alterTable('app_configs', function (table) {
|
||||||
|
table.dropPrimary();
|
||||||
|
table.primary('key');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex) {
|
||||||
|
return knex.schema.alterTable('app_configs', function (table) {
|
||||||
|
table.dropPrimary();
|
||||||
|
table.primary('id');
|
||||||
|
});
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
export async function up(knex) {
|
||||||
|
return knex.schema.alterTable('app_configs', function (table) {
|
||||||
|
table.dropColumn('id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex) {
|
||||||
|
return knex.schema.alterTable('app_configs', function (table) {
|
||||||
|
table.uuid('id').defaultTo(knex.raw('gen_random_uuid()'));
|
||||||
|
});
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`AppConfig model > jsonSchema should have correct validations 1`] = `
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"connectionAllowed": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"customConnectionAllowed": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"shared": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"key",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
}
|
||||||
|
`;
|
@@ -2,6 +2,7 @@ import AES from 'crypto-js/aes.js';
|
|||||||
import enc from 'crypto-js/enc-utf8.js';
|
import enc from 'crypto-js/enc-utf8.js';
|
||||||
import appConfig from '../config/app.js';
|
import appConfig from '../config/app.js';
|
||||||
import Base from './base.js';
|
import Base from './base.js';
|
||||||
|
import AppConfig from './app-config.js';
|
||||||
|
|
||||||
class AppAuthClient extends Base {
|
class AppAuthClient extends Base {
|
||||||
static tableName = 'app_auth_clients';
|
static tableName = 'app_auth_clients';
|
||||||
@@ -21,6 +22,17 @@ class AppAuthClient extends Base {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static relationMappings = () => ({
|
||||||
|
appConfig: {
|
||||||
|
relation: Base.BelongsToOneRelation,
|
||||||
|
modelClass: AppConfig,
|
||||||
|
join: {
|
||||||
|
from: 'app_auth_clients.app_key',
|
||||||
|
to: 'app_configs.key',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
encryptData() {
|
encryptData() {
|
||||||
if (!this.eligibleForEncryption()) return;
|
if (!this.eligibleForEncryption()) return;
|
||||||
|
|
||||||
@@ -48,6 +60,17 @@ class AppAuthClient extends Base {
|
|||||||
return this.authDefaults ? true : false;
|
return this.authDefaults ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async triggerAppConfigUpdate() {
|
||||||
|
const appConfig = await this.$relatedQuery('appConfig');
|
||||||
|
|
||||||
|
// This is a workaround to update connection allowed column for AppConfig
|
||||||
|
await appConfig?.$query().patch({
|
||||||
|
key: appConfig.key,
|
||||||
|
shared: appConfig.shared,
|
||||||
|
disabled: appConfig.disabled,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Make another abstraction like beforeSave instead of using
|
// TODO: Make another abstraction like beforeSave instead of using
|
||||||
// beforeInsert and beforeUpdate separately for the same operation.
|
// beforeInsert and beforeUpdate separately for the same operation.
|
||||||
async $beforeInsert(queryContext) {
|
async $beforeInsert(queryContext) {
|
||||||
@@ -55,11 +78,23 @@ class AppAuthClient extends Base {
|
|||||||
this.encryptData();
|
this.encryptData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async $afterInsert(queryContext) {
|
||||||
|
await super.$afterInsert(queryContext);
|
||||||
|
|
||||||
|
await this.triggerAppConfigUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
async $beforeUpdate(opt, queryContext) {
|
async $beforeUpdate(opt, queryContext) {
|
||||||
await super.$beforeUpdate(opt, queryContext);
|
await super.$beforeUpdate(opt, queryContext);
|
||||||
this.encryptData();
|
this.encryptData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async $afterUpdate(opt, queryContext) {
|
||||||
|
await super.$afterUpdate(opt, queryContext);
|
||||||
|
|
||||||
|
await this.triggerAppConfigUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
async $afterFind() {
|
async $afterFind() {
|
||||||
this.decryptData();
|
this.decryptData();
|
||||||
}
|
}
|
||||||
|
@@ -2,9 +2,12 @@ import { describe, it, expect, vi } from 'vitest';
|
|||||||
import AES from 'crypto-js/aes.js';
|
import AES from 'crypto-js/aes.js';
|
||||||
import enc from 'crypto-js/enc-utf8.js';
|
import enc from 'crypto-js/enc-utf8.js';
|
||||||
|
|
||||||
|
import AppConfig from './app-config.js';
|
||||||
import AppAuthClient from './app-auth-client.js';
|
import AppAuthClient from './app-auth-client.js';
|
||||||
|
import Base from './base.js';
|
||||||
import appConfig from '../config/app.js';
|
import appConfig from '../config/app.js';
|
||||||
import { createAppAuthClient } from '../../test/factories/app-auth-client.js';
|
import { createAppAuthClient } from '../../test/factories/app-auth-client.js';
|
||||||
|
import { createAppConfig } from '../../test/factories/app-config.js';
|
||||||
|
|
||||||
describe('AppAuthClient model', () => {
|
describe('AppAuthClient model', () => {
|
||||||
it('tableName should return correct name', () => {
|
it('tableName should return correct name', () => {
|
||||||
@@ -15,6 +18,23 @@ describe('AppAuthClient model', () => {
|
|||||||
expect(AppAuthClient.jsonSchema).toMatchSnapshot();
|
expect(AppAuthClient.jsonSchema).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('relationMappings should return correct associations', () => {
|
||||||
|
const relationMappings = AppAuthClient.relationMappings();
|
||||||
|
|
||||||
|
const expectedRelations = {
|
||||||
|
appConfig: {
|
||||||
|
relation: Base.BelongsToOneRelation,
|
||||||
|
modelClass: AppConfig,
|
||||||
|
join: {
|
||||||
|
from: 'app_auth_clients.app_key',
|
||||||
|
to: 'app_configs.key',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(relationMappings).toStrictEqual(expectedRelations);
|
||||||
|
});
|
||||||
|
|
||||||
describe('encryptData', () => {
|
describe('encryptData', () => {
|
||||||
it('should return undefined if eligibleForEncryption is not true', async () => {
|
it('should return undefined if eligibleForEncryption is not true', async () => {
|
||||||
vi.spyOn(
|
vi.spyOn(
|
||||||
@@ -140,6 +160,63 @@ describe('AppAuthClient model', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('triggerAppConfigUpdate', () => {
|
||||||
|
it('should trigger an update in related app config', async () => {
|
||||||
|
await createAppConfig({ key: 'gitlab' });
|
||||||
|
|
||||||
|
const appAuthClient = await createAppAuthClient({
|
||||||
|
appKey: 'gitlab',
|
||||||
|
});
|
||||||
|
|
||||||
|
const appConfigBeforeUpdateSpy = vi.spyOn(
|
||||||
|
AppConfig.prototype,
|
||||||
|
'$beforeUpdate'
|
||||||
|
);
|
||||||
|
|
||||||
|
await appAuthClient.triggerAppConfigUpdate();
|
||||||
|
|
||||||
|
expect(appConfigBeforeUpdateSpy).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update related AppConfig after creating an instance', async () => {
|
||||||
|
const appConfig = await createAppConfig({
|
||||||
|
key: 'gitlab',
|
||||||
|
disabled: false,
|
||||||
|
shared: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await createAppAuthClient({
|
||||||
|
appKey: 'gitlab',
|
||||||
|
active: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const refetchedAppConfig = await appConfig.$query();
|
||||||
|
|
||||||
|
expect(refetchedAppConfig.connectionAllowed).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update related AppConfig after updating an instance', async () => {
|
||||||
|
const appConfig = await createAppConfig({
|
||||||
|
key: 'gitlab',
|
||||||
|
disabled: false,
|
||||||
|
shared: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const appAuthClient = await createAppAuthClient({
|
||||||
|
appKey: 'gitlab',
|
||||||
|
active: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
let refetchedAppConfig = await appConfig.$query();
|
||||||
|
expect(refetchedAppConfig.connectionAllowed).toBe(false);
|
||||||
|
|
||||||
|
await appAuthClient.$query().patchAndFetch({ active: true });
|
||||||
|
|
||||||
|
refetchedAppConfig = await appConfig.$query();
|
||||||
|
expect(refetchedAppConfig.connectionAllowed).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('$beforeInsert should call AppAuthClient.encryptData', async () => {
|
it('$beforeInsert should call AppAuthClient.encryptData', async () => {
|
||||||
const appAuthClientBeforeInsertSpy = vi.spyOn(
|
const appAuthClientBeforeInsertSpy = vi.spyOn(
|
||||||
AppAuthClient.prototype,
|
AppAuthClient.prototype,
|
||||||
@@ -151,6 +228,17 @@ describe('AppAuthClient model', () => {
|
|||||||
expect(appAuthClientBeforeInsertSpy).toHaveBeenCalledOnce();
|
expect(appAuthClientBeforeInsertSpy).toHaveBeenCalledOnce();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('$afterInsert should call AppAuthClient.triggerAppConfigUpdate', async () => {
|
||||||
|
const appAuthClientAfterInsertSpy = vi.spyOn(
|
||||||
|
AppAuthClient.prototype,
|
||||||
|
'triggerAppConfigUpdate'
|
||||||
|
);
|
||||||
|
|
||||||
|
await createAppAuthClient();
|
||||||
|
|
||||||
|
expect(appAuthClientAfterInsertSpy).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
|
|
||||||
it('$beforeUpdate should call AppAuthClient.encryptData', async () => {
|
it('$beforeUpdate should call AppAuthClient.encryptData', async () => {
|
||||||
const appAuthClient = await createAppAuthClient();
|
const appAuthClient = await createAppAuthClient();
|
||||||
|
|
||||||
@@ -164,6 +252,19 @@ describe('AppAuthClient model', () => {
|
|||||||
expect(appAuthClientBeforeUpdateSpy).toHaveBeenCalledOnce();
|
expect(appAuthClientBeforeUpdateSpy).toHaveBeenCalledOnce();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('$afterUpdate should call AppAuthClient.triggerAppConfigUpdate', async () => {
|
||||||
|
const appAuthClient = await createAppAuthClient();
|
||||||
|
|
||||||
|
const appAuthClientAfterUpdateSpy = vi.spyOn(
|
||||||
|
AppAuthClient.prototype,
|
||||||
|
'triggerAppConfigUpdate'
|
||||||
|
);
|
||||||
|
|
||||||
|
await appAuthClient.$query().patchAndFetch({ name: 'sample' });
|
||||||
|
|
||||||
|
expect(appAuthClientAfterUpdateSpy).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
|
|
||||||
it('$afterFind should call AppAuthClient.decryptData', async () => {
|
it('$afterFind should call AppAuthClient.decryptData', async () => {
|
||||||
const appAuthClient = await createAppAuthClient();
|
const appAuthClient = await createAppAuthClient();
|
||||||
|
|
||||||
|
@@ -5,6 +5,10 @@ import Base from './base.js';
|
|||||||
class AppConfig extends Base {
|
class AppConfig extends Base {
|
||||||
static tableName = 'app_configs';
|
static tableName = 'app_configs';
|
||||||
|
|
||||||
|
static get idColumn() {
|
||||||
|
return 'key';
|
||||||
|
}
|
||||||
|
|
||||||
static jsonSchema = {
|
static jsonSchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
required: ['key'],
|
required: ['key'],
|
||||||
@@ -12,7 +16,8 @@ class AppConfig extends Base {
|
|||||||
properties: {
|
properties: {
|
||||||
id: { type: 'string', format: 'uuid' },
|
id: { type: 'string', format: 'uuid' },
|
||||||
key: { type: 'string' },
|
key: { type: 'string' },
|
||||||
allowCustomConnection: { type: 'boolean', default: false },
|
connectionAllowed: { type: 'boolean', default: false },
|
||||||
|
customConnectionAllowed: { type: 'boolean', default: false },
|
||||||
shared: { type: 'boolean', default: false },
|
shared: { type: 'boolean', default: false },
|
||||||
disabled: { type: 'boolean', default: false },
|
disabled: { type: 'boolean', default: false },
|
||||||
createdAt: { type: 'string' },
|
createdAt: { type: 'string' },
|
||||||
@@ -31,31 +36,44 @@ class AppConfig extends Base {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
static get virtualAttributes() {
|
|
||||||
return ['canConnect', 'canCustomConnect'];
|
|
||||||
}
|
|
||||||
|
|
||||||
get canCustomConnect() {
|
|
||||||
return !this.disabled && this.allowCustomConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
get canConnect() {
|
|
||||||
const hasSomeActiveAppAuthClients = !!this.appAuthClients?.some(
|
|
||||||
(appAuthClient) => appAuthClient.active
|
|
||||||
);
|
|
||||||
const shared = this.shared;
|
|
||||||
const active = this.disabled === false;
|
|
||||||
|
|
||||||
const conditions = [hasSomeActiveAppAuthClients, shared, active];
|
|
||||||
|
|
||||||
return conditions.every(Boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getApp() {
|
async getApp() {
|
||||||
if (!this.key) return null;
|
if (!this.key) return null;
|
||||||
|
|
||||||
return await App.findOneByKey(this.key);
|
return await App.findOneByKey(this.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async computeAndAssignConnectionAllowedProperty() {
|
||||||
|
this.connectionAllowed = await this.computeConnectionAllowedProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
async computeConnectionAllowedProperty() {
|
||||||
|
const appAuthClients = await this.$relatedQuery('appAuthClients');
|
||||||
|
|
||||||
|
const hasSomeActiveAppAuthClients =
|
||||||
|
appAuthClients?.some((appAuthClient) => appAuthClient.active) || false;
|
||||||
|
|
||||||
|
const conditions = [
|
||||||
|
hasSomeActiveAppAuthClients,
|
||||||
|
this.shared,
|
||||||
|
!this.disabled,
|
||||||
|
];
|
||||||
|
|
||||||
|
const connectionAllowed = conditions.every(Boolean);
|
||||||
|
|
||||||
|
return connectionAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
async $beforeInsert(queryContext) {
|
||||||
|
await super.$beforeInsert(queryContext);
|
||||||
|
|
||||||
|
await this.computeAndAssignConnectionAllowedProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
async $beforeUpdate(opt, queryContext) {
|
||||||
|
await super.$beforeUpdate(opt, queryContext);
|
||||||
|
|
||||||
|
await this.computeAndAssignConnectionAllowedProperty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AppConfig;
|
export default AppConfig;
|
||||||
|
180
packages/backend/src/models/app-config.test.js
Normal file
180
packages/backend/src/models/app-config.test.js
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
import { vi, describe, it, expect } from 'vitest';
|
||||||
|
|
||||||
|
import Base from './base.js';
|
||||||
|
import AppConfig from './app-config.js';
|
||||||
|
import App from './app.js';
|
||||||
|
import AppAuthClient from './app-auth-client.js';
|
||||||
|
import { createAppConfig } from '../../test/factories/app-config.js';
|
||||||
|
import { createAppAuthClient } from '../../test/factories/app-auth-client.js';
|
||||||
|
|
||||||
|
describe('AppConfig model', () => {
|
||||||
|
it('tableName should return correct name', () => {
|
||||||
|
expect(AppConfig.tableName).toBe('app_configs');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('idColumn should return key field', () => {
|
||||||
|
expect(AppConfig.idColumn).toBe('key');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('jsonSchema should have correct validations', () => {
|
||||||
|
expect(AppConfig.jsonSchema).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('relationMappings should return correct associations', () => {
|
||||||
|
const relationMappings = AppConfig.relationMappings();
|
||||||
|
|
||||||
|
const expectedRelations = {
|
||||||
|
appAuthClients: {
|
||||||
|
relation: Base.HasManyRelation,
|
||||||
|
modelClass: AppAuthClient,
|
||||||
|
join: {
|
||||||
|
from: 'app_configs.key',
|
||||||
|
to: 'app_auth_clients.app_key',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(relationMappings).toStrictEqual(expectedRelations);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getApp', () => {
|
||||||
|
it('getApp should return null if there is no key', async () => {
|
||||||
|
const appConfig = new AppConfig();
|
||||||
|
const app = await appConfig.getApp();
|
||||||
|
|
||||||
|
expect(app).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getApp should return app with provided key', async () => {
|
||||||
|
const appConfig = new AppConfig();
|
||||||
|
appConfig.key = 'deepl';
|
||||||
|
|
||||||
|
const app = await appConfig.getApp();
|
||||||
|
const expectedApp = await App.findOneByKey(appConfig.key);
|
||||||
|
|
||||||
|
expect(app).toStrictEqual(expectedApp);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('computeAndAssignConnectionAllowedProperty', () => {
|
||||||
|
it('should call computeConnectionAllowedProperty and assign the result', async () => {
|
||||||
|
const appConfig = await createAppConfig();
|
||||||
|
|
||||||
|
const computeConnectionAllowedPropertySpy = vi
|
||||||
|
.spyOn(appConfig, 'computeConnectionAllowedProperty')
|
||||||
|
.mockResolvedValue(true);
|
||||||
|
|
||||||
|
await appConfig.computeAndAssignConnectionAllowedProperty();
|
||||||
|
|
||||||
|
expect(computeConnectionAllowedPropertySpy).toHaveBeenCalled();
|
||||||
|
expect(appConfig.connectionAllowed).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('computeConnectionAllowedProperty', () => {
|
||||||
|
it('should return true when app is enabled, shared and allows custom connection with an active app auth client', async () => {
|
||||||
|
await createAppAuthClient({
|
||||||
|
appKey: 'deepl',
|
||||||
|
active: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await createAppAuthClient({
|
||||||
|
appKey: 'deepl',
|
||||||
|
active: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const appConfig = await createAppConfig({
|
||||||
|
disabled: false,
|
||||||
|
customConnectionAllowed: true,
|
||||||
|
shared: true,
|
||||||
|
key: 'deepl',
|
||||||
|
});
|
||||||
|
|
||||||
|
const connectionAllowed =
|
||||||
|
await appConfig.computeConnectionAllowedProperty();
|
||||||
|
|
||||||
|
expect(connectionAllowed).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if there is no active app auth client', async () => {
|
||||||
|
await createAppAuthClient({
|
||||||
|
appKey: 'deepl',
|
||||||
|
active: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const appConfig = await createAppConfig({
|
||||||
|
disabled: false,
|
||||||
|
customConnectionAllowed: true,
|
||||||
|
shared: true,
|
||||||
|
key: 'deepl',
|
||||||
|
});
|
||||||
|
|
||||||
|
const connectionAllowed =
|
||||||
|
await appConfig.computeConnectionAllowedProperty();
|
||||||
|
|
||||||
|
expect(connectionAllowed).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if there is no app auth clients', async () => {
|
||||||
|
const appConfig = await createAppConfig({
|
||||||
|
disabled: false,
|
||||||
|
customConnectionAllowed: true,
|
||||||
|
shared: true,
|
||||||
|
key: 'deepl',
|
||||||
|
});
|
||||||
|
|
||||||
|
const connectionAllowed =
|
||||||
|
await appConfig.computeConnectionAllowedProperty();
|
||||||
|
|
||||||
|
expect(connectionAllowed).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false when app is disabled', async () => {
|
||||||
|
const appConfig = await createAppConfig({
|
||||||
|
disabled: true,
|
||||||
|
customConnectionAllowed: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const connectionAllowed =
|
||||||
|
await appConfig.computeConnectionAllowedProperty();
|
||||||
|
|
||||||
|
expect(connectionAllowed).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return false when app doesn't allow custom connection`, async () => {
|
||||||
|
const appConfig = await createAppConfig({
|
||||||
|
disabled: false,
|
||||||
|
customConnectionAllowed: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const connectionAllowed =
|
||||||
|
await appConfig.computeConnectionAllowedProperty();
|
||||||
|
|
||||||
|
expect(connectionAllowed).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('$beforeInsert should call computeAndAssignConnectionAllowedProperty', async () => {
|
||||||
|
const computeAndAssignConnectionAllowedPropertySpy = vi
|
||||||
|
.spyOn(AppConfig.prototype, 'computeAndAssignConnectionAllowedProperty')
|
||||||
|
.mockResolvedValue(true);
|
||||||
|
|
||||||
|
await createAppConfig();
|
||||||
|
|
||||||
|
expect(computeAndAssignConnectionAllowedPropertySpy).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('$beforeUpdate should call computeAndAssignConnectionAllowedProperty', async () => {
|
||||||
|
const appConfig = await createAppConfig();
|
||||||
|
|
||||||
|
const computeAndAssignConnectionAllowedPropertySpy = vi
|
||||||
|
.spyOn(AppConfig.prototype, 'computeAndAssignConnectionAllowedProperty')
|
||||||
|
.mockResolvedValue(true);
|
||||||
|
|
||||||
|
await appConfig.$query().patch({
|
||||||
|
key: 'deepl',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(computeAndAssignConnectionAllowedPropertySpy).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
|
});
|
@@ -89,7 +89,7 @@ class Connection extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.appConfig) {
|
if (this.appConfig) {
|
||||||
return !this.appConfig.disabled && this.appConfig.allowCustomConnection;
|
return !this.appConfig.disabled && this.appConfig.customConnectionAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -144,7 +144,7 @@ class Connection extends Base {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!appConfig.allowCustomConnection && this.formattedData) {
|
if (!appConfig.customConnectionAllowed && this.formattedData) {
|
||||||
throw new NotAuthorizedError(
|
throw new NotAuthorizedError(
|
||||||
`New custom connections have been disabled for ${app.name}!`
|
`New custom connections have been disabled for ${app.name}!`
|
||||||
);
|
);
|
||||||
|
@@ -121,7 +121,7 @@ describe('Connection model', () => {
|
|||||||
const appConfig = await createAppConfig({
|
const appConfig = await createAppConfig({
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
allowCustomConnection: true,
|
customConnectionAllowed: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const connection = await createConnection({
|
const connection = await createConnection({
|
||||||
@@ -151,7 +151,7 @@ describe('Connection model', () => {
|
|||||||
await createAppConfig({
|
await createAppConfig({
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
disabled: true,
|
disabled: true,
|
||||||
allowCustomConnection: false,
|
customConnectionAllowed: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const connectionWithAppAuthClient = await connection
|
const connectionWithAppAuthClient = await connection
|
||||||
@@ -373,7 +373,7 @@ describe('Connection model', () => {
|
|||||||
|
|
||||||
vi.spyOn(Connection.prototype, 'getAppConfig').mockResolvedValue({
|
vi.spyOn(Connection.prototype, 'getAppConfig').mockResolvedValue({
|
||||||
disabled: false,
|
disabled: false,
|
||||||
allowCustomConnection: false,
|
customConnectionAllowed: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const connection = new Connection();
|
const connection = new Connection();
|
||||||
@@ -410,7 +410,7 @@ describe('Connection model', () => {
|
|||||||
await createAppConfig({
|
await createAppConfig({
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
allowCustomConnection: true,
|
customConnectionAllowed: true,
|
||||||
shared: true,
|
shared: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -2,11 +2,10 @@ const appConfigSerializer = (appConfig) => {
|
|||||||
return {
|
return {
|
||||||
id: appConfig.id,
|
id: appConfig.id,
|
||||||
key: appConfig.key,
|
key: appConfig.key,
|
||||||
allowCustomConnection: appConfig.allowCustomConnection,
|
customConnectionAllowed: appConfig.customConnectionAllowed,
|
||||||
shared: appConfig.shared,
|
shared: appConfig.shared,
|
||||||
disabled: appConfig.disabled,
|
disabled: appConfig.disabled,
|
||||||
canConnect: appConfig.canConnect,
|
connectionAllowed: appConfig.connectionAllowed,
|
||||||
canCustomConnect: appConfig.canCustomConnect,
|
|
||||||
createdAt: appConfig.createdAt.getTime(),
|
createdAt: appConfig.createdAt.getTime(),
|
||||||
updatedAt: appConfig.updatedAt.getTime(),
|
updatedAt: appConfig.updatedAt.getTime(),
|
||||||
};
|
};
|
||||||
|
@@ -13,11 +13,10 @@ describe('appConfig serializer', () => {
|
|||||||
const expectedPayload = {
|
const expectedPayload = {
|
||||||
id: appConfig.id,
|
id: appConfig.id,
|
||||||
key: appConfig.key,
|
key: appConfig.key,
|
||||||
allowCustomConnection: appConfig.allowCustomConnection,
|
customConnectionAllowed: appConfig.customConnectionAllowed,
|
||||||
shared: appConfig.shared,
|
shared: appConfig.shared,
|
||||||
disabled: appConfig.disabled,
|
disabled: appConfig.disabled,
|
||||||
canConnect: appConfig.canConnect,
|
connectionAllowed: appConfig.connectionAllowed,
|
||||||
canCustomConnect: appConfig.canCustomConnect,
|
|
||||||
createdAt: appConfig.createdAt.getTime(),
|
createdAt: appConfig.createdAt.getTime(),
|
||||||
updatedAt: appConfig.updatedAt.getTime(),
|
updatedAt: appConfig.updatedAt.getTime(),
|
||||||
};
|
};
|
||||||
|
@@ -10,7 +10,6 @@ const formattedAuthDefaults = {
|
|||||||
|
|
||||||
export const createAppAuthClient = async (params = {}) => {
|
export const createAppAuthClient = async (params = {}) => {
|
||||||
params.name = params?.name || faker.person.fullName();
|
params.name = params?.name || faker.person.fullName();
|
||||||
params.id = params?.id || faker.string.uuid();
|
|
||||||
params.appKey = params?.appKey || 'deepl';
|
params.appKey = params?.appKey || 'deepl';
|
||||||
params.active = params?.active ?? true;
|
params.active = params?.active ?? true;
|
||||||
params.formattedAuthDefaults =
|
params.formattedAuthDefaults =
|
||||||
|
@@ -2,7 +2,7 @@ const createAppConfigMock = (appConfig) => {
|
|||||||
return {
|
return {
|
||||||
data: {
|
data: {
|
||||||
key: appConfig.key,
|
key: appConfig.key,
|
||||||
allowCustomConnection: appConfig.allowCustomConnection,
|
customConnectionAllowed: appConfig.customConnectionAllowed,
|
||||||
shared: appConfig.shared,
|
shared: appConfig.shared,
|
||||||
disabled: appConfig.disabled,
|
disabled: appConfig.disabled,
|
||||||
},
|
},
|
||||||
|
@@ -3,11 +3,10 @@ const getAppConfigMock = (appConfig) => {
|
|||||||
data: {
|
data: {
|
||||||
id: appConfig.id,
|
id: appConfig.id,
|
||||||
key: appConfig.key,
|
key: appConfig.key,
|
||||||
allowCustomConnection: appConfig.allowCustomConnection,
|
customConnectionAllowed: appConfig.customConnectionAllowed,
|
||||||
shared: appConfig.shared,
|
shared: appConfig.shared,
|
||||||
disabled: appConfig.disabled,
|
disabled: appConfig.disabled,
|
||||||
canConnect: appConfig.canConnect,
|
connectionAllowed: appConfig.connectionAllowed,
|
||||||
canCustomConnect: appConfig.canCustomConnect,
|
|
||||||
createdAt: appConfig.createdAt.getTime(),
|
createdAt: appConfig.createdAt.getTime(),
|
||||||
updatedAt: appConfig.updatedAt.getTime(),
|
updatedAt: appConfig.updatedAt.getTime(),
|
||||||
},
|
},
|
||||||
|
@@ -8,11 +8,15 @@ export class AdminApplicationSettingsPage extends AuthenticatedPage {
|
|||||||
constructor(page) {
|
constructor(page) {
|
||||||
super(page);
|
super(page);
|
||||||
|
|
||||||
this.allowCustomConnectionsSwitch = this.page.locator('[name="allowCustomConnection"]');
|
this.allowCustomConnectionsSwitch = this.page.locator(
|
||||||
|
'[name="customConnectionAllowed"]'
|
||||||
|
);
|
||||||
this.allowSharedConnectionsSwitch = this.page.locator('[name="shared"]');
|
this.allowSharedConnectionsSwitch = this.page.locator('[name="shared"]');
|
||||||
this.disableConnectionsSwitch = this.page.locator('[name="disabled"]');
|
this.disableConnectionsSwitch = this.page.locator('[name="disabled"]');
|
||||||
this.saveButton = this.page.getByTestId('submit-button');
|
this.saveButton = this.page.getByTestId('submit-button');
|
||||||
this.successSnackbar = this.page.getByTestId('snackbar-save-admin-apps-settings-success');
|
this.successSnackbar = this.page.getByTestId(
|
||||||
|
'snackbar-save-admin-apps-settings-success'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async allowCustomConnections() {
|
async allowCustomConnections() {
|
||||||
|
@@ -20,7 +20,7 @@ function AdminApplicationCreateAuthClient(props) {
|
|||||||
const {
|
const {
|
||||||
mutateAsync: createAppConfig,
|
mutateAsync: createAppConfig,
|
||||||
isPending: isCreateAppConfigPending,
|
isPending: isCreateAppConfigPending,
|
||||||
error: createAppConfigError
|
error: createAppConfigError,
|
||||||
} = useAdminCreateAppConfig(props.appKey);
|
} = useAdminCreateAppConfig(props.appKey);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -30,16 +30,15 @@ function AdminApplicationCreateAuthClient(props) {
|
|||||||
} = useAdminCreateAppAuthClient(appKey);
|
} = useAdminCreateAppAuthClient(appKey);
|
||||||
|
|
||||||
const submitHandler = async (values) => {
|
const submitHandler = async (values) => {
|
||||||
let appConfigId = appConfig?.data?.id;
|
let appConfigKey = appConfig?.data?.key;
|
||||||
|
|
||||||
if (!appConfigId) {
|
if (!appConfigKey) {
|
||||||
const { data: appConfigData } = await createAppConfig({
|
const { data: appConfigData } = await createAppConfig({
|
||||||
allowCustomConnection: true,
|
customConnectionAllowed: true,
|
||||||
shared: false,
|
shared: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
});
|
});
|
||||||
|
appConfigKey = appConfigData.key;
|
||||||
appConfigId = appConfigData.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { name, active, ...formattedAuthDefaults } = values;
|
const { name, active, ...formattedAuthDefaults } = values;
|
||||||
|
@@ -46,7 +46,8 @@ function AdminApplicationSettings(props) {
|
|||||||
|
|
||||||
const defaultValues = useMemo(
|
const defaultValues = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
allowCustomConnection: appConfig?.data?.allowCustomConnection || false,
|
customConnectionAllowed:
|
||||||
|
appConfig?.data?.customConnectionAllowed || false,
|
||||||
shared: appConfig?.data?.shared || false,
|
shared: appConfig?.data?.shared || false,
|
||||||
disabled: appConfig?.data?.disabled || false,
|
disabled: appConfig?.data?.disabled || false,
|
||||||
}),
|
}),
|
||||||
@@ -61,8 +62,8 @@ function AdminApplicationSettings(props) {
|
|||||||
<Paper sx={{ p: 2, mt: 4 }}>
|
<Paper sx={{ p: 2, mt: 4 }}>
|
||||||
<Stack spacing={2} direction="column">
|
<Stack spacing={2} direction="column">
|
||||||
<Switch
|
<Switch
|
||||||
name="allowCustomConnection"
|
name="customConnectionAllowed"
|
||||||
label={formatMessage('adminAppsSettings.allowCustomConnection')}
|
label={formatMessage('adminAppsSettings.customConnectionAllowed')}
|
||||||
FormControlLabelProps={{
|
FormControlLabelProps={{
|
||||||
labelPlacement: 'start',
|
labelPlacement: 'start',
|
||||||
}}
|
}}
|
||||||
|
@@ -93,14 +93,17 @@ function ChooseConnectionSubstep(props) {
|
|||||||
appWithConnections?.map((connection) => optionGenerator(connection)) ||
|
appWithConnections?.map((connection) => optionGenerator(connection)) ||
|
||||||
[];
|
[];
|
||||||
|
|
||||||
if (!appConfig?.data || appConfig?.data?.canCustomConnect) {
|
if (
|
||||||
|
!appConfig?.data ||
|
||||||
|
(!appConfig.data?.disabled && appConfig.data?.customConnectionAllowed)
|
||||||
|
) {
|
||||||
options.push({
|
options.push({
|
||||||
label: formatMessage('chooseConnectionSubstep.addNewConnection'),
|
label: formatMessage('chooseConnectionSubstep.addNewConnection'),
|
||||||
value: ADD_CONNECTION_VALUE,
|
value: ADD_CONNECTION_VALUE,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appConfig?.data?.canConnect) {
|
if (appConfig?.data?.connectionAllowed) {
|
||||||
options.push({
|
options.push({
|
||||||
label: formatMessage('chooseConnectionSubstep.addNewSharedConnection'),
|
label: formatMessage('chooseConnectionSubstep.addNewSharedConnection'),
|
||||||
value: ADD_SHARED_CONNECTION_VALUE,
|
value: ADD_SHARED_CONNECTION_VALUE,
|
||||||
|
@@ -292,7 +292,7 @@
|
|||||||
"adminApps.connections": "Connections",
|
"adminApps.connections": "Connections",
|
||||||
"adminApps.authClients": "Auth clients",
|
"adminApps.authClients": "Auth clients",
|
||||||
"adminApps.settings": "Settings",
|
"adminApps.settings": "Settings",
|
||||||
"adminAppsSettings.allowCustomConnection": "Allow custom connection",
|
"adminAppsSettings.customConnectionAllowed": "Allow custom connection",
|
||||||
"adminAppsSettings.shared": "Shared",
|
"adminAppsSettings.shared": "Shared",
|
||||||
"adminAppsSettings.disabled": "Disabled",
|
"adminAppsSettings.disabled": "Disabled",
|
||||||
"adminAppsSettings.save": "Save",
|
"adminAppsSettings.save": "Save",
|
||||||
|
@@ -77,14 +77,15 @@ export default function Application() {
|
|||||||
|
|
||||||
const connectionOptions = React.useMemo(() => {
|
const connectionOptions = React.useMemo(() => {
|
||||||
const shouldHaveCustomConnection =
|
const shouldHaveCustomConnection =
|
||||||
appConfig?.data?.canConnect && appConfig?.data?.canCustomConnect;
|
appConfig?.data?.connectionAllowed &&
|
||||||
|
appConfig?.data?.customConnectionAllowed;
|
||||||
|
|
||||||
const options = [
|
const options = [
|
||||||
{
|
{
|
||||||
label: formatMessage('app.addConnection'),
|
label: formatMessage('app.addConnection'),
|
||||||
key: 'addConnection',
|
key: 'addConnection',
|
||||||
'data-test': 'add-connection-button',
|
'data-test': 'add-connection-button',
|
||||||
to: URLS.APP_ADD_CONNECTION(appKey, appConfig?.data?.canConnect),
|
to: URLS.APP_ADD_CONNECTION(appKey, appConfig?.data?.connectionAllowed),
|
||||||
disabled: !currentUserAbility.can('create', 'Connection'),
|
disabled: !currentUserAbility.can('create', 'Connection'),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -155,8 +156,9 @@ export default function Application() {
|
|||||||
disabled={
|
disabled={
|
||||||
!allowed ||
|
!allowed ||
|
||||||
(appConfig?.data &&
|
(appConfig?.data &&
|
||||||
!appConfig?.data?.canConnect &&
|
!appConfig?.data?.disabled &&
|
||||||
!appConfig?.data?.canCustomConnect) ||
|
!appConfig?.data?.connectionAllowed &&
|
||||||
|
!appConfig?.data?.customConnectionAllowed) ||
|
||||||
connectionOptions.every(({ disabled }) => disabled)
|
connectionOptions.every(({ disabled }) => disabled)
|
||||||
}
|
}
|
||||||
options={connectionOptions}
|
options={connectionOptions}
|
||||||
|
@@ -459,9 +459,8 @@ export const SamlAuthProviderRolePropType = PropTypes.shape({
|
|||||||
export const AppConfigPropType = PropTypes.shape({
|
export const AppConfigPropType = PropTypes.shape({
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
key: PropTypes.string,
|
key: PropTypes.string,
|
||||||
allowCustomConnection: PropTypes.bool,
|
customConnectionAllowed: PropTypes.bool,
|
||||||
canConnect: PropTypes.bool,
|
connectionAllowed: PropTypes.bool,
|
||||||
canCustomConnect: PropTypes.bool,
|
|
||||||
shared: PropTypes.bool,
|
shared: PropTypes.bool,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
});
|
});
|
||||||
@@ -469,7 +468,7 @@ export const AppConfigPropType = PropTypes.shape({
|
|||||||
export const AppAuthClientPropType = PropTypes.shape({
|
export const AppAuthClientPropType = PropTypes.shape({
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
appConfigId: PropTypes.string,
|
appConfigKey: PropTypes.string,
|
||||||
authDefaults: PropTypes.string,
|
authDefaults: PropTypes.string,
|
||||||
formattedAuthDefaults: PropTypes.object,
|
formattedAuthDefaults: PropTypes.object,
|
||||||
active: PropTypes.bool,
|
active: PropTypes.bool,
|
||||||
|
Reference in New Issue
Block a user