From 88e08e50f9d9ba4e5fd91c9c20dd5ebdc7efc5e0 Mon Sep 17 00:00:00 2001 From: Akhil G Krishnan Date: Tue, 21 Sep 2021 10:05:36 +0530 Subject: [PATCH 01/69] BugFix: User Invitation URL in email is not clickable (#799) --- server/src/services/email.service.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/services/email.service.ts b/server/src/services/email.service.ts index af45e01d7a..3075300edb 100644 --- a/server/src/services/email.service.ts +++ b/server/src/services/email.service.ts @@ -82,6 +82,7 @@ export class EmailService { async sendOrganizationUserWelcomeEmail(to: string, name: string, sender: string, invitationtoken: string) { const subject = 'Welcome to ToolJet'; + const inviteUrl = `${this.TOOLJET_HOST}/invitations/${invitationtoken}` const html = ` @@ -94,7 +95,7 @@ export class EmailService { ${sender} has invited you to use ToolJet. Use the link below to set up your account and get started.
- ${`${this.TOOLJET_HOST}/invitations/${invitationtoken}`} + ${inviteUrl}

Welcome aboard,
From bc193c081f942353bacb629d26258ad9597d438d Mon Sep 17 00:00:00 2001 From: Akshay Date: Tue, 21 Sep 2021 10:20:02 +0530 Subject: [PATCH 02/69] Fix: Only update credentials when data source is updated (#763) * only update credentials when data source is updated * fix spec --- .../controllers/data_sources.controller.ts | 10 +- server/src/entities/credential.entity.ts | 21 +- server/src/services/credentials.service.ts | 30 ++- server/src/services/data_sources.service.ts | 159 +++++++++----- .../test/controllers/data_sources.e2e-spec.ts | 198 +++++++++++++----- server/test/test.helper.ts | 170 +++++++++------ 6 files changed, 402 insertions(+), 186 deletions(-) diff --git a/server/src/controllers/data_sources.controller.ts b/server/src/controllers/data_sources.controller.ts index 8e9d0dc4e1..88e3466060 100644 --- a/server/src/controllers/data_sources.controller.ts +++ b/server/src/controllers/data_sources.controller.ts @@ -26,7 +26,7 @@ export class DataSourcesController { if(!ability.can('getDataSources', app)) { throw new ForbiddenException('you do not have permissions to perform this action'); } - + const dataSources = await this.dataSourcesService.all(req.user, query.app_id); let response = decamelizeKeys({ data_sources: dataSources }); @@ -45,8 +45,8 @@ export class DataSourcesController { if(!ability.can('createDataSource', app)) { throw new ForbiddenException('you do not have permissions to perform this action'); } - - const dataSource = await this.dataSourcesService.create(req.user, name, kind, options, appId); + + const dataSource = await this.dataSourcesService.create(name, kind, options, appId); return decamelizeKeys(dataSource); } @@ -64,8 +64,8 @@ export class DataSourcesController { if(!ability.can('updateDataSource', app)) { throw new ForbiddenException('you do not have permissions to perform this action'); } - - const result = await this.dataSourcesService.update(req.user, dataSourceId, name, options); + + const result = await this.dataSourcesService.update(dataSourceId, name, options); return decamelizeKeys(result); } diff --git a/server/src/entities/credential.entity.ts b/server/src/entities/credential.entity.ts index fb6d5dc06c..b75cfa46a5 100644 --- a/server/src/entities/credential.entity.ts +++ b/server/src/entities/credential.entity.ts @@ -1,18 +1,23 @@ -import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm'; +import { + Entity, + Column, + PrimaryGeneratedColumn, + CreateDateColumn, + UpdateDateColumn, + BaseEntity +} from 'typeorm'; -@Entity({ name: "credentials" }) -export class Credential { - - @PrimaryGeneratedColumn("uuid") +@Entity({ name: 'credentials' }) +export class Credential extends BaseEntity { + @PrimaryGeneratedColumn('uuid') id: string; - @Column( { name: 'value_ciphertext' } ) + @Column({ name: 'value_ciphertext' }) valueCiphertext: string; @CreateDateColumn({ default: () => 'now()', name: 'created_at' }) createdAt: Date; - + @UpdateDateColumn({ default: () => 'now()', name: 'updated_at' }) updatedAt: Date; - } diff --git a/server/src/services/credentials.service.ts b/server/src/services/credentials.service.ts index 132e438d25..e926508c0b 100644 --- a/server/src/services/credentials.service.ts +++ b/server/src/services/credentials.service.ts @@ -3,20 +3,23 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Credential } from '../../src/entities/credential.entity'; import { Repository } from 'typeorm'; import { EncryptionService } from './encryption.service'; -const crypto = require('crypto') +const crypto = require('crypto'); @Injectable() export class CredentialsService { - constructor( private encryptionService: EncryptionService, @InjectRepository(Credential) private credentialsRepository: Repository, - ) { } + ) {} async create(value: string): Promise { const newCredential = this.credentialsRepository.create({ - valueCiphertext: await this.encryptionService.encryptColumnValue('credentials', 'value', value), + valueCiphertext: await this.encryptionService.encryptColumnValue( + 'credentials', + 'value', + value, + ), createdAt: new Date(), updatedAt: new Date(), }); @@ -24,9 +27,24 @@ export class CredentialsService { return credential; } - async getValue(credentialId: string): Promise { + async update(id: string, value: string) { + const valueCiphertext = await this.encryptionService.encryptColumnValue( + 'credentials', + 'value', + value, + ); + const params = { valueCiphertext, updatedAt: new Date() }; + + return await this.credentialsRepository.update(id, params); + } + + async getValue(credentialId: string): Promise { const credential = await this.credentialsRepository.findOne(credentialId); - const decryptedValue = await this.encryptionService.decryptColumnValue('credentials', 'value', credential.valueCiphertext) + const decryptedValue = await this.encryptionService.decryptColumnValue( + 'credentials', + 'value', + credential.valueCiphertext, + ); return decryptedValue; } } diff --git a/server/src/services/data_sources.service.ts b/server/src/services/data_sources.service.ts index 4ccfb8a0f7..c9b38b8295 100644 --- a/server/src/services/data_sources.service.ts +++ b/server/src/services/data_sources.service.ts @@ -8,31 +8,37 @@ import { allPlugins } from 'src/modules/data_sources/plugins'; @Injectable() export class DataSourcesService { - constructor( private credentialsService: CredentialsService, @InjectRepository(DataSource) private dataSourcesRepository: Repository, - ) { } + ) {} async all(user: User, appId: string): Promise { - return await this.dataSourcesRepository.find({ - where: { - appId - }, + where: { + appId, + }, }); } async findOne(dataSourceId: string): Promise { - return await this.dataSourcesRepository.findOne({ where: { id: dataSourceId}, relations: ['app'] }); + return await this.dataSourcesRepository.findOne({ + where: { id: dataSourceId }, + relations: ['app'], + }); } - async create(user: User, name:string, kind:string, options:Array, appId:string): Promise { - const newDataSource = this.dataSourcesRepository.create({ + async create( + name: string, + kind: string, + options: Array, + appId: string, + ): Promise { + const newDataSource = this.dataSourcesRepository.create({ name, kind, - options: await this.parseOptionsForSaving(options), + options: await this.parseOptionsForCreate(options), appId, createdAt: new Date(), updatedAt: new Date(), @@ -41,40 +47,53 @@ export class DataSourcesService { return dataSource; } - async update(user: User, dataSourceId:string, name:string, options:Array): Promise { + async update( + dataSourceId: string, + name: string, + options: Array, + ): Promise { + const dataSource = await this.findOne(dataSourceId); const updateableParams = { id: dataSourceId, name, - options: await this.parseOptionsForSaving(options), - updatedAt: new Date() - } + options: await this.parseOptionsForUpdate(dataSource, options), + updatedAt: new Date(), + }; // Remove keys with undefined values - Object.keys(updateableParams).forEach(key => updateableParams[key] === undefined ? delete updateableParams[key] : {}); + Object.keys(updateableParams).forEach((key) => + updateableParams[key] === undefined ? delete updateableParams[key] : {}, + ); - const dataSource = this.dataSourcesRepository.save(updateableParams); - - return dataSource; + return this.dataSourcesRepository.save(updateableParams); } /* This function merges new options with the existing options */ - async updateOptions(dataSourceId: string, optionsToMerge: any): Promise { - const parsedOptions = await this.parseOptionsForSaving(optionsToMerge); + async updateOptions( + dataSourceId: string, + optionsToMerge: any, + ): Promise { const dataSource = await this.findOne(dataSourceId); + const parsedOptions = await this.parseOptionsForUpdate( + dataSource, + optionsToMerge, + ); const updatedOptions = { ...dataSource.options, ...parsedOptions }; - return await this.dataSourcesRepository.save({ id: dataSourceId, options: updatedOptions }); + return await this.dataSourcesRepository.save({ + id: dataSourceId, + options: updatedOptions, + }); } async testConnection(kind: string, options: object): Promise { let result = {}; try { - let sourceOptions = {}; - for(const key of Object.keys(options)) { + for (const key of Object.keys(options)) { sourceOptions[key] = options[key]['value']; } @@ -82,55 +101,98 @@ export class DataSourcesService { const serviceClass = plugins[kind]; const service = new serviceClass(); result = await service.testConnection(sourceOptions); - - } catch(error) { + } catch (error) { result = { status: 'failed', - message: error.message - } + message: error.message, + }; } return result; } - - async parseOptionsForSaving(options:Array) { - let parsedOptions = {} - - // Check if an Oauth2 datasource - if(options.find(option => option['key'] === 'oauth2')) { - const provider = options.find(option => option['key'] === 'provider')['value']; - const authCode = options.find(option => option['key'] === 'code')['value']; + async parseOptionsForOauthDataSource(options: Array) { + if (options.find((option) => option['key'] === 'oauth2')) { + const provider = options.find((option) => option['key'] === 'provider')[ + 'value' + ]; + const authCode = options.find((option) => option['key'] === 'code')[ + 'value' + ]; const plugins = await allPlugins; - const queryService = new plugins[provider]; + const queryService = new plugins[provider](); const accessDetails = await queryService.accessDetailsFrom(authCode); - for(const row of accessDetails) { + for (const row of accessDetails) { const option = {}; option['key'] = row[0]; - option['value'] = row[1] + option['value'] = row[1]; option['encrypted'] = true; options.push(option); } - options = options.filter(option => !(['provider', 'code', 'oauth2'].includes(option['key'])) ); + options = options.filter( + (option) => !['provider', 'code', 'oauth2'].includes(option['key']), + ); } - for (const option of options) { - if(option['encrypted']) { - const credential = await this.credentialsService.create(option['value'] || ''); + return options; + } + + async parseOptionsForCreate(options: Array) { + if (!options) return {}; + + const optionsWithOauth = await this.parseOptionsForOauthDataSource(options); + const parsedOptions = {}; + + for (const option of optionsWithOauth) { + if (option['encrypted']) { + const credential = await this.credentialsService.create( + option['value'] || '', + ); parsedOptions[option['key']] = { credential_id: credential.id, - encrypted: option["encrypted"] - } + encrypted: option['encrypted'], + }; } else { parsedOptions[option['key']] = { value: option['value'], - encrypted: false - } + encrypted: false, + }; + } + } + + return parsedOptions; + } + + async parseOptionsForUpdate(dataSource: DataSource, options: Array) { + if (!options) return {}; + + const optionsWithOauth = await this.parseOptionsForOauthDataSource(options); + const parsedOptions = {}; + + for (const option of optionsWithOauth) { + if (option['encrypted']) { + const existingCredentialId = + dataSource.options[option['key']]['credential_id']; + + await this.credentialsService.update( + existingCredentialId, + option['value'] || '', + ); + + parsedOptions[option['key']] = { + credential_id: existingCredentialId, + encrypted: option['encrypted'], + }; + } else { + parsedOptions[option['key']] = { + value: option['value'], + encrypted: false, + }; } } @@ -139,8 +201,7 @@ export class DataSourcesService { async getAuthUrl(provider): Promise { const plugins = await allPlugins; - const service = new plugins[provider]; - return { url: service.authUrl() } + const service = new plugins[provider](); + return { url: service.authUrl() }; } - } diff --git a/server/test/controllers/data_sources.e2e-spec.ts b/server/test/controllers/data_sources.e2e-spec.ts index a5e9f3867f..c149b053e9 100644 --- a/server/test/controllers/data_sources.e2e-spec.ts +++ b/server/test/controllers/data_sources.e2e-spec.ts @@ -1,6 +1,14 @@ import * as request from 'supertest'; import { INestApplication } from '@nestjs/common'; -import { authHeaderForUser, clearDB, createApplication, createUser, createNestAppInstance, createApplicationVersion, createDataQuery, createDataSource } from '../test.helper'; +import { + authHeaderForUser, + clearDB, + createApplication, + createUser, + createNestAppInstance, + createDataSource, +} from '../test.helper'; +import { Credential } from 'src/entities/credential.entity'; describe('data sources controller', () => { let app: INestApplication; @@ -14,89 +22,164 @@ describe('data sources controller', () => { }); it('should be able to create data sources of an app only if admin/developer of same organization', async () => { + const adminUserData = await createUser(app, { + email: 'admin@tooljet.io', + role: 'admin', + }); + const developerUserData = await createUser(app, { + email: 'developer@tooljet.io', + role: 'developer', + organization: adminUserData.organization, + }); + const viewerUserData = await createUser(app, { + email: 'viewer@tooljet.io', + role: 'viewer', + organization: adminUserData.organization, + }); + const anotherOrgAdminUserData = await createUser(app, { + email: 'another@tooljet.io', + role: 'admin', + }); + const application = await createApplication(app, { + name: 'name', + user: adminUserData.user, + }); - const adminUserData = await createUser(app, { email: 'admin@tooljet.io', role: 'admin' }); - const developerUserData = await createUser(app, { email: 'developer@tooljet.io', role: 'developer', organization: adminUserData.organization }); - const viewerUserData = await createUser(app, { email: 'viewer@tooljet.io', role: 'viewer', organization: adminUserData.organization }); - const anotherOrgAdminUserData = await createUser(app, { email: 'another@tooljet.io', role: 'admin' }); - const application = await createApplication(app, { name: 'name', user: adminUserData.user }); + const dataSourceParams = { + name: 'name', + options: [{ key: 'foo', value: 'bar', encrypted: 'true' }], + kind: 'postgres', + app_id: application.id, + }; - const dataSourceParams = { - name: 'name', - options: [], - kind: 'postgres', - app_id: application.id - } - - for(const userData of [adminUserData, developerUserData]) { + for (const userData of [adminUserData, developerUserData]) { const response = await request(app.getHttpServer()) .post(`/data_sources`) .set('Authorization', authHeaderForUser(userData.user)) - .send(dataSourceParams) + .send(dataSourceParams); expect(response.statusCode).toBe(201); } + // encrypted data source options will create credentials + expect(await Credential.count()).toBe(2); + // Should not update if viewer or if user of another org - for(const userData of [anotherOrgAdminUserData, viewerUserData]) { + for (const userData of [anotherOrgAdminUserData, viewerUserData]) { const response = await request(app.getHttpServer()) .post(`/data_sources`) .set('Authorization', authHeaderForUser(userData.user)) - .send(dataSourceParams) + .send(dataSourceParams); expect(response.statusCode).toBe(403); } - }); it('should be able to update data sources of an app only if admin/developer of same organization', async () => { + const adminUserData = await createUser(app, { + email: 'admin@tooljet.io', + role: 'admin', + }); + const developerUserData = await createUser(app, { + email: 'developer@tooljet.io', + role: 'developer', + organization: adminUserData.organization, + }); + const viewerUserData = await createUser(app, { + email: 'viewer@tooljet.io', + role: 'viewer', + organization: adminUserData.organization, + }); + const anotherOrgAdminUserData = await createUser(app, { + email: 'another@tooljet.io', + role: 'admin', + }); + const application = await createApplication(app, { + name: 'name', + user: adminUserData.user, + }); + const dataSource = await createDataSource(app, { + name: 'name', + options: [{ key: 'foo', value: 'bar', encrypted: 'true' }], + kind: 'postgres', + application: application, + user: adminUserData.user, + }); - const adminUserData = await createUser(app, { email: 'admin@tooljet.io', role: 'admin' }); - const developerUserData = await createUser(app, { email: 'developer@tooljet.io', role: 'developer', organization: adminUserData.organization }); - const viewerUserData = await createUser(app, { email: 'viewer@tooljet.io', role: 'viewer', organization: adminUserData.organization }); - const anotherOrgAdminUserData = await createUser(app, { email: 'another@tooljet.io', role: 'admin' }); - const application = await createApplication(app, { name: 'name', user: adminUserData.user }); - const dataSource = await createDataSource(app, { name: 'name', options: [], kind: 'postgres', application: application, user: adminUserData.user }); + // encrypted data source options will create credentials + expect(await Credential.count()).toBe(1); - for(const userData of [adminUserData, developerUserData]) { - const newOptions = [ { key: 'email', value: userData.user.email } ] + for (const userData of [adminUserData, developerUserData]) { + const newOptions = [ + { key: 'email', value: userData.user.email }, + { key: 'foo', value: 'baz', encrypted: 'true' }, + ]; const response = await request(app.getHttpServer()) .put(`/data_sources/${dataSource.id}`) .set('Authorization', authHeaderForUser(userData.user)) .send({ - options: newOptions - }) + options: newOptions, + }); expect(response.statusCode).toBe(200); await dataSource.reload(); expect(dataSource.options['email']['value']).toBe(userData.user.email); } + // new credentials will not be created upon data source update + expect(await Credential.count()).toBe(1); + // Should not update if viewer or if user of another org - for(const userData of [anotherOrgAdminUserData, viewerUserData]) { + for (const userData of [anotherOrgAdminUserData, viewerUserData]) { + const newOptions = [ + { key: 'email', value: userData.user.email }, + { key: 'foo', value: 'baz', encrypted: 'true' }, + ]; const response = await request(app.getHttpServer()) .put(`/data_sources/${dataSource.id}`) .set('Authorization', authHeaderForUser(userData.user)) .send({ - options: [ ] - }) + options: newOptions, + }); expect(response.statusCode).toBe(403); } }); it('should be able to list (get) datasources for an app only if admin/developer of same organization', async () => { - const adminUserData = await createUser(app, { email: 'admin@tooljet.io', role: 'admin' }); - const developerUserData = await createUser(app, { email: 'developer@tooljet.io', role: 'developer', organization: adminUserData.organization }); - const viewerUserData = await createUser(app, { email: 'viewer@tooljet.io', role: 'viewer', organization: adminUserData.organization }); - const application = await createApplication(app, { name: 'name', user: adminUserData.user }); - const anotherOrgAdminUserData = await createUser(app, { email: 'another@tooljet.io', role: 'admin' }); - const dataSource = await createDataSource(app, { name: 'name', kind: 'postgres', application: application, user: adminUserData.user }); + const adminUserData = await createUser(app, { + email: 'admin@tooljet.io', + role: 'admin', + }); + const developerUserData = await createUser(app, { + email: 'developer@tooljet.io', + role: 'developer', + organization: adminUserData.organization, + }); + const viewerUserData = await createUser(app, { + email: 'viewer@tooljet.io', + role: 'viewer', + organization: adminUserData.organization, + }); + const application = await createApplication(app, { + name: 'name', + user: adminUserData.user, + }); + const anotherOrgAdminUserData = await createUser(app, { + email: 'another@tooljet.io', + role: 'admin', + }); + const dataSource = await createDataSource(app, { + name: 'name', + kind: 'postgres', + application: application, + user: adminUserData.user, + }); - for(const userData of [adminUserData, developerUserData, viewerUserData]) { + for (const userData of [adminUserData, developerUserData, viewerUserData]) { const response = await request(app.getHttpServer()) .get(`/data_sources?app_id=${application.id}`) - .set('Authorization', authHeaderForUser(userData.user)) + .set('Authorization', authHeaderForUser(userData.user)); expect(response.statusCode).toBe(200); expect(response.body.data_sources.length).toBe(1); @@ -104,28 +187,41 @@ describe('data sources controller', () => { // Forbidden if user of another organization const response = await request(app.getHttpServer()) - .get(`/data_sources?app_id=${application.id}`) - .set('Authorization', authHeaderForUser(anotherOrgAdminUserData.user)) + .get(`/data_sources?app_id=${application.id}`) + .set('Authorization', authHeaderForUser(anotherOrgAdminUserData.user)); - expect(response.statusCode).toBe(403); + expect(response.statusCode).toBe(403); }); it('should not be able to authorize OAuth code for a REST API source if user of another organization', async () => { - - const adminUserData = await createUser(app, { email: 'admin@tooljet.io', role: 'admin' }); - const anotherOrgAdminUserData = await createUser(app, { email: 'another@tooljet.io', role: 'admin' }); - const application = await createApplication(app, { name: 'name', user: adminUserData.user }); - const dataSource = await createDataSource(app, { name: 'name', options: [], kind: 'restapi', application: application, user: adminUserData.user }); + const adminUserData = await createUser(app, { + email: 'admin@tooljet.io', + role: 'admin', + }); + const anotherOrgAdminUserData = await createUser(app, { + email: 'another@tooljet.io', + role: 'admin', + }); + const application = await createApplication(app, { + name: 'name', + user: adminUserData.user, + }); + const dataSource = await createDataSource(app, { + name: 'name', + options: [], + kind: 'restapi', + application: application, + user: adminUserData.user, + }); // Should not update if user of another org const response = await request(app.getHttpServer()) .post(`/data_sources/${dataSource.id}/authorize_oauth2`) .set('Authorization', authHeaderForUser(anotherOrgAdminUserData.user)) .send({ - code: 'oauth-auth-code' - }) + code: 'oauth-auth-code', + }); expect(response.statusCode).toBe(403); }); - -}); \ No newline at end of file +}); diff --git a/server/test/test.helper.ts b/server/test/test.helper.ts index aae57e32bc..cfbe035014 100644 --- a/server/test/test.helper.ts +++ b/server/test/test.helper.ts @@ -1,4 +1,5 @@ import { JwtService } from '@nestjs/jwt'; +import { TypeOrmModule } from '@nestjs/typeorm'; import { ConfigService } from '@nestjs/config'; import { getConnection, Repository } from 'typeorm'; import { OrganizationUser } from 'src/entities/organization_user.entity'; @@ -12,14 +13,16 @@ import { AppUser } from 'src/entities/app_user.entity'; import { AppVersion } from 'src/entities/app_version.entity'; import { DataQuery } from 'src/entities/data_query.entity'; import { DataSource } from 'src/entities/data_source.entity'; +import { DataSourcesService } from 'src/services/data_sources.service'; +import { DataSourcesModule } from 'src/modules/data_sources/data_sources.module'; export async function createNestAppInstance() { let app: INestApplication; const moduleRef = await Test.createTestingModule({ imports: [AppModule], - }) - .compile(); + providers: [], + }).compile(); app = moduleRef.createNestApplication(); await app.init(); @@ -29,7 +32,9 @@ export async function createNestAppInstance() { export function authHeaderForUser(user: any) { const configService = new ConfigService(); - const jwtService = new JwtService({secret: configService.get('SECRET_KEY_BASE')}); + const jwtService = new JwtService({ + secret: configService.get('SECRET_KEY_BASE'), + }); const authPayload = { username: user.id, sub: user.email }; const authToken = jwtService.sign(authPayload); return `Bearer ${authToken}`; @@ -39,7 +44,9 @@ export async function clearDB() { const entities = getConnection().entityMetadatas; for (const entity of entities) { const repository = await getConnection().getRepository(entity.name); - await repository.query(`TRUNCATE ${entity.tableName} RESTART IDENTITY CASCADE;`); + await repository.query( + `TRUNCATE ${entity.tableName} RESTART IDENTITY CASCADE;`, + ); } } @@ -49,24 +56,28 @@ export async function createApplication(app, { name, user, isPublic }: any) { let appUsersRepository: Repository; appUsersRepository = app.get('AppUserRepository'); - user = user || await (await createUser(app, {})).user; + user = user || (await (await createUser(app, {})).user); - const newApp = await appRepository.save(appRepository.create({ - name, - user, - isPublic: isPublic || false, - organizationId: user.organization.id, - createdAt: new Date(), - updatedAt: new Date() - })); + const newApp = await appRepository.save( + appRepository.create({ + name, + user, + isPublic: isPublic || false, + organizationId: user.organization.id, + createdAt: new Date(), + updatedAt: new Date(), + }), + ); - await appUsersRepository.save(appUsersRepository.create({ - app: newApp, - user, - role: 'admin', - createdAt: new Date(), - updatedAt: new Date() - })); + await appUsersRepository.save( + appUsersRepository.create({ + app: newApp, + user, + role: 'admin', + createdAt: new Date(), + updatedAt: new Date(), + }), + ); return newApp; } @@ -75,13 +86,18 @@ export async function createApplicationVersion(app, application) { let appVersionsRepository: Repository; appVersionsRepository = app.get('AppVersionRepository'); - return await appVersionsRepository.save(appVersionsRepository.create({ - app: application, - name: 'v0' - })); + return await appVersionsRepository.save( + appVersionsRepository.create({ + app: application, + name: 'v0', + }), + ); } -export async function createUser(app, { firstName, lastName, email, role, organization }: any) { +export async function createUser( + app, + { firstName, lastName, email, role, organization }: any, +) { let userRepository: Repository; let organizationRepository: Repository; let organizationUsersRepository: Repository; @@ -90,59 +106,79 @@ export async function createUser(app, { firstName, lastName, email, role, organi organizationRepository = app.get('OrganizationRepository'); organizationUsersRepository = app.get('OrganizationUserRepository'); - organization = organization || await organizationRepository.save(organizationRepository.create({ - name: 'test org', - createdAt: new Date(), - updatedAt: new Date() - })); + organization = + organization || + (await organizationRepository.save( + organizationRepository.create({ + name: 'test org', + createdAt: new Date(), + updatedAt: new Date(), + }), + )); - const user = await userRepository.save(userRepository.create({ - firstName: firstName || 'test', - lastName: lastName || 'test', - email: email || 'dev@tooljet.io', - password: 'password', - organization, - createdAt: new Date(), - updatedAt: new Date(), - })); + const user = await userRepository.save( + userRepository.create({ + firstName: firstName || 'test', + lastName: lastName || 'test', + email: email || 'dev@tooljet.io', + password: 'password', + organization, + createdAt: new Date(), + updatedAt: new Date(), + }), + ); - const orgUser = await organizationUsersRepository.save(organizationUsersRepository.create({ - user: user, - organization, - role: role || 'admin', - createdAt: new Date(), - updatedAt: new Date() - })); + const orgUser = await organizationUsersRepository.save( + organizationUsersRepository.create({ + user: user, + organization, + role: role || 'admin', + createdAt: new Date(), + updatedAt: new Date(), + }), + ); - return { organization, user, orgUser } + return { organization, user, orgUser }; } -export async function createDataSource(nestInstance, { name, application, kind, options }: any) { +export async function createDataSource( + nestInstance, + { name, application, kind, options }: any, +) { let dataSourceRepository: Repository; dataSourceRepository = nestInstance.get('DataSourceRepository'); - return await dataSourceRepository.save(dataSourceRepository.create({ - name, - options, - app: application, - kind, - createdAt: new Date(), - updatedAt: new Date() - })); + const dataSourcesService = nestInstance + .select(DataSourcesModule) + .get(DataSourcesService); + + return await dataSourceRepository.save( + dataSourceRepository.create({ + name, + options: await dataSourcesService.parseOptionsForCreate(options), + app: application, + kind, + createdAt: new Date(), + updatedAt: new Date(), + }), + ); } - -export async function createDataQuery(nestInstance, { application, kind, dataSource, options }: any) { +export async function createDataQuery( + nestInstance, + { application, kind, dataSource, options }: any, +) { let dataQueryRepository: Repository; dataQueryRepository = nestInstance.get('DataQueryRepository'); - return await dataQueryRepository.save(dataQueryRepository.create({ - options, - app: application, - kind, - dataSource, - createdAt: new Date(), - updatedAt: new Date() - })); + return await dataQueryRepository.save( + dataQueryRepository.create({ + options, + app: application, + kind, + dataSource, + createdAt: new Date(), + updatedAt: new Date(), + }), + ); } - From c17b76e5ea0260aba9604a3b123164642036dbfa Mon Sep 17 00:00:00 2001 From: Sherfin Shamsudeen Date: Tue, 21 Sep 2021 16:52:39 +0530 Subject: [PATCH 03/69] Disable auto-reset in Table when its data is recomputed (#805) --- frontend/src/Editor/Components/Table/Table.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/Editor/Components/Table/Table.jsx b/frontend/src/Editor/Components/Table/Table.jsx index 0ff84693ee..e6b38a196f 100644 --- a/frontend/src/Editor/Components/Table/Table.jsx +++ b/frontend/src/Editor/Components/Table/Table.jsx @@ -593,6 +593,7 @@ export function Table({ exportData } = useTable( { + autoResetPage: false, columns, data, defaultColumn, From ab17ead153d7612889ddaee7cc31b6da4e631a86 Mon Sep 17 00:00:00 2001 From: Arpit Date: Tue, 21 Sep 2021 17:02:18 +0530 Subject: [PATCH 04/69] Bugfix: tags table-cell-type cannot be edited if its readOnly (#806) * tags and badges:table-cell-type cannot be edited if its readOnly * going backward for badge and badges type --- frontend/src/Editor/Components/Table/Table.jsx | 3 ++- frontend/src/Editor/Components/Table/Tags.jsx | 12 +++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/src/Editor/Components/Table/Table.jsx b/frontend/src/Editor/Components/Table/Table.jsx index e6b38a196f..1ccff3757a 100644 --- a/frontend/src/Editor/Components/Table/Table.jsx +++ b/frontend/src/Editor/Components/Table/Table.jsx @@ -266,7 +266,7 @@ export function Table({ if (Array.isArray(labels)) { columnOptions.selectOptions = labels.map((label, index) => { - return { name: label, value: values[index] }; + return { name: label, value: values[index]}; }); } } @@ -432,6 +432,7 @@ export function Table({ return (
{ handleCellValueChange(cell.row.index, column.key || column.name, value, cell.row.original); diff --git a/frontend/src/Editor/Components/Table/Tags.jsx b/frontend/src/Editor/Components/Table/Tags.jsx index ff99ca723b..aacbfea90f 100644 --- a/frontend/src/Editor/Components/Table/Tags.jsx +++ b/frontend/src/Editor/Components/Table/Tags.jsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; -export const Tags = ({ value, onChange }) => { +export const Tags = ({ value, onChange, readOnly }) => { value = value || []; @@ -30,9 +30,11 @@ export const Tags = ({ value, onChange }) => { function renderTag(text) { return {text} - removeTag(text)}> - x - + {!readOnly && ( + removeTag(text)}> + x + + )} ; } @@ -42,7 +44,7 @@ export const Tags = ({ value, onChange }) => { return renderTag(item) })} - {!showForm && + {(!showForm && !readOnly) && setShowForm(true)}>{'+'} } From 4dc356cb3626339b2a68f229a600ffe1b6418839 Mon Sep 17 00:00:00 2001 From: Arpit Date: Tue, 21 Sep 2021 17:20:29 +0530 Subject: [PATCH 05/69] Parameter to accept a specific range within a Googlesheet (#798) * Parameter to accept a specific range within a googlesheet * default range: A1:Z500 --- .../QueryManager/QueryEditors/Googlesheets.jsx | 16 ++++++++++++++++ server/plugins/datasources/googlesheets/index.ts | 5 +++-- .../datasources/googlesheets/operations.ts | 3 ++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/frontend/src/Editor/QueryManager/QueryEditors/Googlesheets.jsx b/frontend/src/Editor/QueryManager/QueryEditors/Googlesheets.jsx index a95fbd3d34..522b1815db 100644 --- a/frontend/src/Editor/QueryManager/QueryEditors/Googlesheets.jsx +++ b/frontend/src/Editor/QueryManager/QueryEditors/Googlesheets.jsx @@ -86,6 +86,20 @@ class Googlesheets extends React.Component { className="form-control" />
+ {['read'].includes(this.state.options.operation) && ( +
+ + { + changeOption(this, 'spreadsheet_range', e.target.value); + }} + className="form-control" + /> +
+ ) }
)} + + {this.state.options.operation === 'append' && (
diff --git a/server/plugins/datasources/googlesheets/index.ts b/server/plugins/datasources/googlesheets/index.ts index 2aa10d4101..670d171b23 100644 --- a/server/plugins/datasources/googlesheets/index.ts +++ b/server/plugins/datasources/googlesheets/index.ts @@ -71,6 +71,7 @@ export default class GooglesheetsQueryService implements QueryService { let response = null; const operation = queryOptions.operation; const spreadsheetId = queryOptions['spreadsheet_id']; + const spreadsheetRange = queryOptions['spreadsheet_range'] ? queryOptions['spreadsheet_range'] : 'A1:Z500' ; const accessToken = sourceOptions['access_token']; try { @@ -84,8 +85,8 @@ export default class GooglesheetsQueryService implements QueryService { result = JSON.parse(response.body); break; - case 'read': - result = await readData(spreadsheetId, queryOptions['sheet'], this.authHeader(accessToken)); + case 'read': + result = await readData(spreadsheetId, spreadsheetRange, queryOptions['sheet'], this.authHeader(accessToken)); break; case 'append': diff --git a/server/plugins/datasources/googlesheets/operations.ts b/server/plugins/datasources/googlesheets/operations.ts index 5334b017fd..c8ce9fa648 100644 --- a/server/plugins/datasources/googlesheets/operations.ts +++ b/server/plugins/datasources/googlesheets/operations.ts @@ -141,10 +141,11 @@ async function deleteDataFromSheet( export async function readData( spreadSheetId: string, + spreadsheetRange:string, sheet: string, authHeader: any, ): Promise { - return await readDataFromSheet(spreadSheetId, sheet, 'A1:Z500', authHeader); + return await readDataFromSheet(spreadSheetId, sheet, spreadsheetRange, authHeader); } export async function appendData( From eb73c9cd5b14c4f7906580b4120c383b0fcb2876 Mon Sep 17 00:00:00 2001 From: Akhil G Krishnan Date: Tue, 21 Sep 2021 17:30:14 +0530 Subject: [PATCH 06/69] Fix for broken pin icon of popovers in dark mode (#802) * Fix: Pin icon white stroke showing in dark theme * Secondary outline color added for pin button. --- frontend/src/Editor/LeftSidebar/SidebarPinnedButton.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Editor/LeftSidebar/SidebarPinnedButton.jsx b/frontend/src/Editor/LeftSidebar/SidebarPinnedButton.jsx index a92c963aa5..a69fd14871 100644 --- a/frontend/src/Editor/LeftSidebar/SidebarPinnedButton.jsx +++ b/frontend/src/Editor/LeftSidebar/SidebarPinnedButton.jsx @@ -7,7 +7,7 @@ export const SidebarPinnedButton = ({ state, component, updateState }) => { const tooltipMsg = state ? `Unpin ${component}` : `Pin ${component}` return ( -
+
From 40005146c4aa2ee34d3bd2a9de72c3fd9230ad60 Mon Sep 17 00:00:00 2001 From: Akshay Date: Tue, 21 Sep 2021 17:36:21 +0530 Subject: [PATCH 07/69] Fix role change when only one admin is present (#766) --- .../services/organization_users.service.ts | 102 ++++++++++++------ .../organization_users.e2e-spec.ts | 17 +++ server/test/test.helper.ts | 4 +- 3 files changed, 92 insertions(+), 31 deletions(-) diff --git a/server/src/services/organization_users.service.ts b/server/src/services/organization_users.service.ts index 50528ee55c..1310c782b1 100644 --- a/server/src/services/organization_users.service.ts +++ b/server/src/services/organization_users.service.ts @@ -10,69 +10,111 @@ import { EmailService } from './email.service'; @Injectable() export class OrganizationUsersService { - constructor( @InjectRepository(OrganizationUser) private organizationUsersRepository: Repository, private usersService: UsersService, private emailService: EmailService, - ) { } + ) {} async findOne(id: string): Promise { return await this.organizationUsersRepository.findOne({ id: id }); } - async inviteNewUser(currentUser: User, params: any): Promise { - - const userParams = { + async inviteNewUser( + currentUser: User, + params: any, + ): Promise { + const userParams = { firstName: params['first_name'], lastName: params['last_name'], - email: params['email'] - } + email: params['email'], + }; - const user = await this.usersService.create(userParams, currentUser.organization); - const organizationUser = await this.create(user, currentUser.organization, params.role); + const user = await this.usersService.create( + userParams, + currentUser.organization, + ); + const organizationUser = await this.create( + user, + currentUser.organization, + params.role, + ); - this.emailService.sendOrganizationUserWelcomeEmail(user.email, user.firstName, currentUser.firstName, user.invitationToken); + this.emailService.sendOrganizationUserWelcomeEmail( + user.email, + user.firstName, + currentUser.firstName, + user.invitationToken, + ); return organizationUser; } - async create(user: User, organization: Organization, role: string): Promise { - return await this.organizationUsersRepository.save(this.organizationUsersRepository.create({ - user, - organization, - role, - createdAt: new Date(), - updatedAt: new Date(), - })); + async create( + user: User, + organization: Organization, + role: string, + ): Promise { + return await this.organizationUsersRepository.save( + this.organizationUsersRepository.create({ + user, + organization, + role, + createdAt: new Date(), + updatedAt: new Date(), + }), + ); } async changeRole(user: User, id: string, role: string) { const organizationUser = await this.organizationUsersRepository.findOne(id); + if (organizationUser.role == 'admin') { + const lastActiveAdmin = await this.lastActiveAdmin( + organizationUser.organizationId, + ); + + if (lastActiveAdmin) { + throw new BadRequestException( + 'Atleast one active admin is required.', + ); + } + } return await this.organizationUsersRepository.update(id, { role }); } async archive(id: string) { - const organizationUser = await this.organizationUsersRepository.findOne(id); - if(organizationUser.role === 'admin') { - // Check if this is the last admin of the org - const adminsCount = await this.organizationUsersRepository.count({ - where: { - organizationId: organizationUser.organizationId, - role: 'admin', - status: 'active' - } - }); + if (organizationUser.role === 'admin') { + const lastActiveAdmin = await this.lastActiveAdmin( + organizationUser.organizationId, + ); - if(adminsCount === 1) { - throw new BadRequestException('You cannot archive this user as there are no other active admin users.'); + if (lastActiveAdmin) { + throw new BadRequestException( + 'You cannot archive this user as there are no other active admin users.', + ); } } await this.organizationUsersRepository.update(id, { status: 'archived' }); return true; } + + async lastActiveAdmin(organizationId: string): Promise { + const adminsCount = await this.activeAdminCount(organizationId); + + return adminsCount <= 1; + } + + async activeAdminCount(organizationId: string) { + return await this.organizationUsersRepository.count({ + where: { + organizationId: organizationId, + role: 'admin', + status: 'active', + }, + }); + } } diff --git a/server/test/controllers/organization_users.e2e-spec.ts b/server/test/controllers/organization_users.e2e-spec.ts index 56347d4f50..15f8cb651c 100644 --- a/server/test/controllers/organization_users.e2e-spec.ts +++ b/server/test/controllers/organization_users.e2e-spec.ts @@ -174,6 +174,23 @@ describe('organization users controller', () => { expect(developerUserData.orgUser.role).toBe('developer'); }); + it('should not allow to change role from admin when no other admins are present', async () => { + const adminUserData = await createUser(app, { + email: 'admin@tooljet.io', + role: 'admin', + status: 'active', + }); + + const response = await request(app.getHttpServer()) + .post(`/organization_users/${adminUserData.orgUser.id}/change_role`) + .set('Authorization', authHeaderForUser(adminUserData.user)) + .send({ role: 'viewer' }) + .expect(400); + + await adminUserData.orgUser.reload(); + expect(adminUserData.orgUser.role).toBe('admin'); + }); + it('should allow only admin users to archive org users', async () => { const adminUserData = await createUser(app, { email: 'admin@tooljet.io', diff --git a/server/test/test.helper.ts b/server/test/test.helper.ts index cfbe035014..5931c52927 100644 --- a/server/test/test.helper.ts +++ b/server/test/test.helper.ts @@ -94,9 +94,10 @@ export async function createApplicationVersion(app, application) { ); } + export async function createUser( app, - { firstName, lastName, email, role, organization }: any, + { firstName, lastName, email, role, organization, status }: any, ) { let userRepository: Repository; let organizationRepository: Repository; @@ -133,6 +134,7 @@ export async function createUser( user: user, organization, role: role || 'admin', + status: status || 'invited', createdAt: new Date(), updatedAt: new Date(), }), From 26c9cc655c9774936e1007c07263cac89cdf181d Mon Sep 17 00:00:00 2001 From: Arpit Date: Tue, 21 Sep 2021 19:18:28 +0530 Subject: [PATCH 08/69] Fix linting errors across the app (#785) * eslint-setup: rules for frontend and server * setup pre-commit:hook * frontend:eslint fixes * frontend eslint errors and warning fixed * eslint:fix for ./server * fix server/test: expectatin string lint/error * pre-commit:updated * removed unwanted install cmd from docker file * recommended settings and extension for vscode * husky prepare script added * updated extension recommendations * added prettier as recommended extension * added pre-commit to package.json * remove .prettierrc file * resolve changes * resolve changes --- .prettierignore | 2 - .prettierrc | 8 - .vscode/extension.json | 11 + .vscode/settings.json | 14 + docker/client.Dockerfile.dev | 1 + frontend/.eslintrc.js | 37 - frontend/.eslintrc.json | 56 + frontend/cypress/plugins/index.js | 14 +- frontend/cypress/support/index.js | 2 +- frontend/package-lock.json | 2291 ++++++++++++++++- frontend/package.json | 13 +- frontend/src/App/App.jsx | 105 +- frontend/src/Editor/ActionTypes.js | 30 +- frontend/src/Editor/Box.jsx | 93 +- frontend/src/Editor/BoxDragPreview.jsx | 13 +- .../src/Editor/CodeBuilder/CodeBuilder.jsx | 6 +- .../src/Editor/CodeBuilder/CodeHinter.jsx | 2 + .../Editor/CodeBuilder/CodeHinter.spec.jsx | 54 +- frontend/src/Editor/CodeBuilder/utils.js | 46 +- frontend/src/Editor/Components/Button.jsx | 23 +- frontend/src/Editor/Components/Chart.jsx | 95 +- frontend/src/Editor/Components/Checkbox.jsx | 26 +- frontend/src/Editor/Components/Container.jsx | 35 +- frontend/src/Editor/Components/Datepicker.jsx | 58 +- .../src/Editor/Components/DaterangePicker.jsx | 20 +- .../src/Editor/Components/DraftEditor.jsx | 1 + frontend/src/Editor/Components/DropDown.jsx | 50 +- frontend/src/Editor/Components/Image.jsx | 28 +- frontend/src/Editor/Components/Map/Map.jsx | 9 +- frontend/src/Editor/Components/Map/styles.js | 272 +- frontend/src/Editor/Components/Modal.jsx | 47 +- .../src/Editor/Components/Multiselect.jsx | 26 +- .../src/Editor/Components/NumberInput.jsx | 20 +- .../Components/QrScanner/ErrorModal.jsx | 57 +- .../Editor/Components/QrScanner/QrScanner.jsx | 28 +- .../src/Editor/Components/RadioButton.jsx | 64 +- .../src/Editor/Components/RichTextEditor.jsx | 31 +- .../Components/StarRating/icons/half-star.js | 73 +- .../StarRating/icons/star-outline.js | 73 +- .../Components/StarRating/icons/star.js | 73 +- .../src/Editor/Components/StarRating/index.js | 23 +- .../src/Editor/Components/StarRating/star.js | 1 + .../Editor/Components/Table/CustomSelect.jsx | 45 +- .../Editor/Components/Table/Datepicker.jsx | 124 +- .../Editor/Components/Table/Pagination.jsx | 86 +- .../src/Editor/Components/Table/Radio.jsx | 26 +- .../src/Editor/Components/Table/Table.jsx | 381 +-- frontend/src/Editor/Components/Table/Tags.jsx | 107 +- .../src/Editor/Components/Table/Toggle.jsx | 32 +- frontend/src/Editor/Components/Text.jsx | 27 +- frontend/src/Editor/Components/TextArea.jsx | 22 +- frontend/src/Editor/Components/TextInput.jsx | 1 + frontend/src/Editor/Components/components.js | 207 +- frontend/src/Editor/ConfigHandle.jsx | 66 +- frontend/src/Editor/Container.jsx | 182 +- frontend/src/Editor/CustomDragLayer.jsx | 29 +- .../DataSourceManager/DataSourceManager.jsx | 6 +- .../DataSourceManager/DataSourceTypes.js | 93 +- .../DataSourceManager/DefaultOptions.js | 32 +- .../SourceComponents/Mysql.jsx | 17 +- .../SourceComponents/index.js | 2 +- .../DataSourceManager/TestConnection.jsx | 5 +- frontend/src/Editor/DraggableBox.jsx | 7 +- frontend/src/Editor/Editor.jsx | 50 +- .../ActionConfigurationPanels/GotoApp.jsx | 106 +- .../src/Editor/Inspector/Components/Chart.jsx | 79 +- .../src/Editor/Inspector/Components/Table.jsx | 370 ++- .../src/Editor/Inspector/Elements/Code.jsx | 12 +- .../src/Editor/Inspector/Elements/Color.jsx | 18 +- .../Inspector/Elements/Components/ToolTip.jsx | 39 +- .../src/Editor/Inspector/Elements/Json.jsx | 10 +- .../src/Editor/Inspector/Elements/Select.jsx | 9 +- .../src/Editor/Inspector/Elements/Text.jsx | 12 +- .../src/Editor/Inspector/Elements/Toggle.jsx | 22 +- .../src/Editor/Inspector/EventManager.jsx | 343 ++- frontend/src/Editor/Inspector/Inspector.jsx | 200 +- .../src/Editor/Inspector/QuerySelector.jsx | 19 +- frontend/src/Editor/Inspector/TypeMapping.js | 2 +- frontend/src/Editor/ItemTypes.js | 2 +- .../Editor/LeftSidebar/SidebarDebugger.jsx | 360 +-- .../LeftSidebar/SidebarPinnedButton.jsx | 58 +- .../Editor/LeftSidebar/sidebar-datasources.js | 1 - .../Editor/LeftSidebar/sidebar-inspector.js | 19 +- .../src/Editor/LeftSidebar/sidebar-item.js | 40 +- .../src/Editor/LeftSidebar/sidebar-zoom.js | 65 +- frontend/src/Editor/ManageAppUsers.jsx | 151 +- .../QueryManager/QueryEditors/Airtable.jsx | 10 +- .../QueryManager/QueryEditors/Dynamodb.jsx | 34 +- .../QueryEditors/Elasticsearch.jsx | 16 +- .../QueryManager/QueryEditors/Firestore.jsx | 43 +- .../QueryEditors/Googlesheets.jsx | 90 +- .../QueryManager/QueryEditors/Graphql.jsx | 2 +- .../QueryManager/QueryEditors/Mongodb.jsx | 12 +- .../QueryManager/QueryEditors/Mssql.jsx | 2 +- .../QueryManager/QueryEditors/Mysql.jsx | 16 +- .../QueryManager/QueryEditors/Postgresql.jsx | 18 +- .../QueryManager/QueryEditors/Redis.jsx | 6 +- .../QueryEditors/Restapi/index.jsx | 14 +- .../QueryManager/QueryEditors/Slack.jsx | 48 +- .../QueryManager/QueryEditors/Stripe.jsx | 57 +- .../Editor/QueryManager/QueryEditors/index.js | 2 +- .../QueryManager/QueryEditors/placeholders.js | 11 +- .../Editor/QueryManager/QueryEditors/utils.js | 7 +- .../src/Editor/QueryManager/QueryManager.jsx | 4 +- .../Editor/QueryManager/Transformation.jsx | 37 +- frontend/src/Editor/QueryManager/constants.js | 30 +- frontend/src/Editor/SaveAndPreview.jsx | 44 +- frontend/src/Editor/SubContainer.jsx | 122 +- frontend/src/Editor/SubCustomDragLayer.jsx | 28 +- frontend/src/Editor/Viewer.jsx | 132 +- frontend/src/Editor/Viewer/Confirm.jsx | 4 +- frontend/src/Editor/WidgetManager.jsx | 8 +- frontend/src/Editor/index.js | 1 + frontend/src/HomePage/AppMenu.jsx | 1 - frontend/src/HomePage/BlankPage.jsx | 66 +- frontend/src/HomePage/Folders.jsx | 153 +- frontend/src/HomePage/HomePage.jsx | 419 +-- .../src/InvitationPage/InvitationPage.jsx | 18 +- frontend/src/LoginPage/LoginPage.jsx | 18 +- .../src/ManageOrgUsers/ManageOrgUsers.jsx | 5 +- frontend/src/Oauth2/Authorize.jsx | 4 +- frontend/src/Onboarding/OnboardingModal.jsx | 50 +- frontend/src/SettingsPage/SettingsPage.jsx | 157 +- frontend/src/SignupPage/SignupPage.jsx | 17 +- frontend/src/_components/ConfirmDialog.jsx | 11 +- frontend/src/_components/DarkModeToggle.jsx | 8 +- frontend/src/_components/DynamicForm.jsx | 2 +- frontend/src/_components/Googlesheets.jsx | 2 +- frontend/src/_components/Header.jsx | 127 +- frontend/src/_components/Pagination.jsx | 51 +- frontend/src/_components/PrivateRoute.jsx | 13 +- frontend/src/_components/Slack.jsx | 19 +- frontend/src/_helpers/appUtils.js | 452 ++-- frontend/src/_helpers/auth-header.js | 4 +- frontend/src/_helpers/handle-response.js | 4 +- frontend/src/_helpers/utils.js | 2 + frontend/src/_hooks/use-height-transition.jsx | 1 + frontend/src/_hooks/use-popover.jsx | 9 +- frontend/src/_hooks/use-router.jsx | 7 +- frontend/src/_hooks/usePinnedPopover.jsx | 29 +- frontend/src/_services/app.service.js | 19 +- frontend/src/_services/appVersion.service.js | 6 +- .../src/_services/authentication.service.js | 21 +- frontend/src/_services/dataquery.service.js | 10 +- frontend/src/_services/datasource.service.js | 8 +- frontend/src/_services/folder.service.js | 6 +- frontend/src/_services/index.js | 1 - frontend/src/_services/openapi.service.js | 2 +- .../src/_services/organization.service.js | 4 +- .../_services/organization_user.service.js | 6 +- frontend/src/_services/tooljet.service.js | 18 +- frontend/src/_services/user.service.js | 6 +- frontend/src/_ui/Button/index.js | 8 +- frontend/src/_ui/Input/index.js | 2 +- frontend/src/_ui/OAuth/Authentication.jsx | 2 +- frontend/src/_ui/Toggle/index.js | 2 +- frontend/src/index.jsx | 4 +- frontend/webpack.config.js | 11 +- package-lock.json | 26 +- package.json | 16 +- server/.eslintignore | 2 + server/.eslintrc.js | 54 +- server/.prettierrc | 4 - server/ormconfig.ts | 48 +- server/package-lock.json | 314 ++- server/package.json | 14 +- server/plugins/datasources/airtable/index.ts | 73 +- server/plugins/datasources/dynamodb/index.ts | 26 +- .../datasources/dynamodb/operations.ts | 18 +- .../datasources/elasticsearch/index.ts | 18 +- .../datasources/elasticsearch/operations.ts | 19 +- server/plugins/datasources/firestore/index.ts | 47 +- .../datasources/firestore/operations.ts | 34 +- .../plugins/datasources/googlesheets/index.ts | 49 +- .../datasources/googlesheets/operations.ts | 88 +- server/plugins/datasources/graphql/index.ts | 26 +- .../plugins/datasources/graphql/test.spec.ts | 12 +- server/plugins/datasources/mongodb/index.ts | 31 +- server/plugins/datasources/mssql/index.ts | 49 +- .../datasources/mysql/index.service.spec.ts | 35 +- server/plugins/datasources/mysql/index.ts | 55 +- .../postgresql/index.service.spec.ts | 37 +- .../plugins/datasources/postgresql/index.ts | 56 +- server/plugins/datasources/redis/index.ts | 17 +- server/plugins/datasources/restapi/index.ts | 86 +- server/plugins/datasources/slack/index.ts | 53 +- server/plugins/datasources/stripe/index.ts | 29 +- server/scripts/create-database.ts | 10 +- server/scripts/drop-database.ts | 10 +- server/src/app.module.ts | 14 +- server/src/controllers/app.controller.ts | 8 +- .../src/controllers/app_config.controller.ts | 3 +- .../src/controllers/app_users.controller.ts | 10 +- server/src/controllers/apps.controller.ts | 74 +- .../controllers/data_queries.controller.ts | 53 +- .../controllers/data_sources.controller.ts | 17 +- .../src/controllers/folder_apps.controller.ts | 7 +- server/src/controllers/folders.controller.ts | 8 +- server/src/controllers/metadata.controller.ts | 23 +- .../organization_users.controller.ts | 7 +- .../controllers/organizations.controller.ts | 8 +- server/src/controllers/users.controller.ts | 12 +- server/src/entities/app.entity.ts | 35 +- server/src/entities/app_user.entity.ts | 33 +- server/src/entities/app_version.entity.ts | 29 +- server/src/entities/credential.entity.ts | 9 +- server/src/entities/data_query.entity.ts | 45 +- server/src/entities/data_source.entity.ts | 37 +- server/src/entities/folder.entity.ts | 30 +- server/src/entities/folder_app.entity.ts | 34 +- server/src/entities/metadata.entity.ts | 13 +- server/src/entities/organization.entity.ts | 10 +- .../src/entities/organization_user.entity.ts | 39 +- server/src/entities/user.entity.ts | 37 +- server/src/helpers/utils.helper.ts | 9 +- server/src/interceptors/sentry.interceptor.ts | 15 +- server/src/main.ts | 21 +- .../modules/app_config/app_config.module.ts | 4 +- server/src/modules/apps/apps.module.ts | 8 +- server/src/modules/auth/app-auth.guard.ts | 17 +- server/src/modules/auth/auth.module.ts | 12 +- .../modules/auth/password-revalidate.guard.ts | 21 +- server/src/modules/auth/query-auth.guard.ts | 18 +- .../casl/abilities/apps-ability.factory.ts | 19 +- .../src/modules/casl/casl-ability.factory.ts | 20 +- server/src/modules/casl/casl.module.ts | 5 +- .../modules/casl/check_policies.decorator.ts | 3 +- server/src/modules/casl/policies.guard.ts | 17 +- .../data_queries/data_queries.module.ts | 10 +- .../connection_test_result.type.ts | 8 +- .../data_sources/data_sources.module.ts | 10 +- server/src/modules/data_sources/plugins.ts | 13 +- .../modules/data_sources/query_result.type.ts | 8 +- .../data_sources/query_service.interface.ts | 15 +- server/src/modules/meta/meta.module.ts | 1 - .../organizations/organizations.module.ts | 2 +- server/src/services/app_clone.service.ts | 11 +- server/src/services/app_config.service.ts | 17 +- server/src/services/app_users.service.ts | 25 +- server/src/services/apps.service.ts | 22 +- server/src/services/auth.service.ts | 21 +- server/src/services/credentials.service.ts | 17 +- .../src/services/data_queries.service.spec.ts | 43 +- server/src/services/data_queries.service.ts | 83 +- server/src/services/data_sources.service.ts | 53 +- server/src/services/email.service.ts | 25 +- .../src/services/encryption.service.spec.ts | 3 +- server/src/services/encryption.service.ts | 17 +- server/src/services/folder_apps.service.ts | 6 +- server/src/services/folders.service.ts | 62 +- server/src/services/metadata.service.ts | 53 +- .../services/organization_users.service.ts | 47 +- server/src/services/organizations.service.ts | 33 +- server/src/services/users.service.ts | 56 +- server/test/controllers/app.e2e-spec.ts | 17 +- server/test/controllers/app_users.e2e-spec.ts | 57 +- server/test/controllers/apps.e2e-spec.ts | 43 +- .../test/controllers/data_queries.e2e-spec.ts | 192 +- .../test/controllers/data_sources.e2e-spec.ts | 1 + .../organization_users.e2e-spec.ts | 12 +- .../controllers/organizations.e2e-spec.ts | 21 +- server/test/controllers/users.e2e-spec.ts | 36 +- server/test/test.helper.ts | 42 +- 263 files changed, 7822 insertions(+), 5398 deletions(-) delete mode 100644 .prettierignore delete mode 100644 .prettierrc create mode 100644 .vscode/extension.json create mode 100644 .vscode/settings.json delete mode 100644 frontend/.eslintrc.js create mode 100644 frontend/.eslintrc.json create mode 100644 server/.eslintignore delete mode 100644 server/.prettierrc diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 1658ad576a..0000000000 --- a/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -frontend/node_modules/** -# **/*.js \ No newline at end of file diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 28907f42d8..0000000000 --- a/.prettierrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "semi": true, - "trailingComma": "es5", - "printWidth": 120, - "singleQuote": true, - "arrowParens": "always", - "proseWrap": "preserve" -} \ No newline at end of file diff --git a/.vscode/extension.json b/.vscode/extension.json new file mode 100644 index 0000000000..fbddc72229 --- /dev/null +++ b/.vscode/extension.json @@ -0,0 +1,11 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "CoenraadS.bracket-pair-colorizer", + "mgmcdermott.vscode-language-babel", + "formulahendry.auto-rename-tag", + "xabikos.javascriptsnippets", + "streetsidesoftware.code-spell-checker", + "esbenp.prettier-vscode" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..8e9ce74d63 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "[javascript, typescript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint", + }, + "eslint.validate": [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact" + ], + "eslint.format.enable": true, + "editor.formatOnSave": true, + +} \ No newline at end of file diff --git a/docker/client.Dockerfile.dev b/docker/client.Dockerfile.dev index d86a2f8895..e1c90d3efd 100644 --- a/docker/client.Dockerfile.dev +++ b/docker/client.Dockerfile.dev @@ -12,6 +12,7 @@ ENV PATH /app/node_modules/.bin:$PATH # Fix for heap limit allocation issue ENV NODE_OPTIONS="--max-old-space-size=2048" + # install app dependencies COPY package.json package-lock.json ./ RUN npm install diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js deleted file mode 100644 index 45c9767f46..0000000000 --- a/frontend/.eslintrc.js +++ /dev/null @@ -1,37 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true - }, - - parser: 'babel-eslint', - - parserOptions: { - ecmaFeatures: { - jsx: true - }, - ecmaVersion: 12, - sourceType: 'module' - }, - extends: [ - 'plugin:react/recommended', - 'prettier', - 'airbnb-base/legacy' - ], - plugins: ['html', 'react', 'prettier', 'babel'], - rules: { - "react/prop-types": 0, - "no-underscore-dangle": ["error", { "allow": ["_self"] }], - "max-len": 0, - "no-bitwise": 0, - "no-use-before-define": ["error", { "variables": false, "functions": false }], - "no-nested-ternary": 0, - "no-loop-func": 0, - - }, - settings: { - react: { - version: "detect" - } - } -}; diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json new file mode 100644 index 0000000000..b705cb1a22 --- /dev/null +++ b/frontend/.eslintrc.json @@ -0,0 +1,56 @@ +{ + "env": { + "browser": true, + "amd": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "plugin:import/errors", + "plugin:import/warnings", + "plugin:prettier/recommended", + "plugin:cypress/recommended" + ], + "parser": "babel-eslint", + "parserOptions": { + "ecmaFeatures": { + "jsx": true + }, + "ecmaVersion": 12, + "sourceType": "module" + }, + "plugins": ["react", "prettier"], + "rules": { + "prettier/prettier": [ + "error", + { + "semi": true, + "trailingComma": "es5", + "printWidth": 120, + "singleQuote": true, + "arrowParens": "always", + "proseWrap": "preserve" + } + ], + "react/prop-types": 0, + "react/display-name": "off", + "no-unused-vars": [2, { "args": "after-used", "argsIgnorePattern": "reject" }], + "react/no-deprecated": 0, + "no-prototype-builtins": 0 + }, + "settings": { + "react": { + "version": "detect" + }, + "import/resolver": "webpack" + }, + "globals": { + "fetch": true, + "process": true, + "module": true, + "__dirname": true + } +} + \ No newline at end of file diff --git a/frontend/cypress/plugins/index.js b/frontend/cypress/plugins/index.js index be566ad6d6..97409954b9 100644 --- a/frontend/cypress/plugins/index.js +++ b/frontend/cypress/plugins/index.js @@ -1,16 +1,12 @@ -const webpackPreprocessor = require('@cypress/webpack-preprocessor') - module.exports = (on, config) => { if (config.testingType === 'component') { - const { startDevServer } = require('@cypress/webpack-dev-server') + const { startDevServer } = require('@cypress/webpack-dev-server'); // Your project's Webpack configuration - const webpackConfig = require('../../webpack.config.js') + const webpackConfig = require('../../webpack.config.js'); - on('dev-server:start', (options) => - startDevServer({ options, webpackConfig }) - ) + on('dev-server:start', (options) => startDevServer({ options, webpackConfig })); } - return config -} \ No newline at end of file + return config; +}; diff --git a/frontend/cypress/support/index.js b/frontend/cypress/support/index.js index d68db96df2..37a498fb5b 100644 --- a/frontend/cypress/support/index.js +++ b/frontend/cypress/support/index.js @@ -14,7 +14,7 @@ // *********************************************************** // Import commands.js using ES2015 syntax: -import './commands' +import './commands'; // Alternatively you can use CommonJS syntax: // require('./commands') diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 851413fd15..efc7f8f44e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -5,7 +5,6 @@ "requires": true, "packages": { "": { - "name": "frontend", "version": "0.1.0", "dependencies": { "@babel/core": "^7.4.3", @@ -22,6 +21,7 @@ "array-move": "^3.0.1", "babel-loader": "^8.0.5", "babel-plugin-console-source": "^2.0.5", + "babel-plugin-import": "^1.13.3", "bootstrap": "^4.6.0", "dompurify": "^2.2.7", "draft-js": "^0.11.7", @@ -74,9 +74,17 @@ "@cypress/webpack-dev-server": "^1.3.1", "@cypress/webpack-preprocessor": "^5.9.0", "@svgr/webpack": "^5.5.0", - "babel-plugin-import": "^1.13.3", "cypress": "^7.4.0", + "eslint": "^7.32.0", + "eslint-config-prettier": "^8.3.0", + "eslint-import-resolver-webpack": "^0.13.1", + "eslint-plugin-cypress": "^2.12.1", + "eslint-plugin-import": "^2.24.2", + "eslint-plugin-prettier": "^3.4.1", + "eslint-plugin-react": "^7.25.2", + "eslint-plugin-react-hooks": "^4.2.0", "path": "^0.12.7", + "prettier": "^2.3.2", "webpack": "^4.29.6", "webpack-dev-server": "^3.11.2" } @@ -1968,6 +1976,73 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@googlemaps/js-api-loader": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.11.1.tgz", @@ -2015,6 +2090,24 @@ "@hapi/hoek": "^8.3.0" } }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==" + }, "node_modules/@icons/material": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", @@ -3331,6 +3424,11 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==" }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" + }, "node_modules/@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", @@ -4244,6 +4342,12 @@ "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" }, + "node_modules/array-find": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz", + "integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=", + "dev": true + }, "node_modules/array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -4341,6 +4445,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.flatmap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", + "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -4669,7 +4790,6 @@ "version": "1.13.3", "resolved": "https://registry.npmjs.org/babel-plugin-import/-/babel-plugin-import-1.13.3.tgz", "integrity": "sha512-1qCWdljJOrDRH/ybaCZuDgySii4yYrtQ8OJQwrcDqdt0y67N30ng3X3nABg6j7gR7qUJgcMa9OMhc4AGViDwWw==", - "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.0.0", "@babel/runtime": "^7.0.0" @@ -8059,6 +8179,25 @@ "node": ">=4.3.0 <5.0.0 || >=5.10" } }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/enquirer/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "engines": { + "node": ">=6" + } + }, "node_modules/entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", @@ -8099,26 +8238,28 @@ } }, "node_modules/es-abstract": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", - "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", + "version": "1.18.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.6.tgz", + "integrity": "sha512-kAeIT4cku5eNLNuUKhlmtuk1/TRZvQoYccn6TO0cSVdf1kzB0T7+dYuVK9MWM7l+/53W2Q8M7N2c6MQvhXFcUQ==", "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.2", - "is-string": "^1.0.5", - "object-inspect": "^1.9.0", + "is-regex": "^1.1.4", + "is-string": "^1.0.7", + "object-inspect": "^1.11.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", "string.prototype.trimend": "^1.0.4", "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.0" + "unbox-primitive": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -8214,6 +8355,74 @@ "source-map": "~0.6.1" } }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-config-react-app": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz", @@ -8234,26 +8443,85 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", "dependencies": { - "debug": "^2.6.9", - "resolve": "^1.13.1" + "debug": "^3.2.7", + "resolve": "^1.20.0" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, - "node_modules/eslint-import-resolver-node/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "node_modules/eslint-import-resolver-webpack": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.1.tgz", + "integrity": "sha512-O/8mG6AHmaKYSMb4lWxiXPpaARxOJ4rMQEHJ8vTgjS1MXooJA3KPgBPPAdOPoV17v5ML5120qod5FBLM+DtgEw==", + "dev": true, + "dependencies": { + "array-find": "^1.0.0", + "debug": "^3.2.7", + "enhanced-resolve": "^0.9.1", + "find-root": "^1.1.0", + "has": "^1.0.3", + "interpret": "^1.4.0", + "is-core-module": "^2.4.0", + "is-regex": "^1.1.3", + "lodash": "^4.17.21", + "resolve": "^1.20.0", + "semver": "^5.7.1" + }, + "engines": { + "node": "^16 || ^15 || ^14 || ^13 || ^12 || ^11 || ^10 || ^9 || ^8 || ^7 || ^6" + }, + "peerDependencies": { + "eslint-plugin-import": ">=1.4.0", + "webpack": ">=1.11.0" + } + }, + "node_modules/eslint-import-resolver-webpack/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-webpack/node_modules/enhanced-resolve": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz", + "integrity": "sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.2.0", + "tapable": "^0.1.8" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/eslint-import-resolver-webpack/node_modules/memory-fs": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz", + "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=", + "dev": true + }, + "node_modules/eslint-import-resolver-webpack/node_modules/tapable": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz", + "integrity": "sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=", + "dev": true, + "engines": { + "node": ">=0.6" + } }, "node_modules/eslint-loader": { "version": "3.0.3", @@ -8276,11 +8544,11 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz", + "integrity": "sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==", "dependencies": { - "debug": "^2.6.9", + "debug": "^3.2.7", "pkg-dir": "^2.0.0" }, "engines": { @@ -8288,11 +8556,11 @@ } }, "node_modules/eslint-module-utils/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "node_modules/eslint-module-utils/node_modules/find-up": { @@ -8318,11 +8586,6 @@ "node": ">=4" } }, - "node_modules/eslint-module-utils/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, "node_modules/eslint-module-utils/node_modules/p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", @@ -8372,6 +8635,18 @@ "node": ">=4" } }, + "node_modules/eslint-plugin-cypress": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.12.1.tgz", + "integrity": "sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA==", + "dev": true, + "dependencies": { + "globals": "^11.12.0" + }, + "peerDependencies": { + "eslint": ">= 3.2.1" + } + }, "node_modules/eslint-plugin-flowtype": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.6.0.tgz", @@ -8386,6 +8661,297 @@ "eslint": ">=6.1.0" } }, + "node_modules/eslint-plugin-import": { + "version": "2.24.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz", + "integrity": "sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==", + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.6.2", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.6.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.4", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/eslint-plugin-import/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", + "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "eslint": ">=5.0.0", + "prettier": ">=1.13.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.25.2.tgz", + "integrity": "sha512-elx4585wgmryanJK4C5IoSKQyVZ+e7H0t2JOOtJNBql0cuercvSShvRReuLBbfx8687yW5yv+UL7pXwMsd6adQ==", + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flatmap": "^1.2.4", + "doctrine": "^2.1.0", + "estraverse": "^5.2.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.4", + "object.fromentries": "^2.0.4", + "object.values": "^1.1.4", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "string.prototype.matchall": "^4.0.5" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", + "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -8420,6 +8986,308 @@ "node": ">=4" } }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/eslint/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/eslint/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -8934,6 +9802,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "node_modules/fast-glob": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", @@ -9068,6 +9942,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/file-loader": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.3.0.tgz", @@ -9325,6 +10210,37 @@ "node": ">= 0.10" } }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==" + }, "node_modules/flatten": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", @@ -9664,6 +10580,21 @@ "node": ">=6" } }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -9969,6 +10900,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -10897,9 +11842,9 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "node_modules/is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "engines": { "node": ">= 0.4" }, @@ -10932,9 +11877,9 @@ } }, "node_modules/is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", + "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", "dependencies": { "has": "^1.0.3" }, @@ -11198,12 +12143,12 @@ "dev": true }, "node_modules/is-regex": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", - "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dependencies": { "call-bind": "^1.0.2", - "has-symbols": "^1.0.1" + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -11242,9 +12187,12 @@ } }, "node_modules/is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -12277,6 +13225,18 @@ "resolved": "https://registry.npmjs.org/jsqr/-/jsqr-1.4.0.tgz", "integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A==" }, + "node_modules/jsx-ast-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", + "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "dependencies": { + "array-includes": "^3.1.3", + "object.assign": "^4.1.2" + }, + "engines": { + "node": ">=4.0" + } + }, "node_modules/killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -12685,6 +13645,11 @@ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, "node_modules/lodash.curry": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", @@ -12705,6 +13670,11 @@ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -12733,6 +13703,11 @@ "lodash._reinterpolate": "^3.0.0" } }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" + }, "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -14000,9 +14975,9 @@ } }, "node_modules/object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -14067,14 +15042,13 @@ } }, "node_modules/object.entries": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz", - "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz", + "integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==", "dependencies": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" + "es-abstract": "^1.18.2" }, "engines": { "node": ">= 0.4" @@ -14125,14 +15099,13 @@ } }, "node_modules/object.values": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", - "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", + "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" + "es-abstract": "^1.18.2" }, "engines": { "node": ">= 0.4" @@ -15879,6 +16852,30 @@ "node": ">=0.10.0" } }, + "node_modules/prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -18533,6 +19530,14 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -19881,14 +20886,15 @@ } }, "node_modules/string.prototype.matchall": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz", - "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz", + "integrity": "sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has-symbols": "^1.0.1", + "es-abstract": "^1.18.2", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.2", "internal-slot": "^1.0.3", "regexp.prototype.flags": "^1.3.1", "side-channel": "^1.0.4" @@ -20134,6 +21140,141 @@ "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.15.tgz", "integrity": "sha512-k8uzYIkIVwmT+TcglpdN50pS2y1BDcUnBPK9iJeGu0Pl1lOI8pD6wtzgw91Pjpe+RxtTncw32tLxs/R0yNL2Mg==" }, + "node_modules/table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dependencies": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/table/node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/table/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/table/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/table/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/table/node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -20627,6 +21768,36 @@ } } }, + "node_modules/tsconfig-paths": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", + "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "engines": { + "node": ">=4" + } + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -23846,6 +25017,51 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" }, + "@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "requires": { + "type-fest": "^0.20.2" + } + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + } + } + }, "@googlemaps/js-api-loader": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.11.1.tgz", @@ -23888,6 +25104,21 @@ "@hapi/hoek": "^8.3.0" } }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==" + }, "@icons/material": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", @@ -24865,6 +26096,11 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==" }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" + }, "@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", @@ -25582,6 +26818,12 @@ "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" }, + "array-find": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz", + "integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=", + "dev": true + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -25646,6 +26888,17 @@ "es-abstract": "^1.18.0-next.1" } }, + "array.prototype.flatmap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", + "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "function-bind": "^1.1.1" + } + }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -25910,7 +27163,6 @@ "version": "1.13.3", "resolved": "https://registry.npmjs.org/babel-plugin-import/-/babel-plugin-import-1.13.3.tgz", "integrity": "sha512-1qCWdljJOrDRH/ybaCZuDgySii4yYrtQ8OJQwrcDqdt0y67N30ng3X3nABg6j7gR7qUJgcMa9OMhc4AGViDwWw==", - "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", "@babel/runtime": "^7.0.0" @@ -28661,6 +29913,21 @@ } } }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "requires": { + "ansi-colors": "^4.1.1" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" + } + } + }, "entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", @@ -28692,26 +29959,28 @@ } }, "es-abstract": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", - "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", + "version": "1.18.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.6.tgz", + "integrity": "sha512-kAeIT4cku5eNLNuUKhlmtuk1/TRZvQoYccn6TO0cSVdf1kzB0T7+dYuVK9MWM7l+/53W2Q8M7N2c6MQvhXFcUQ==", "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.2", - "is-string": "^1.0.5", - "object-inspect": "^1.9.0", + "is-regex": "^1.1.4", + "is-string": "^1.0.7", + "object-inspect": "^1.11.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", "string.prototype.trimend": "^1.0.4", "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.0" + "unbox-primitive": "^1.0.1" } }, "es-to-primitive": { @@ -28780,6 +30049,255 @@ "source-map": "~0.6.1" } }, + "eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + }, + "globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true, + "requires": {} + }, "eslint-config-react-app": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz", @@ -28789,26 +30307,74 @@ } }, "eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" + "debug": "^3.2.7", + "resolve": "^1.20.0" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" + } + } + } + }, + "eslint-import-resolver-webpack": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.1.tgz", + "integrity": "sha512-O/8mG6AHmaKYSMb4lWxiXPpaARxOJ4rMQEHJ8vTgjS1MXooJA3KPgBPPAdOPoV17v5ML5120qod5FBLM+DtgEw==", + "dev": true, + "requires": { + "array-find": "^1.0.0", + "debug": "^3.2.7", + "enhanced-resolve": "^0.9.1", + "find-root": "^1.1.0", + "has": "^1.0.3", + "interpret": "^1.4.0", + "is-core-module": "^2.4.0", + "is-regex": "^1.1.3", + "lodash": "^4.17.21", + "resolve": "^1.20.0", + "semver": "^5.7.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "enhanced-resolve": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz", + "integrity": "sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.2.0", + "tapable": "^0.1.8" + } + }, + "memory-fs": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz", + "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=", + "dev": true + }, + "tapable": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz", + "integrity": "sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=", + "dev": true } } }, @@ -28825,20 +30391,20 @@ } }, "eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz", + "integrity": "sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==", "requires": { - "debug": "^2.6.9", + "debug": "^3.2.7", "pkg-dir": "^2.0.0" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "find-up": { @@ -28858,11 +30424,6 @@ "path-exists": "^3.0.0" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", @@ -28899,6 +30460,15 @@ } } }, + "eslint-plugin-cypress": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.12.1.tgz", + "integrity": "sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA==", + "dev": true, + "requires": { + "globals": "^11.12.0" + } + }, "eslint-plugin-flowtype": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.6.0.tgz", @@ -28907,6 +30477,218 @@ "lodash": "^4.17.15" } }, + "eslint-plugin-import": { + "version": "2.24.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz", + "integrity": "sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==", + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.6.2", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.6.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.4", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "requires": { + "find-up": "^2.1.0" + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + } + } + }, + "eslint-plugin-prettier": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", + "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-plugin-react": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.25.2.tgz", + "integrity": "sha512-elx4585wgmryanJK4C5IoSKQyVZ+e7H0t2JOOtJNBql0cuercvSShvRReuLBbfx8687yW5yv+UL7pXwMsd6adQ==", + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flatmap": "^1.2.4", + "doctrine": "^2.1.0", + "estraverse": "^5.2.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.4", + "object.fromentries": "^2.0.4", + "object.values": "^1.1.4", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "string.prototype.matchall": "^4.0.5" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + }, + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + }, + "resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-plugin-react-hooks": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", + "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", + "requires": {} + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -28929,6 +30711,16 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -29344,6 +31136,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "fast-glob": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", @@ -29469,6 +31267,14 @@ "escape-string-regexp": "^1.0.5" } }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "requires": { + "flat-cache": "^3.0.4" + } + }, "file-loader": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.3.0.tgz", @@ -29682,6 +31488,30 @@ "resolve-dir": "^1.0.1" } }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==" + }, "flatten": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", @@ -29928,6 +31758,15 @@ "pump": "^3.0.0" } }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -30161,6 +32000,14 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -30889,9 +32736,9 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" }, "is-ci": { "version": "2.0.0", @@ -30915,9 +32762,9 @@ } }, "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", + "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", "requires": { "has": "^1.0.3" } @@ -31089,12 +32936,12 @@ "dev": true }, "is-regex": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", - "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "requires": { "call-bind": "^1.0.2", - "has-symbols": "^1.0.1" + "has-tostringtag": "^1.0.0" } }, "is-regexp": { @@ -31118,9 +32965,12 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-svg": { "version": "3.0.0", @@ -31955,6 +33805,15 @@ "resolved": "https://registry.npmjs.org/jsqr/-/jsqr-1.4.0.tgz", "integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A==" }, + "jsx-ast-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", + "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "requires": { + "array-includes": "^3.1.3", + "object.assign": "^4.1.2" + } + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -32278,6 +34137,11 @@ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, "lodash.curry": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", @@ -32298,6 +34162,11 @@ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, "lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -32326,6 +34195,11 @@ "lodash._reinterpolate": "^3.0.0" } }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" + }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -33351,9 +35225,9 @@ "integrity": "sha512-VOJmgmS+7wvXf8CjbQmimtCnEx3IAoLxI3fp2fbWehxrWBcAQFbk+vcwb6vzR0VZv/eNCJ/27j151ZTwqW/JeQ==" }, "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==" + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" }, "object-is": { "version": "1.1.5", @@ -33394,14 +35268,13 @@ } }, "object.entries": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz", - "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz", + "integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==", "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" + "es-abstract": "^1.18.2" } }, "object.fromentries": { @@ -33434,14 +35307,13 @@ } }, "object.values": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", - "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", + "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" + "es-abstract": "^1.18.2" } }, "obuf": { @@ -34872,6 +36744,21 @@ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, + "prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -36930,6 +38817,11 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -38039,14 +39931,15 @@ } }, "string.prototype.matchall": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz", - "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz", + "integrity": "sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has-symbols": "^1.0.1", + "es-abstract": "^1.18.2", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.2", "internal-slot": "^1.0.3", "regexp.prototype.flags": "^1.3.1", "side-channel": "^1.0.4" @@ -38234,6 +40127,106 @@ "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.15.tgz", "integrity": "sha512-k8uzYIkIVwmT+TcglpdN50pS2y1BDcUnBPK9iJeGu0Pl1lOI8pD6wtzgw91Pjpe+RxtTncw32tLxs/R0yNL2Mg==" }, + "table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -38607,6 +40600,32 @@ "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.6.tgz", "integrity": "sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ==" }, + "tsconfig-paths": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", + "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + } + } + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index a38c8cda6d..70205918d4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,7 +3,6 @@ "version": "0.1.0", "private": true, "dependencies": { - "babel-plugin-import": "^1.13.3", "@babel/core": "^7.4.3", "@babel/plugin-proposal-class-properties": "^7.10.4", "@babel/preset-env": "^7.4.3", @@ -18,6 +17,7 @@ "array-move": "^3.0.1", "babel-loader": "^8.0.5", "babel-plugin-console-source": "^2.0.5", + "babel-plugin-import": "^1.13.3", "bootstrap": "^4.6.0", "dompurify": "^2.2.7", "draft-js": "^0.11.7", @@ -71,13 +71,24 @@ "@cypress/webpack-preprocessor": "^5.9.0", "@svgr/webpack": "^5.5.0", "cypress": "^7.4.0", + "eslint": "^7.32.0", + "eslint-config-prettier": "^8.3.0", + "eslint-import-resolver-webpack": "^0.13.1", + "eslint-plugin-cypress": "^2.12.1", + "eslint-plugin-import": "^2.24.2", + "eslint-plugin-prettier": "^3.4.1", + "eslint-plugin-react": "^7.25.2", + "eslint-plugin-react-hooks": "^4.2.0", "path": "^0.12.7", + "prettier": "^2.3.2", "webpack": "^4.29.6", "webpack-dev-server": "^3.11.2" }, "scripts": { "start": "webpack-dev-server --open --port 8082 --host 0.0.0.0", "build": "webpack -p && cp -a ./assets/. ./build/assets/", + "lint": "eslint . '**/*.{js,jsx}'", + "format": "eslint . --fix '**/*.{js,jsx}'", "test": "react-scripts test", "eject": "react-scripts eject" }, diff --git a/frontend/src/App/App.jsx b/frontend/src/App/App.jsx index 6ca33d99ab..9e38f1136c 100644 --- a/frontend/src/App/App.jsx +++ b/frontend/src/App/App.jsx @@ -15,7 +15,7 @@ import 'react-toastify/dist/ReactToastify.css'; import { ManageOrgUsers } from '@/ManageOrgUsers'; import { SettingsPage } from '../SettingsPage/SettingsPage'; import { OnboardingModal } from '@/Onboarding/OnboardingModal'; -import {ForgotPassword} from '@/ForgotPassword' +import { ForgotPassword } from '@/ForgotPassword'; import { ResetPassword } from '@/ResetPassword'; import { lt } from 'semver'; @@ -27,7 +27,7 @@ class App extends React.Component { currentUser: null, fetchedMetadata: false, onboarded: true, - darkMode: localStorage.getItem('darkMode') === 'true' + darkMode: localStorage.getItem('darkMode') === 'true', }; } @@ -40,56 +40,107 @@ class App extends React.Component { logout = () => { authenticationService.logout(); history.push('/login'); - } + }; switchDarkMode = (newMode) => { this.setState({ darkMode: newMode }); localStorage.setItem('darkMode', newMode); - } + }; render() { const { currentUser, fetchedMetadata, updateAvailable, onboarded, darkMode } = this.state; - if(currentUser && fetchedMetadata === false) { + if (currentUser && fetchedMetadata === false) { tooljetService.fetchMetaData().then((data) => { this.setState({ fetchedMetadata: true, onboarded: data.onboarded }); - if(lt(data.installed_version, data.latest_version) && data.version_ignored === false) { + if (lt(data.installed_version, data.latest_version) && data.version_ignored === false) { this.setState({ updateAvailable: true }); } - }) + }); } return (
- {updateAvailable &&
-

Update available

-

A new version of ToolJet has been released.

- } + )} - {!onboarded && - - } + {!onboarded && } - - + + - - + + - - - - - - + + + + + +
); diff --git a/frontend/src/Editor/ActionTypes.js b/frontend/src/Editor/ActionTypes.js index 0c8a7fa642..0111eb2619 100644 --- a/frontend/src/Editor/ActionTypes.js +++ b/frontend/src/Editor/ActionTypes.js @@ -2,51 +2,39 @@ export const ActionTypes = [ { name: 'Show Alert', id: 'show-alert', - options: [ - { name: 'message', type: 'text', default: 'Message !' } - ] + options: [{ name: 'message', type: 'text', default: 'Message !' }], }, { name: 'Run Query', id: 'run-query', - options: [ - { queryId: '' } - ] + options: [{ queryId: '' }], }, { name: 'Open Webpage', id: 'open-webpage', - options: [ - { name: 'url', type: 'text', default: 'https://example.com' } - ] + options: [{ name: 'url', type: 'text', default: 'https://example.com' }], }, { name: 'Go to app', id: 'go-to-app', options: [ { name: 'app', type: 'text', default: '' }, - { name: 'queryParams', type: 'code', default: '[]' } - ] + { name: 'queryParams', type: 'code', default: '[]' }, + ], }, { name: 'Show Modal', id: 'show-modal', - options: [ - { name: 'modal', type: 'text', default: '' } - ] + options: [{ name: 'modal', type: 'text', default: '' }], }, { name: 'Close Modal', id: 'close-modal', - options: [ - { name: 'modal', type: 'text', default: '' } - ] + options: [{ name: 'modal', type: 'text', default: '' }], }, { name: 'Copy to clipboard', id: 'copy-to-clipboard', - options: [ - { name: 'copy-to-clipboard', type: 'text', default: '' } - ] - } + options: [{ name: 'copy-to-clipboard', type: 'text', default: '' }], + }, ]; diff --git a/frontend/src/Editor/Box.jsx b/frontend/src/Editor/Box.jsx index 9ad04f3266..1fefeca782 100644 --- a/frontend/src/Editor/Box.jsx +++ b/frontend/src/Editor/Box.jsx @@ -17,9 +17,9 @@ import { Modal } from './Components/Modal'; import { Chart } from './Components/Chart'; import { Map } from './Components/Map/Map'; import { QrScanner } from './Components/QrScanner/QrScanner'; -import { ToggleSwitch } from './Components/Toggle' -import { RadioButton } from './Components/RadioButton' -import { StarRating } from './Components/StarRating' +import { ToggleSwitch } from './Components/Toggle'; +import { RadioButton } from './Components/RadioButton'; +import { StarRating } from './Components/StarRating'; import { renderTooltip } from '../_helpers/appUtils'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import '@/_styles/custom.scss'; @@ -45,12 +45,11 @@ const AllComponents = { QrScanner, ToggleSwitch, RadioButton, - StarRating + StarRating, }; export const Box = function Box({ id, - mode, width, height, yellow, @@ -66,7 +65,7 @@ export const Box = function Box({ changeCanDrag, containerProps, darkMode, - removeComponent + removeComponent, }) { const backgroundColor = yellow ? 'yellow' : ''; @@ -86,49 +85,49 @@ export const Box = function Box({ renderTooltip({props, text: `${component.description}`})} + trigger={!inCanvas ? ['hover', 'focus'] : null} + overlay={(props) => renderTooltip({ props, text: `${component.description}` })} > -
- {inCanvas ? ( - - ) : ( -
-
-
-
-
- {component.displayName} +
+ {inCanvas ? ( + + ) : ( +
+
+
+
+
+ {component.displayName} +
-
- )} -
+ )} +
); }; diff --git a/frontend/src/Editor/BoxDragPreview.jsx b/frontend/src/Editor/BoxDragPreview.jsx index 1cfa332741..608feb3b28 100644 --- a/frontend/src/Editor/BoxDragPreview.jsx +++ b/frontend/src/Editor/BoxDragPreview.jsx @@ -11,7 +11,7 @@ export const BoxDragPreview = memo(function BoxDragPreview({ item, currentLayout [tickTock] ); - const layouts = item.layouts; + const layouts = item.layouts; let { width, height } = layouts ? item.layouts[currentLayout] : {}; if (item.id === undefined) { @@ -21,9 +21,14 @@ export const BoxDragPreview = memo(function BoxDragPreview({ item, currentLayout return (
-
+
); }); diff --git a/frontend/src/Editor/CodeBuilder/CodeBuilder.jsx b/frontend/src/Editor/CodeBuilder/CodeBuilder.jsx index 3d1df1f657..e5bfd9625a 100644 --- a/frontend/src/Editor/CodeBuilder/CodeBuilder.jsx +++ b/frontend/src/Editor/CodeBuilder/CodeBuilder.jsx @@ -6,9 +6,7 @@ import { DataSourceTypes } from '../DataSourceManager/DataSourceTypes'; import { debounce } from 'lodash'; import Fuse from 'fuse.js'; -export function CodeBuilder({ - initialValue, onChange, components, dataQueries -}) { +export function CodeBuilder({ initialValue, onChange, components, dataQueries }) { const [showDropdown, setShowDropdown] = useState(false); const [cursorPosition, setCursorPosition] = useState(0); const [currentValue, setCurrentValue] = useState(initialValue); @@ -130,7 +128,7 @@ export function CodeBuilder({ mode: 'javascript', lineWrapping: true, scrollbarStyle: null, - lineNumbers: false + lineNumbers: false, }} /> {showDropdown && ( diff --git a/frontend/src/Editor/CodeBuilder/CodeHinter.jsx b/frontend/src/Editor/CodeBuilder/CodeHinter.jsx index 5b89433563..8e7c1d7201 100644 --- a/frontend/src/Editor/CodeBuilder/CodeHinter.jsx +++ b/frontend/src/Editor/CodeBuilder/CodeHinter.jsx @@ -57,10 +57,12 @@ export function CodeHinter({ }); useEffect(() => { setRealState(currentState); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentState.components]); let suggestions = useMemo(() => { return getSuggestionKeys(realState); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [realState.components, realState.queries]); function valueChanged(editor, onChange, suggestions, ignoreBraces) { diff --git a/frontend/src/Editor/CodeBuilder/CodeHinter.spec.jsx b/frontend/src/Editor/CodeBuilder/CodeHinter.spec.jsx index 666f297259..2cf3fc7173 100644 --- a/frontend/src/Editor/CodeBuilder/CodeHinter.spec.jsx +++ b/frontend/src/Editor/CodeBuilder/CodeHinter.spec.jsx @@ -1,33 +1,27 @@ -import * as React from 'react' -import { mount } from '@cypress/react' -import { CodeHinter } from './CodeHinter' +import * as React from 'react'; +import { mount } from '@cypress/react'; +import { CodeHinter } from './CodeHinter'; it('Codehinter', () => { - mount( console.log(value)} + /> + ); - }, - globals: { - - } - }} - initialValue={''} - theme="duotone-light" - mode="javascript" - lineNumbers={true} - className="query-hinter" - onChange={(value) => {}} - />) - - cy.get('.code-hinter') - .click() - .type('{{') - .contains('{{}}') // autocomplete for dynamic variables -}) - \ No newline at end of file + cy.get('.code-hinter').click().type('{{').contains('{{}}'); // autocomplete for dynamic variables +}); diff --git a/frontend/src/Editor/CodeBuilder/utils.js b/frontend/src/Editor/CodeBuilder/utils.js index 001557141e..2c16334789 100644 --- a/frontend/src/Editor/CodeBuilder/utils.js +++ b/frontend/src/Editor/CodeBuilder/utils.js @@ -6,16 +6,15 @@ export function getSuggestionKeys(currentState) { _.keys(currentState).forEach((key) => { _.keys(currentState[key]).forEach((key2) => { _.keys(currentState[key][key2]).forEach((key3) => { - suggestions.push(`${key}.${key2}.${key3}`) - }) - }) + suggestions.push(`${key}.${key2}.${key3}`); + }); + }); }); return suggestions; } export function generateHints(word, suggestions) { - - if(word === '') { + if (word === '') { return suggestions; } @@ -38,25 +37,25 @@ export function computeCurrentWord(editor, _cursorPosition, ignoreBraces = false export function makeOverlay(style) { return { + // eslint-disable-next-line no-unused-vars token: function (stream, state) { var ch; - if (stream.match("{{")) { + if (stream.match('{{')) { while ((ch = stream.next()) != null) - if (ch == "}" && stream.next() == "}") { - stream.eat("}"); + if (ch == '}' && stream.next() == '}') { + stream.eat('}'); return style; } } - while (stream.next() != null && !stream.match("{{", false)) { } + // eslint-disable-next-line no-empty + while (stream.next() != null && !stream.match('{{', false)) {} return null; - } - } + }, + }; } export function onBeforeChange(editor, change, ignoreBraces = false) { - - if(!ignoreBraces) { - + if (!ignoreBraces) { const cursor = editor.getCursor(); const line = cursor.line; const ch = cursor.ch; @@ -64,33 +63,30 @@ export function onBeforeChange(editor, change, ignoreBraces = false) { const isLastCharacterBrace = value.slice(ch - 1, value.length) === '{'; if (isLastCharacterBrace && change.origin === '+input' && change.text[0] === '{') { - change.text[0] = '{}}' + change.text[0] = '{}}'; // editor.setCursor({ line: 0, ch: ch }) } - } return change; } export function canShowHint(editor, ignoreBraces = false) { - - if(!editor.hasFocus()) return false; + if (!editor.hasFocus()) return false; const cursor = editor.getCursor(); const line = cursor.line; const ch = cursor.ch; const value = editor.getLine(line); - if(ignoreBraces && value.length > 0) return true; + if (ignoreBraces && value.length > 0) return true; return value.slice(ch, ch + 2) === '}}'; } export function handleChange(editor, onChange, suggestions, ignoreBraces = false) { - let state = editor.state.matchHighlighter; - editor.addOverlay(state.overlay = makeOverlay(state.options.style)); + editor.addOverlay((state.overlay = makeOverlay(state.options.style))); const cursor = editor.getCursor(); const currentWord = computeCurrentWord(editor, cursor.ch, ignoreBraces); @@ -103,11 +99,11 @@ export function handleChange(editor, onChange, suggestions, ignoreBraces = false return { from: { line: cursor.line, ch: cursor.ch - currentWord.length }, to: cursor, - list: hints - } - } + list: hints, + }; + }, }; if (canShowHint(editor, ignoreBraces)) { editor.showHint(options); } -}; +} diff --git a/frontend/src/Editor/Components/Button.jsx b/frontend/src/Editor/Components/Button.jsx index 1496faf59e..5ef061188d 100644 --- a/frontend/src/Editor/Components/Button.jsx +++ b/frontend/src/Editor/Components/Button.jsx @@ -1,10 +1,8 @@ import React, { useState, useEffect } from 'react'; import { resolveReferences, resolveWidgetFieldValue } from '@/_helpers/utils'; -var tinycolor = require("tinycolor2"); +var tinycolor = require('tinycolor2'); -export const Button = function Button({ - id, width, height, component, onComponentClick, currentState -}) { +export const Button = function Button({ id, width, height, component, onComponentClick, currentState }) { console.log('currentState', currentState); const [loadingState, setLoadingState] = useState(false); @@ -15,6 +13,7 @@ export const Button = function Button({ const newState = resolveReferences(loadingStateProperty.value, currentState, false); setLoadingState(newState); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentState]); const text = component.definition.properties.text.value; @@ -23,12 +22,15 @@ export const Button = function Button({ const widgetVisibility = component.definition.styles?.visibility?.value ?? true; const disabledState = component.definition.styles?.disabledState?.value ?? false; - const parsedDisabledState = typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; + const parsedDisabledState = + typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; let parsedWidgetVisibility = widgetVisibility; - + try { parsedWidgetVisibility = resolveReferences(parsedWidgetVisibility, currentState, []); - } catch (err) { console.log(err); } + } catch (err) { + console.log(err); + } const computedStyles = { backgroundColor, @@ -36,7 +38,7 @@ export const Button = function Button({ width, height, display: parsedWidgetVisibility ? '' : 'none', - '--tblr-btn-color-darker': tinycolor(backgroundColor).darken(8).toString() + '--tblr-btn-color-darker': tinycolor(backgroundColor).darken(8).toString(), }; return ( @@ -44,7 +46,10 @@ export const Button = function Button({ disabled={parsedDisabledState} className={`jet-button btn btn-primary p-1 ${loadingState === true ? ' btn-loading' : ''}`} style={computedStyles} - onClick={(event) => {event.stopPropagation(); onComponentClick(id, component)}} + onClick={(event) => { + event.stopPropagation(); + onComponentClick(id, component); + }} > {text} diff --git a/frontend/src/Editor/Components/Chart.jsx b/frontend/src/Editor/Components/Chart.jsx index b3d6097804..b0920f3347 100644 --- a/frontend/src/Editor/Components/Chart.jsx +++ b/frontend/src/Editor/Components/Chart.jsx @@ -4,14 +4,9 @@ import { resolveReferences, resolveWidgetFieldValue } from '@/_helpers/utils'; // Use plotly basic bundle import Plotly from 'plotly.js-basic-dist-min'; import createPlotlyComponent from 'react-plotly.js/factory'; -const Plot = createPlotlyComponent(Plotly) - -import Skeleton from 'react-loading-skeleton'; - -export const Chart = function Chart({ - id, width, height, component, onComponentClick, currentState, darkMode -}) { +const Plot = createPlotlyComponent(Plotly); +export const Chart = function Chart({ id, width, height, component, onComponentClick, currentState, darkMode }) { const [loadingState, setLoadingState] = useState(false); const [chartData, setChartData] = useState([]); @@ -19,28 +14,31 @@ export const Chart = function Chart({ const disabledState = component.definition.styles?.disabledState?.value ?? false; let parsedWidgetVisibility = widgetVisibility; - const parsedDisabledState = typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; - + const parsedDisabledState = + typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; + try { parsedWidgetVisibility = resolveReferences(parsedWidgetVisibility, currentState, []); - } catch (err) { console.log(err); } + } catch (err) { + console.log(err); + } useEffect(() => { const loadingStateProperty = component.definition.properties.loadingState; if (loadingStateProperty && currentState) { const newState = resolveReferences(loadingStateProperty.value, currentState, false); - setLoadingState(newState); + setLoadingState(newState); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentState]); const computedStyles = { width, height, display: parsedWidgetVisibility ? '' : 'none', - background: darkMode ? '#1f2936' : 'white' + background: darkMode ? '#1f2936' : 'white', }; - // darkMode ? '#1f2936' : 'white' const dataProperty = component.definition.properties.data; const dataString = dataProperty ? dataProperty.value : []; @@ -66,73 +64,84 @@ export const Chart = function Chart({ title: { text: title, font: { - color: fontColor - } + color: fontColor, + }, }, legend: { text: title, font: { - color: fontColor - } + color: fontColor, + }, }, xaxis: { showgrid: showGridLines, showline: true, - color: fontColor + color: fontColor, }, yaxis: { - showgrid: showGridLines, - showline: true, - color: fontColor - } - } + showgrid: showGridLines, + showline: true, + color: fontColor, + }, + }; const data = resolveReferences(dataString, currentState, []); useEffect(() => { - let rawData = data || []; - if(typeof rawData === 'string') { + if (typeof rawData === 'string') { try { rawData = JSON.parse(dataString); - } catch (err) { rawData = []; } + } catch (err) { + rawData = []; + } } - if(!Array.isArray(rawData)) { rawData = []; } + if (!Array.isArray(rawData)) { + rawData = []; + } let newData = []; - if(chartType === 'pie') { - newData = [{ - type: chartType, - values: rawData.map((item) => item["value"]), - labels: rawData.map((item) => item["label"]), - }]; + if (chartType === 'pie') { + newData = [ + { + type: chartType, + values: rawData.map((item) => item['value']), + labels: rawData.map((item) => item['label']), + }, + ]; } else { - newData = [{ - type: chartType || 'line', - x: rawData.map((item) => item["x"]), - y: rawData.map((item) => item["y"]), - marker: { color: markerColor } - }]; + newData = [ + { + type: chartType || 'line', + x: rawData.map((item) => item['x']), + y: rawData.map((item) => item['y']), + marker: { color: markerColor }, + }, + ]; } setChartData(newData); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [data, chartType]); return (
{event.stopPropagation(); onComponentClick(id, component)}} + onClick={(event) => { + event.stopPropagation(); + onComponentClick(id, component); + }} > - {loadingState === true ? + {loadingState === true ? (
- : + ) : ( - } + )}
); }; diff --git a/frontend/src/Editor/Components/Checkbox.jsx b/frontend/src/Editor/Components/Checkbox.jsx index a06b4e9725..84448646b9 100644 --- a/frontend/src/Editor/Components/Checkbox.jsx +++ b/frontend/src/Editor/Components/Checkbox.jsx @@ -9,22 +9,24 @@ export const Checkbox = function Checkbox({ onComponentClick, currentState, onComponentOptionChanged, - onEvent + onEvent, }) { - const label = component.definition.properties.label.value; const textColorProperty = component.definition.styles.textColor; const textColor = textColorProperty ? textColorProperty.value : '#000'; const widgetVisibility = component.definition.styles?.visibility?.value ?? true; const disabledState = component.definition.styles?.disabledState?.value ?? false; - const parsedDisabledState = typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; + const parsedDisabledState = + typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; let parsedWidgetVisibility = widgetVisibility; - + try { parsedWidgetVisibility = resolveReferences(parsedWidgetVisibility, currentState, []); - } catch (err) { console.log(err); } + } catch (err) { + console.log(err); + } function toggleValue(e) { const checked = e.target.checked; @@ -37,7 +39,15 @@ export const Checkbox = function Checkbox({ } return ( -
{event.stopPropagation(); onComponentClick(id, component)}}> +
{ + event.stopPropagation(); + onComponentClick(id, component); + }} + >
); diff --git a/frontend/src/Editor/Components/Container.jsx b/frontend/src/Editor/Components/Container.jsx index 849189bd1c..9eb8ae0a1b 100644 --- a/frontend/src/Editor/Components/Container.jsx +++ b/frontend/src/Editor/Components/Container.jsx @@ -10,43 +10,42 @@ export const Container = function Container({ containerProps, width, currentState, - removeComponent + removeComponent, }) { - const backgroundColor = component.definition.styles.backgroundColor.value; const widgetVisibility = component.definition.styles?.visibility?.value ?? true; const disabledState = component.definition.styles?.disabledState?.value ?? false; - const parsedDisabledState = typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; + const parsedDisabledState = + typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; let parsedWidgetVisibility = widgetVisibility; - + try { parsedWidgetVisibility = resolveReferences(parsedWidgetVisibility, currentState, []); - } catch (err) { console.log(err); } + } catch (err) { + console.log(err); + } const computedStyles = { backgroundColor, width, height, - display: parsedWidgetVisibility ? 'flex' : 'none' + display: parsedWidgetVisibility ? 'flex' : 'none', }; const parentRef = useRef(null); return ( -
containerProps.onComponentClick(id, component)} style={computedStyles}> - - +
containerProps.onComponentClick(id, component)} + style={computedStyles} + > + +
); }; diff --git a/frontend/src/Editor/Components/Datepicker.jsx b/frontend/src/Editor/Components/Datepicker.jsx index 4175452ae1..a2049e6bd5 100644 --- a/frontend/src/Editor/Components/Datepicker.jsx +++ b/frontend/src/Editor/Components/Datepicker.jsx @@ -1,8 +1,7 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import Datetime from 'react-datetime'; import 'react-datetime/css/react-datetime.css'; import { resolveReferences, resolveWidgetFieldValue, validateWidget } from '@/_helpers/utils'; -import { useEffect, useState } from 'react'; export const Datepicker = function Datepicker({ id, @@ -11,7 +10,7 @@ export const Datepicker = function Datepicker({ component, onComponentClick, currentState, - onComponentOptionChanged + onComponentOptionChanged, }) { console.log('currentState', currentState); @@ -22,71 +21,86 @@ export const Datepicker = function Datepicker({ const disabledState = component.definition.styles?.disabledState?.value ?? false; const defaultValue = component.definition.properties?.defaultValue?.value ?? ''; - const parsedDisabledState = typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; + const parsedDisabledState = + typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; let parsedWidgetVisibility = widgetVisibility; try { parsedWidgetVisibility = resolveReferences(parsedWidgetVisibility, currentState, []); - } catch (err) { console.log(err); } + } catch (err) { + console.log(err); + } const enableTime = resolveReferences(enableTimeProp.value, currentState, false); let enableDate = true; if (enableDateProp) { + // eslint-disable-next-line no-unused-vars enableDate = resolveReferences(enableDateProp.value, currentState, true); } - let dateFormat = formatProp + let dateFormat = formatProp; try { dateFormat = resolveReferences(formatProp, currentState); - } catch (err) { console.log(err); } + } catch (err) { + console.log(err); + } function onDateChange(event) { - const value = event._isAMomentObject? event.format(dateFormat.value) : event; + const value = event._isAMomentObject ? event.format(dateFormat.value) : event; setDateText(value); onComponentOptionChanged(component, 'value', value); } let value = defaultValue; - if (value && currentState) - value = resolveReferences(value, currentState, ''); + if (value && currentState) value = resolveReferences(value, currentState, ''); const [dateText, setDateText] = useState(value); useEffect(() => { setDateText(value); onComponentOptionChanged(component, 'value', value); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [value]); const validationData = validateWidget({ validationObject: component.definition.validation, widgetValue: value, - currentState - }) + currentState, + }); const { isValid, validationError } = validationData; const currentValidState = currentState?.components[component?.name]?.isValid; - if(currentValidState !== isValid) { + if (currentValidState !== isValid) { onComponentOptionChanged(component, 'isValid', isValid); } return ( -
{event.stopPropagation(); onComponentClick(id, component)}}> - { + event.stopPropagation(); + onComponentClick(id, component); + }} + > + { - return + return ( + + ); }} />
{validationError}
diff --git a/frontend/src/Editor/Components/DaterangePicker.jsx b/frontend/src/Editor/Components/DaterangePicker.jsx index b4459597bd..afacc6dc6d 100644 --- a/frontend/src/Editor/Components/DaterangePicker.jsx +++ b/frontend/src/Editor/Components/DaterangePicker.jsx @@ -12,7 +12,7 @@ export const DaterangePicker = function DaterangePicker({ component, onComponentClick, currentState, - onComponentOptionChanged + onComponentOptionChanged, }) { console.log('currentState', currentState); @@ -21,18 +21,20 @@ export const DaterangePicker = function DaterangePicker({ const formatProp = component.definition.properties.format; const widgetVisibility = component.definition.styles?.visibility?.value ?? true; const disabledState = component.definition.styles?.disabledState?.value ?? false; - const parsedDisabledState = typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; - + const parsedDisabledState = + typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; const [focusedInput, setFocusedInput] = useState(null); const [startDate, setStartDate] = useState(startDateProp ? startDateProp.value : null); const [endDate, setEndDate] = useState(endDateProp ? endDateProp.value : null); let parsedWidgetVisibility = widgetVisibility; - + try { parsedWidgetVisibility = resolveReferences(parsedWidgetVisibility, currentState, []); - } catch (err) { console.log(err); } + } catch (err) { + console.log(err); + } function onDateChange(dates) { const start = dates.startDate; @@ -55,7 +57,13 @@ export const DaterangePicker = function DaterangePicker({ } return ( -
{event.stopPropagation(); onComponentClick(id, component)}}> +
{ + event.stopPropagation(); + onComponentClick(id, component); + }} + > { return { name: parsedDisplayValues[index], value: value }; - }) + }), ]; - } catch (err) { console.log(err); } + } catch (err) { + console.log(err); + } const currentValueProperty = component.definition.properties.value; const value = currentValueProperty ? currentValueProperty.value : ''; const [currentValue, setCurrentValue] = useState(''); - let newValue = value; if (currentValueProperty && currentState) { @@ -63,14 +71,14 @@ export const DropDown = function DropDown({ const validationData = validateWidget({ validationObject: component.definition.validation, widgetValue: currentValue, - currentState - }) + currentState, + }); const { isValid, validationError } = validationData; const currentValidState = currentState?.components[component?.name]?.isValid; - if(currentValidState !== isValid) { + if (currentValidState !== isValid) { onComponentOptionChanged(component, 'isValid', isValid); } @@ -79,13 +87,23 @@ export const DropDown = function DropDown({ }, [newValue]); useEffect(() => { - onComponentOptionChanged(component, 'value', currentValue).then(() => onEvent('onSelect', { component }) ); + onComponentOptionChanged(component, 'value', currentValue).then(() => onEvent('onSelect', { component })); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentValue]); return ( -
{event.stopPropagation(); onComponentClick(id, component)}}> +
{ + event.stopPropagation(); + onComponentClick(id, component); + }} + >
- +
- ); + return
; } return ( -
{event.stopPropagation(); onComponentClick(id, component)}}> - } debounce={500}> +
{ + event.stopPropagation(); + onComponentClick(id, component); + }} + > + } debounce={500}>
diff --git a/frontend/src/Editor/Components/Map/Map.jsx b/frontend/src/Editor/Components/Map/Map.jsx index 9cd3866627..75be5ce4c0 100644 --- a/frontend/src/Editor/Components/Map/Map.jsx +++ b/frontend/src/Editor/Components/Map/Map.jsx @@ -1,8 +1,6 @@ -import React, { useEffect, useState, useCallback } from 'react'; -import { GoogleMap, LoadScript } from '@react-google-maps/api'; -import { Marker } from '@react-google-maps/api'; +import React, { useState, useCallback } from 'react'; +import { GoogleMap, LoadScript, Marker, Autocomplete } from '@react-google-maps/api'; import { resolveReferences, resolveWidgetFieldValue } from '@/_helpers/utils'; -import { Autocomplete } from '@react-google-maps/api'; import { darkModeStyles } from './styles'; export const Map = function Map({ @@ -88,6 +86,7 @@ export const Map = function Map({ ]).then(() => onEvent('onBoundsChange', { component })); } + // eslint-disable-next-line react-hooks/exhaustive-deps const onLoad = useCallback(function onLoad(mapInstance) { setGmap(mapInstance); onComponentOptionsChanged(component, [['center', mapInstance.center?.toJSON()]]); @@ -151,7 +150,7 @@ export const Map = function Map({ {Array.isArray(markers) && ( <> {markers.map((marker, index) => ( - handleMarkerClick(index)} /> + handleMarkerClick(index)} /> ))} )} diff --git a/frontend/src/Editor/Components/Map/styles.js b/frontend/src/Editor/Components/Map/styles.js index 352803840e..0378b259c1 100644 --- a/frontend/src/Editor/Components/Map/styles.js +++ b/frontend/src/Editor/Components/Map/styles.js @@ -1,137 +1,137 @@ export const darkModeStyles = [ - { - "featureType": "all", - "elementType": "labels.text.fill", - "stylers": [ - { - "color": "#ffffff" - } - ] - }, - { - "featureType": "all", - "elementType": "labels.text.stroke", - "stylers": [ - { - "color": "#000000" - }, - { - "lightness": 13 - } - ] - }, - { - "featureType": "administrative", - "elementType": "geometry.fill", - "stylers": [ - { - "color": "#000000" - } - ] - }, - { - "featureType": "administrative", - "elementType": "geometry.stroke", - "stylers": [ - { - "color": "#144b53" - }, - { - "lightness": 14 - }, - { - "weight": 1.4 - } - ] - }, - { - "featureType": "landscape", - "elementType": "all", - "stylers": [ - { - "color": "#08304b" - } - ] - }, - { - "featureType": "poi", - "elementType": "geometry", - "stylers": [ - { - "color": "#0c4152" - }, - { - "lightness": 5 - } - ] - }, - { - "featureType": "road.highway", - "elementType": "geometry.fill", - "stylers": [ - { - "color": "#000000" - } - ] - }, - { - "featureType": "road.highway", - "elementType": "geometry.stroke", - "stylers": [ - { - "color": "#0b434f" - }, - { - "lightness": 25 - } - ] - }, - { - "featureType": "road.arterial", - "elementType": "geometry.fill", - "stylers": [ - { - "color": "#000000" - } - ] - }, - { - "featureType": "road.arterial", - "elementType": "geometry.stroke", - "stylers": [ - { - "color": "#0b3d51" - }, - { - "lightness": 16 - } - ] - }, - { - "featureType": "road.local", - "elementType": "geometry", - "stylers": [ - { - "color": "#000000" - } - ] - }, - { - "featureType": "transit", - "elementType": "all", - "stylers": [ - { - "color": "#146474" - } - ] - }, - { - "featureType": "water", - "elementType": "all", - "stylers": [ - { - "color": "#021019" - } - ] - } - ]; + { + featureType: 'all', + elementType: 'labels.text.fill', + stylers: [ + { + color: '#ffffff', + }, + ], + }, + { + featureType: 'all', + elementType: 'labels.text.stroke', + stylers: [ + { + color: '#000000', + }, + { + lightness: 13, + }, + ], + }, + { + featureType: 'administrative', + elementType: 'geometry.fill', + stylers: [ + { + color: '#000000', + }, + ], + }, + { + featureType: 'administrative', + elementType: 'geometry.stroke', + stylers: [ + { + color: '#144b53', + }, + { + lightness: 14, + }, + { + weight: 1.4, + }, + ], + }, + { + featureType: 'landscape', + elementType: 'all', + stylers: [ + { + color: '#08304b', + }, + ], + }, + { + featureType: 'poi', + elementType: 'geometry', + stylers: [ + { + color: '#0c4152', + }, + { + lightness: 5, + }, + ], + }, + { + featureType: 'road.highway', + elementType: 'geometry.fill', + stylers: [ + { + color: '#000000', + }, + ], + }, + { + featureType: 'road.highway', + elementType: 'geometry.stroke', + stylers: [ + { + color: '#0b434f', + }, + { + lightness: 25, + }, + ], + }, + { + featureType: 'road.arterial', + elementType: 'geometry.fill', + stylers: [ + { + color: '#000000', + }, + ], + }, + { + featureType: 'road.arterial', + elementType: 'geometry.stroke', + stylers: [ + { + color: '#0b3d51', + }, + { + lightness: 16, + }, + ], + }, + { + featureType: 'road.local', + elementType: 'geometry', + stylers: [ + { + color: '#000000', + }, + ], + }, + { + featureType: 'transit', + elementType: 'all', + stylers: [ + { + color: '#146474', + }, + ], + }, + { + featureType: 'water', + elementType: 'all', + stylers: [ + { + color: '#021019', + }, + ], + }, +]; diff --git a/frontend/src/Editor/Components/Modal.jsx b/frontend/src/Editor/Components/Modal.jsx index b0cc403fcc..0ae7833ab1 100644 --- a/frontend/src/Editor/Components/Modal.jsx +++ b/frontend/src/Editor/Components/Modal.jsx @@ -4,16 +4,9 @@ import Button from 'react-bootstrap/Button'; import { SubCustomDragLayer } from '../SubCustomDragLayer'; import { SubContainer } from '../SubContainer'; import { ConfigHandle } from '../ConfigHandle'; -import { resolveWidgetFieldValue, resolveReferences } from '../../_helpers/utils'; +import { resolveWidgetFieldValue } from '../../_helpers/utils'; -export const Modal = function Modal({ - id, - component, - height, - mode, - containerProps, - currentState -}) { +export const Modal = function Modal({ id, component, height, containerProps, currentState }) { const [show, showModal] = useState(false); const parentRef = useRef(null); @@ -25,12 +18,14 @@ export const Modal = function Modal({ const disabledState = component.definition.styles?.disabledState?.value ?? false; - const parsedDisabledState = typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; + const parsedDisabledState = + typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; useEffect(() => { const componentState = containerProps.currentState.components[component.name]; const canShowModel = componentState ? componentState.show : false; showModal(canShowModel); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [containerProps.currentState.components[component.name]]); function hideModal() { @@ -51,17 +46,11 @@ export const Modal = function Modal({ animation={false} onEscapeKeyDown={() => showModal(false)} > - {containerProps.mode === 'edit' && - - } + {containerProps.mode === 'edit' && ( + + )} - - {title} - + {title}
diff --git a/frontend/src/Editor/Components/Multiselect.jsx b/frontend/src/Editor/Components/Multiselect.jsx index 3cfdc3550e..d2ca129e07 100644 --- a/frontend/src/Editor/Components/Multiselect.jsx +++ b/frontend/src/Editor/Components/Multiselect.jsx @@ -9,7 +9,7 @@ export const Multiselect = function Multiselect({ component, onComponentClick, currentState, - onComponentOptionChanged + onComponentOptionChanged, }) { console.log('currentState', currentState); @@ -19,7 +19,8 @@ export const Multiselect = function Multiselect({ const widgetVisibility = component.definition.styles?.visibility?.value ?? true; const disabledState = component.definition.styles?.disabledState?.value ?? false; - const parsedDisabledState = typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; + const parsedDisabledState = + typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; const parsedValues = JSON.parse(values); const parsedDisplayValues = JSON.parse(displayValues); @@ -27,7 +28,7 @@ export const Multiselect = function Multiselect({ const selectOptions = [ ...parsedValues.map((value, index) => { return { name: parsedDisplayValues[index], value: value }; - }) + }), ]; const currentValueProperty = component.definition.properties.values; @@ -40,19 +41,30 @@ export const Multiselect = function Multiselect({ } let parsedWidgetVisibility = widgetVisibility; - + try { parsedWidgetVisibility = resolveReferences(parsedWidgetVisibility, currentState, []); - } catch (err) { console.log(err); } + } catch (err) { + console.log(err); + } useEffect(() => { setCurrentValue(newValue); }, [newValue]); return ( -
{event.stopPropagation(); onComponentClick(id, component)}}> +
{ + event.stopPropagation(); + onComponentClick(id, component); + }} + >
- +
{ setNumber(parseInt(newNumber)); onComponentOptionChanged(component, 'value', parseInt(newNumber)); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [newNumber]); const placeholder = component.definition.properties.placeholder.value; const widgetVisibility = component.definition.styles?.visibility?.value ?? true; const disabledState = component.definition.styles?.disabledState?.value ?? false; - const parsedDisabledState = typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; + const parsedDisabledState = + typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; let parsedWidgetVisibility = widgetVisibility; - + try { parsedWidgetVisibility = resolveReferences(parsedWidgetVisibility, currentState, []); - } catch (err) { console.log(err); } + } catch (err) { + console.log(err); + } return ( {event.stopPropagation(); onComponentClick(id, component)}} + onClick={(event) => { + event.stopPropagation(); + onComponentClick(id, component); + }} onChange={(e) => { setNumber(parseInt(e.target.value)); onComponentOptionChanged(component, 'value', parseInt(e.target.value)); @@ -48,7 +54,7 @@ export const NumberInput = function NumberInput({ type="number" className="form-control" placeholder={placeholder} - style={{ width, height, display:parsedWidgetVisibility ? '' : 'none' }} + style={{ width, height, display: parsedWidgetVisibility ? '' : 'none' }} value={number} /> ); diff --git a/frontend/src/Editor/Components/QrScanner/ErrorModal.jsx b/frontend/src/Editor/Components/QrScanner/ErrorModal.jsx index 890f4e2648..409ae536ab 100644 --- a/frontend/src/Editor/Components/QrScanner/ErrorModal.jsx +++ b/frontend/src/Editor/Components/QrScanner/ErrorModal.jsx @@ -1,34 +1,41 @@ -import React, { useState } from 'react'; +import React from 'react'; export default function ErrorModal() { - - const [show, setShow] = React.useState(true) + const [show, setShow] = React.useState(true); const close = () => { - setShow(false) - } - - return( + setShow(false); + }; + + return (
- { - show ? -