Browse Source

Merge pull request #7140 from nocodb/fix/various-sn

fix: various leftover stuff
pull/6066/merge
mertmit 12 months ago committed by GitHub
parent
commit
068fbdcedf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      packages/nc-gui/components/account/UsersModal.vue
  2. 1
      packages/nc-gui/components/cell/DatePicker.vue
  3. 18
      packages/nc-gui/components/dashboard/TreeView/ProjectNode.vue
  4. 1
      packages/nocodb/src/db/BaseModelSqlv2.ts
  5. 6
      packages/nocodb/src/db/sql-client/lib/mysql/MysqlClient.ts
  6. 1
      packages/nocodb/src/helpers/index.ts
  7. 4033
      packages/nocodb/src/helpers/isDisposableEmail.ts
  8. 22
      packages/nocodb/src/helpers/sqlSanitize.ts
  9. 11
      packages/nocodb/src/interface/Jobs.ts
  10. 6
      packages/nocodb/src/modules/jobs/redis/jobs-event.service.ts
  11. 11
      packages/nocodb/src/modules/jobs/redis/jobs-redis.service.ts
  12. 21
      packages/nocodb/src/modules/jobs/redis/jobs.service.ts
  13. 2
      packages/nocodb/tests/unit/rest/tests/groupby.test.ts

1
packages/nc-gui/components/account/UsersModal.vue

@ -192,6 +192,7 @@ const emailInput: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
<div class="flex flex-col w-2/4">
<a-form-item name="role" :rules="[{ required: true, message: $t('msg.roleRequired') }]">
<div class="ml-1 mb-1 text-xs text-gray-500">{{ $t('labels.selectUserRole') }}</div>
<a-select v-model:value="usersData.role" class="nc-user-roles" dropdown-class-name="nc-dropdown-user-role">
<a-select-option
class="nc-role-option"

1
packages/nc-gui/components/cell/DatePicker.vue

@ -22,6 +22,7 @@ interface Props {
}
const { modelValue, isPk } = defineProps<Props>()
const emit = defineEmits(['update:modelValue'])
const { t } = useI18n()

18
packages/nc-gui/components/dashboard/TreeView/ProjectNode.vue

@ -77,7 +77,7 @@ const tempTitle = ref('')
const activeBaseId = ref('')
const isErdModalOpen = ref<boolean>(false)
const isErdModalOpen = ref<Boolean>(false)
const { t } = useI18n()
@ -116,7 +116,7 @@ const showBaseOption = computed(() => {
return ['airtableImport', 'csvImport', 'jsonImport', 'excelImport'].some((permission) => isUIAllowed(permission))
})
function enableEditMode() {
const enableEditMode = () => {
editMode.value = true
tempTitle.value = base.value.title!
nextTick(() => {
@ -126,7 +126,7 @@ function enableEditMode() {
})
}
async function updateProjectTitle() {
const updateProjectTitle = async () => {
if (!tempTitle.value) return
try {
@ -146,7 +146,7 @@ async function updateProjectTitle() {
const { copy } = useCopy(true)
async function copyProjectInfo() {
const copyProjectInfo = async () => {
try {
if (
await copy(
@ -168,7 +168,7 @@ defineExpose({
enableEditMode,
})
async function setIcon(icon: string, base: BaseType) {
const setIcon = async (icon: string, base: BaseType) => {
try {
const meta = {
...((base.meta as object) || {}),
@ -249,7 +249,7 @@ async function addNewProjectChildEntity() {
}
}
async function onProjectClick(base: NcProject, ignoreNavigation?: boolean, toggleIsExpanded?: boolean) {
const onProjectClick = async (base: NcProject, ignoreNavigation?: boolean, toggleIsExpanded?: boolean) => {
if (!base) {
return
}
@ -348,17 +348,17 @@ onKeyStroke('Escape', () => {
const isDuplicateDlgOpen = ref(false)
const selectedProjectToDuplicate = ref()
function duplicateProject(base: BaseType) {
const duplicateProject = (base: BaseType) => {
selectedProjectToDuplicate.value = base
isDuplicateDlgOpen.value = true
}
function tableDelete() {
const tableDelete = () => {
isTableDeleteDialogVisible.value = true
$e('c:table:delete')
}
function projectDelete() {
const projectDelete = () => {
isProjectDeleteDialogVisible.value = true
$e('c:project:delete')
}

1
packages/nocodb/src/db/BaseModelSqlv2.ts

@ -2305,6 +2305,7 @@ class BaseModelSqlv2 {
if ('beforeInsert' in this) {
await this.beforeInsert(insertObj, trx, cookie);
}
await this.prepareAttachmentData(insertObj);
let response;

6
packages/nocodb/src/db/sql-client/lib/mysql/MysqlClient.ts

@ -20,9 +20,9 @@ const log = new Debug('MysqlClient');
const evt = new Emit();
class MysqlClient extends KnexClient {
private queries: any;
private _version: any;
private types: any;
protected queries: any;
protected _version: any;
protected types: any;
constructor(connectionConfig) {
super(connectionConfig);

1
packages/nocodb/src/helpers/index.ts

@ -3,5 +3,6 @@ export * from './columnHelpers';
export * from './apiHelpers';
export * from './cacheHelpers';
export * from './extractLimitAndOffset';
export * from './isDisposableEmail';
export { populateMeta };

4033
packages/nocodb/src/helpers/isDisposableEmail.ts

File diff suppressed because it is too large Load Diff

22
packages/nocodb/src/helpers/sqlSanitize.ts

@ -1,3 +1,5 @@
import type { XKnex } from '~/db/CustomKnex';
export function sanitize(v) {
if (typeof v !== 'string') return v;
return v?.replace(/([^\\]|^)(\?+)/g, (_, m1, m2) => {
@ -9,3 +11,23 @@ export function unsanitize(v) {
if (typeof v !== 'string') return v;
return v?.replace(/\\[?]/g, '?');
}
export function sanitizeAndEscapeDots(alias: string, knex: XKnex) {
const sanitizedAlias = sanitize(alias);
// if alias does not contain any dot then return as it is
if (!knex || !sanitizedAlias.includes('.')) return sanitizedAlias;
// if alias contains dot then return knex.raw with escaped dot
switch (knex?.clientType?.()) {
case 'mysql':
case 'mysql2':
return knex.raw(
knex.raw('??', sanitizedAlias).toQuery().replace(/`\.`/g, '.'),
);
case 'pg':
return knex.raw(
knex.raw('??', sanitizedAlias).toQuery().replace(/"\."/g, '.'),
);
default:
return sanitizedAlias;
}
}

11
packages/nocodb/src/interface/Jobs.ts

@ -28,13 +28,14 @@ export enum JobEvents {
LOG = 'job.log',
}
export enum InstanceTypes {
PRIMARY = 'primary',
WORKER = 'worker',
}
export const InstanceTypes = {
PRIMARY: `${process.env.NC_ENV ?? 'default'}-primary`,
WORKER: `${process.env.NC_ENV ?? 'default'}-worker`,
};
export enum WorkerCommands {
export enum InstanceCommands {
RESUME_LOCAL = 'resumeLocal',
PAUSE_LOCAL = 'pauseLocal',
RESET = 'reset',
RELEASE = 'release',
}

6
packages/nocodb/src/modules/jobs/redis/jobs-event.service.ts

@ -7,14 +7,18 @@ import {
import { Job } from 'bull';
import boxen from 'boxen';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { Logger } from '@nestjs/common';
import { JobEvents, JOBS_QUEUE, JobStatus } from '~/interface/Jobs';
@Processor(JOBS_QUEUE)
export class JobsEventService {
protected logger = new Logger(JobsEventService.name);
constructor(private eventEmitter: EventEmitter2) {}
@OnQueueActive()
onActive(job: Job) {
this.logger.log(`Processing job ${job.id} of type ${job.name}`);
this.eventEmitter.emit(JobEvents.STATUS, {
id: job.id.toString(),
status: JobStatus.ACTIVE,
@ -23,6 +27,7 @@ export class JobsEventService {
@OnQueueFailed()
onFailed(job: Job, error: Error) {
this.logger.error(`Job ${job.id} failed with error ${error.message}`);
console.error(
boxen(
`---- !! JOB FAILED !! ----\nid:${job.id}\nerror:${error.name} (${error.message})\n\nstack: ${error.stack}`,
@ -47,6 +52,7 @@ export class JobsEventService {
@OnQueueCompleted()
onCompleted(job: Job, data: any) {
this.logger.log(`Job ${job.id} completed`);
this.eventEmitter.emit(JobEvents.STATUS, {
id: job.id.toString(),
status: JobStatus.COMPLETED,

11
packages/nocodb/src/modules/jobs/redis/jobs-redis.service.ts

@ -8,8 +8,8 @@ export class JobsRedisService {
private redisSubscriber: Redis;
private unsubscribeCallbacks: { [key: string]: () => void } = {};
public primaryCallbacks: { [key: string]: () => void } = {};
public workerCallbacks: { [key: string]: () => void } = {};
public primaryCallbacks: { [key: string]: (...args) => void } = {};
public workerCallbacks: { [key: string]: (...args) => void } = {};
constructor() {
this.redisClient = new Redis(process.env.NC_REDIS_JOB_URL);
@ -22,10 +22,13 @@ export class JobsRedisService {
}
const onMessage = (channel, message) => {
const args = message.split(':');
const command = args.shift();
if (channel === InstanceTypes.WORKER) {
this.workerCallbacks[message] && this.workerCallbacks[message]();
this.workerCallbacks[command] && this.workerCallbacks[command](...args);
} else if (channel === InstanceTypes.PRIMARY) {
this.primaryCallbacks[message] && this.primaryCallbacks[message]();
this.primaryCallbacks[command] &&
this.primaryCallbacks[command](...args);
}
};

21
packages/nocodb/src/modules/jobs/redis/jobs.service.ts

@ -2,7 +2,12 @@ import { InjectQueue } from '@nestjs/bull';
import { Injectable, Logger } from '@nestjs/common';
import { Queue } from 'bull';
import type { OnModuleInit } from '@nestjs/common';
import { JOBS_QUEUE, JobStatus, WorkerCommands } from '~/interface/Jobs';
import {
InstanceCommands,
InstanceTypes,
JOBS_QUEUE,
JobStatus,
} from '~/interface/Jobs';
import { JobsRedisService } from '~/modules/jobs/redis/jobs-redis.service';
@Injectable()
@ -19,12 +24,12 @@ export class JobsService implements OnModuleInit {
if (process.env.NC_WORKER_CONTAINER !== 'true') {
await this.jobsQueue.pause(true);
} else {
this.jobsRedisService.workerCallbacks[WorkerCommands.RESUME_LOCAL] =
this.jobsRedisService.workerCallbacks[InstanceCommands.RESUME_LOCAL] =
async () => {
this.logger.log('Resuming local queue');
await this.jobsQueue.resume(true);
};
this.jobsRedisService.workerCallbacks[WorkerCommands.PAUSE_LOCAL] =
this.jobsRedisService.workerCallbacks[InstanceCommands.PAUSE_LOCAL] =
async () => {
this.logger.log('Pausing local queue');
await this.jobsQueue.pause(true);
@ -102,4 +107,14 @@ export class JobsService implements OnModuleInit {
this.logger.log('Pausing global queue');
await this.jobsQueue.pause();
}
async emitWorkerCommand(command: InstanceCommands, ...args: any[]) {
const data = `${command}${args.length ? `:${args.join(':')}` : ''}`;
await this.jobsRedisService.publish(InstanceTypes.WORKER, data);
}
async emitPrimaryCommand(command: InstanceCommands, ...args: any[]) {
const data = `${command}${args.length ? `:${args.join(':')}` : ''}`;
await this.jobsRedisService.publish(InstanceTypes.PRIMARY, data);
}
}

2
packages/nocodb/tests/unit/rest/tests/groupby.test.ts

@ -18,7 +18,7 @@ function groupByTests() {
let filmView: View;
let gridViewColumns;
before(async function () {
beforeEach(async function () {
console.time('GroupBy Tests');
context = await init();

Loading…
Cancel
Save