diff --git a/.github/workflows/pr-e2e.yml b/.github/workflows/pr-e2e.yml index 09a13ddea1..c1ae0c9b8b 100644 --- a/.github/workflows/pr-e2e.yml +++ b/.github/workflows/pr-e2e.yml @@ -37,13 +37,8 @@ jobs: timeout_minutes: 15 max_attempts: 3 command: yarn build:ci - - name: Update webdriver (with retries) - uses: nick-invision/retry@v2 - with: - timeout_minutes: 15 - max_attempts: 3 - command: yarn lerna run --scope @altairgraphql/app webdriver-update-ci + - run: npx playwright install - name: Run headless e2e test uses: GabrielBB/xvfb-action@v1 with: - run: yarn lerna run --scope @altairgraphql/app e2e:ci + run: yarn playwright test --retries 2 diff --git a/libs/prettier-config/package.json b/libs/prettier-config/package.json index d6d823d8f3..d84180e31b 100644 --- a/libs/prettier-config/package.json +++ b/libs/prettier-config/package.json @@ -2,5 +2,6 @@ "name": "prettier-config-altair", "version": "5.0.18", "main": "index.js", - "license": "MIT" + "license": "MIT", + "private": true } diff --git a/package.json b/package.json index 4597676b3a..54a8adee4c 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ }, "devDependencies": { "@changesets/cli": "^2.18.1", + "@playwright/test": "^1.31.2", "chalk": "^4.1.0", "compare-versions": "^4.1.3", "cwex": "^1.0.4", @@ -64,7 +65,7 @@ "stream-browserify": "^3.0.0", "stream-http": "^3.1.0", "turbo": "^1.7.3", - "typescript": "^4.7.4", + "typescript": "4.9.5", "web-ext": "^6.5.0", "wrangler": "^2.0.27" }, @@ -89,5 +90,6 @@ "url": "https://opencollective.com/altair" }, "snyk": true, - "private": true + "private": true, + "dependencies": {} } diff --git a/packages/altair-api/package.json b/packages/altair-api/package.json index fbe450372c..871f602d54 100644 --- a/packages/altair-api/package.json +++ b/packages/altair-api/package.json @@ -71,7 +71,7 @@ "eslint": "^8.0.1", "eslint-config-prettier": "^8.3.0", "eslint-plugin-prettier": "^4.0.0", - "jest": "28.1.3", + "jest": "29.4.1", "pino-pretty": "^9.2.0", "prettier": "^2.3.2", "prettier-config-altair": "^5.0.18", @@ -79,7 +79,7 @@ "source-map-support": "^0.5.20", "supertest": "^6.1.3", "sync-dotenv": "^2.7.0", - "ts-jest": "28.0.8", + "ts-jest": "29.0.5", "ts-loader": "^9.2.3", "ts-node": "^10.0.0", "tsconfig-paths": "4.1.0", diff --git a/packages/altair-api/src/common/errors.ts b/packages/altair-api/src/common/errors.ts new file mode 100644 index 0000000000..837e459fc0 --- /dev/null +++ b/packages/altair-api/src/common/errors.ts @@ -0,0 +1,11 @@ +export const ERRORS = { + ERR_MAX_TEAM_COUNT: + 'You have reached the limit of the number of teams for your plan', + ERR_MAX_QUERY_COUNT: + 'You have reached the limit of the number of queries for your plan', + ERR_MAX_TEAM_MEMBER_COUNT: + 'You have reached the limit of the number of team members in a team for your plan', + ERR_PERM_DENIED: 'You do not have permission to access this resource', +}; + +export type ErrorCode = keyof typeof ERRORS; diff --git a/packages/altair-api/src/exceptions/invalid-request.exception.ts b/packages/altair-api/src/exceptions/invalid-request.exception.ts new file mode 100644 index 0000000000..097e23e8e9 --- /dev/null +++ b/packages/altair-api/src/exceptions/invalid-request.exception.ts @@ -0,0 +1,17 @@ +import { HttpException, HttpStatus } from '@nestjs/common'; +import { ErrorCode, ERRORS } from 'src/common/errors'; + +export class InvalidRequestException extends HttpException { + constructor(errCode: ErrorCode, message?: string) { + super( + { + status: HttpStatus.BAD_REQUEST, + error: { + code: errCode, + message: ERRORS[errCode] ?? message ?? 'Bad request', + }, + }, + HttpStatus.BAD_REQUEST + ); + } +} diff --git a/packages/altair-api/src/queries/queries.service.ts b/packages/altair-api/src/queries/queries.service.ts index 58eeae7cdb..f5b7568c75 100644 --- a/packages/altair-api/src/queries/queries.service.ts +++ b/packages/altair-api/src/queries/queries.service.ts @@ -4,6 +4,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter'; import { PrismaService } from 'nestjs-prisma'; import { UserService } from 'src/auth/user/user.service'; import { EVENTS } from 'src/common/events'; +import { InvalidRequestException } from 'src/exceptions/invalid-request.exception'; @Injectable() export class QueriesService { @@ -25,7 +26,7 @@ export class QueriesService { }, }); if (queryCount >= userPlanConfig.maxQueryCount) { - throw new ForbiddenException(); + throw new InvalidRequestException('ERR_MAX_QUERY_COUNT'); } // specified collection is owned by the user @@ -39,7 +40,10 @@ export class QueriesService { }); if (!validCollection.length) { - throw new ForbiddenException(); + throw new InvalidRequestException( + 'ERR_PERM_DENIED', + 'You do not have the permission to add a query to this collection' + ); } const res = await this.prisma.queryItem.create({ diff --git a/packages/altair-api/src/query-collections/query-collections.service.ts b/packages/altair-api/src/query-collections/query-collections.service.ts index ff1476e5ee..e021904e9f 100644 --- a/packages/altair-api/src/query-collections/query-collections.service.ts +++ b/packages/altair-api/src/query-collections/query-collections.service.ts @@ -7,11 +7,14 @@ import { import { EventEmitter2 } from '@nestjs/event-emitter'; import { EVENTS } from 'src/common/events'; import { TeamsService } from 'src/teams/teams.service'; +import { InvalidRequestException } from 'src/exceptions/invalid-request.exception'; +import { UserService } from 'src/auth/user/user.service'; @Injectable() export class QueryCollectionsService { constructor( private readonly prisma: PrismaService, + private readonly userService: UserService, private readonly teamsService: TeamsService, private readonly eventService: EventEmitter2 ) {} @@ -20,6 +23,7 @@ export class QueryCollectionsService { userId: string, createQueryCollectionDto: CreateQueryCollectionDto ) { + const userPlanConfig = await this.userService.getPlanConfig(userId); const userWorkspace = await this.prisma.workspace.findFirst({ where: { ownerId: userId, @@ -35,8 +39,9 @@ export class QueryCollectionsService { const validTeam = await this.teamsService.findOne(userId, teamId); if (!validTeam) { - throw new BadRequestException( - 'You cannot create a collection for this teaam' + throw new InvalidRequestException( + 'ERR_PERM_DENIED', + 'You cannot create a collection for this teaam.' ); } @@ -50,7 +55,40 @@ export class QueryCollectionsService { } if (!workspaceId) { - throw new BadRequestException(); + throw new BadRequestException('Workspace is not valid.'); + } + + // Count number of queries + const queryItems = await this.prisma.queryItem.findMany({ + where: { + AND: { + collection: { + OR: [ + { + // queries user owns + workspace: { + ownerId: userId, + }, + }, + { + // queries owned by user's team + workspace: { + team: { + ownerId: userId, + }, + }, + }, + ], + }, + }, + }, + }); + + if ( + queryItems.length + createQueryCollectionDto.queries.length > + userPlanConfig.maxQueryCount + ) { + throw new InvalidRequestException('ERR_MAX_QUERY_COUNT'); } const res = await this.prisma.queryCollection.create({ diff --git a/packages/altair-api/src/team-memberships/team-memberships.service.ts b/packages/altair-api/src/team-memberships/team-memberships.service.ts index 47e4efc437..01ea6f907a 100644 --- a/packages/altair-api/src/team-memberships/team-memberships.service.ts +++ b/packages/altair-api/src/team-memberships/team-memberships.service.ts @@ -9,6 +9,7 @@ import { } from '@nestjs/common'; import { PrismaService } from 'nestjs-prisma'; import { UserService } from 'src/auth/user/user.service'; +import { InvalidRequestException } from 'src/exceptions/invalid-request.exception'; @Injectable() export class TeamMembershipsService { @@ -36,7 +37,7 @@ export class TeamMembershipsService { !userPlanConfig.allowMoreTeamMembers && teamMembershipCount >= userPlanConfig.maxTeamMemberCount ) { - throw new ForbiddenException('Maximum allowed team members reached.'); + throw new InvalidRequestException('ERR_MAX_TEAM_MEMBER_COUNT'); } // Update stripe subscription item quantity @@ -56,7 +57,10 @@ export class TeamMembershipsService { }); if (!validTeam) { - throw new ForbiddenException(); + throw new InvalidRequestException( + 'ERR_PERM_DENIED', + 'You are not permitted to add a team member to this team.' + ); } const validMember = await this.prisma.user.findFirst({ @@ -66,6 +70,7 @@ export class TeamMembershipsService { }); if (!validMember) { + console.error('The user does not exist.'); throw new BadRequestException(); } @@ -92,7 +97,10 @@ export class TeamMembershipsService { }); if (!validMember && !validOwner) { - throw new ForbiddenException(); + throw new InvalidRequestException( + 'ERR_PERM_DENIED', + 'You do not have permission to access the team members.' + ); } return this.prisma.teamMembership.findMany({ @@ -133,7 +141,10 @@ export class TeamMembershipsService { }); if (!validOwner) { - throw new ForbiddenException(); + throw new InvalidRequestException( + 'ERR_PERM_DENIED', + 'You are not permitted to remove this team membership.' + ); } return this.prisma.teamMembership.delete({ diff --git a/packages/altair-api/src/teams/teams.service.ts b/packages/altair-api/src/teams/teams.service.ts index 163b3c16ad..70ab965f96 100644 --- a/packages/altair-api/src/teams/teams.service.ts +++ b/packages/altair-api/src/teams/teams.service.ts @@ -2,6 +2,7 @@ import { CreateTeamDto, UpdateTeamDto } from '@altairgraphql/api-utils'; import { ForbiddenException, Injectable } from '@nestjs/common'; import { PrismaService } from 'nestjs-prisma'; import { UserService } from 'src/auth/user/user.service'; +import { InvalidRequestException } from 'src/exceptions/invalid-request.exception'; @Injectable() export class TeamsService { @@ -19,7 +20,10 @@ export class TeamsService { }); if (teamCount >= userPlanConfig.maxTeamCount) { - throw new ForbiddenException(); + throw new InvalidRequestException( + 'ERR_MAX_TEAM_COUNT', + 'You have reached the limit of the number of teams for your plan.' + ); } return this.prisma.team.create({ diff --git a/packages/altair-app/e2e/app.e2e-spec.ts b/packages/altair-app/e2e/app.e2e-spec.ts index 8b36ea46fe..c6b9545053 100644 --- a/packages/altair-app/e2e/app.e2e-spec.ts +++ b/packages/altair-app/e2e/app.e2e-spec.ts @@ -1,14 +1,11 @@ +import { test, expect } from '@playwright/test'; import { AltairPage } from './app.po'; -describe('altair App', () => { - let page: AltairPage; +test.describe('altair App', () => { + test('should have at lease one window', async ({ page }) => { + const altairPage = new AltairPage(page); + await altairPage.navigateTo(); - beforeEach(() => { - page = new AltairPage(); - }); - - it('should have at lease one window', async () => { - await page.navigateTo(); - expect(await page.getWindows().isDisplayed()).toBe(true); + expect(await altairPage.getWindows()).toBeVisible(); }); }); diff --git a/packages/altair-app/e2e/app.po.ts b/packages/altair-app/e2e/app.po.ts index bbb188d3fe..f31861d160 100644 --- a/packages/altair-app/e2e/app.po.ts +++ b/packages/altair-app/e2e/app.po.ts @@ -1,27 +1,21 @@ -import { browser, element, by, ExpectedConditions } from 'protractor'; +import { Page } from '@playwright/test'; export class AltairPage { - constructor() { - browser.waitForAngularEnabled(false); - } + constructor(private page: Page) {} async navigateTo() { - await browser.get('/'); - const EC = ExpectedConditions; - await browser.wait( - ExpectedConditions.elementToBeClickable(element(by.css('app-window'))), - 5000 - ); + await this.page.goto('/'); + await this.page.waitForSelector('app-window'); } getParagraphText() { - return element(by.css('app-root h1')).getText(); + return this.page.locator('app-root h1').textContent(); } getWindows() { - return element(by.css('app-window')); + return this.page.locator('app-window'); } title() { - return browser.getTitle(); + return this.page.title(); } } diff --git a/packages/altair-app/package.json b/packages/altair-app/package.json index 4acd28c2c3..3b6634a6c5 100644 --- a/packages/altair-app/package.json +++ b/packages/altair-app/package.json @@ -17,26 +17,23 @@ "test-build": "ng lint && yarn build && yarn test-single-run", "postinstall": "yarn generate-settings-schema-validator", "lint": "ng lint", - "e2e": "ng e2e", - "e2e:ci": "ng e2e --webdriver-update=false", "generate-settings-schema-validator": "./scripts/generate-settings-schema.sh", "analyze": "ng build --stats-json && npx webpack-bundle-analyzer dist/stats.json", - "analyze:prod": "ng build --aot --stats-json && npx webpack-bundle-analyzer dist/stats.json", - "webdriver-update-ci": "webdriver-manager update --standalone false --gecko false --versions.chrome=109.0.5414.119" + "analyze:prod": "ng build --aot --stats-json && npx webpack-bundle-analyzer dist/stats.json" }, "dependencies": { "@altairgraphql/api-utils": "^5.0.18", "@altairgraphql/db": "^5.0.18", - "@angular/animations": "14.0.3", + "@angular/animations": "15.2.3", "@angular/cdk": "12.2.6", - "@angular/cli": "14.0.3", - "@angular/common": "14.0.3", - "@angular/core": "14.0.3", - "@angular/forms": "14.0.3", - "@angular/platform-browser": "14.0.3", - "@angular/platform-browser-dynamic": "14.0.3", - "@angular/platform-server": "14.0.3", - "@angular/router": "14.0.3", + "@angular/cli": "15.2.4", + "@angular/common": "15.2.3", + "@angular/core": "^15.2.3", + "@angular/forms": "15.2.3", + "@angular/platform-browser": "15.2.3", + "@angular/platform-browser-dynamic": "15.2.3", + "@angular/platform-server": "15.2.3", + "@angular/router": "15.2.3", "@apollo/client": "3.5.6", "@codemirror/autocomplete": "6.0.1", "@codemirror/commands": "6.0.1", @@ -54,9 +51,9 @@ "@ngneat/hot-toast": "2.0.1", "@ngneat/overview": "1.0.0", "@ngneat/until-destroy": "8.0.1", - "@ngrx/effects": "12.4.0", - "@ngrx/store": "12.4.0", - "@ngrx/store-devtools": "12.4.0", + "@ngrx/effects": "15.4.0", + "@ngrx/store": "15.4.0", + "@ngrx/store-devtools": "15.4.0", "@ngui/auto-complete": "3.0.0", "@ngx-translate/core": "12.1.2", "@ngx-translate/http-loader": "4.0.0", @@ -125,17 +122,18 @@ "zone.js": "0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "14.0.3", - "@angular-eslint/builder": "14.0.0", - "@angular-eslint/eslint-plugin": "14.0.0", - "@angular-eslint/eslint-plugin-template": "14.0.0", - "@angular-eslint/schematics": "14.0.0", - "@angular-eslint/template-parser": "14.0.0", - "@angular/compiler": "14.0.3", - "@angular/compiler-cli": "14.0.3", + "@angular-devkit/build-angular": "15.2.4", + "@angular-eslint/builder": "15.2.1", + "@angular-eslint/eslint-plugin": "15.2.1", + "@angular-eslint/eslint-plugin-template": "15.2.1", + "@angular-eslint/schematics": "15.2.1", + "@angular-eslint/template-parser": "15.2.1", + "@angular/compiler": "15.2.3", + "@angular/compiler-cli": "15.2.3", "@briebug/jest-schematic": "2.1.1", "@jest/globals": "28.1.3", "@ngrx/schematics": "12.4.0", + "@playwright/test": "^1.31.2", "@types/actioncable": "5.2.3", "@types/chrome": "^0.0.209", "@types/crypto-js": "^4.0.1", @@ -143,7 +141,6 @@ "@types/file-saver": "^2.0.1", "@types/firefox-webext-browser": "^109.0.0", "@types/graphql": "^14.5.0", - "@types/jasmine": "~3.6.0", "@types/jest": "26.0.0", "@types/json-schema": "^7.0.6", "@types/lodash-es": "^4.17.4", @@ -173,11 +170,9 @@ "eslint-plugin-no-unsanitized": "^4.0.2", "eslint-plugin-prettier": "4.0.0", "fake-indexeddb": "3.1.7", - "jasmine-core": "~3.6.0", - "jasmine-spec-reporter": "~5.0.0", - "jest": "28.0.0", + "jest": "29.4.1", "jest-chrome": "^0.8.0", - "jest-preset-angular": "12.2.0", + "jest-preset-angular": "12.2.6", "karma-cli": "^2.0.0", "ncp": "2.0.0", "ng-mocks": "14.0.1", @@ -187,10 +182,10 @@ "react": "17.0.1", "rxjs-tslint-rules": "4.32.0", "start-server-and-test": "1.11.0", - "ts-jest": "28.0.7", + "ts-jest": "29.0.5", "ts-mocks": "2.6.1", "ts-node": "9.1.1", - "typescript": "4.6.4", + "typescript": "4.9.5", "typescript-json-schema": "0.50.1" }, "private": true, diff --git a/packages/altair-app/protractor.conf.js b/packages/altair-app/protractor.conf.js deleted file mode 100644 index 657f5143d1..0000000000 --- a/packages/altair-app/protractor.conf.js +++ /dev/null @@ -1,30 +0,0 @@ -// Protractor configuration file, see link for more information -// https://github.com/angular/protractor/blob/master/lib/config.ts - -const { SpecReporter } = require('jasmine-spec-reporter'); - -exports.config = { - allScriptsTimeout: 11000, - specs: ['./e2e/**/*.e2e-spec.ts'], - capabilities: { - browserName: 'chrome', - }, - directConnect: true, - baseUrl: 'http://localhost:4200/', - framework: 'jasmine', - jasmineNodeOpts: { - showColors: true, - defaultTimeoutInterval: 30000, - print: function () {}, - }, - beforeLaunch: function () { - require('ts-node').register({ - project: 'e2e/tsconfig.e2e.json', - }); - }, - onPrepare() { - jasmine - .getEnv() - .addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); - }, -}; diff --git a/packages/altair-app/src/app/modules/altair/components/header/header.component.html b/packages/altair-app/src/app/modules/altair/components/header/header.component.html index cd068e1a9f..01eb626dd4 100644 --- a/packages/altair-app/src/app/modules/altair/components/header/header.component.html +++ b/packages/altair-app/src/app/modules/altair/components/header/header.component.html @@ -59,7 +59,7 @@ > - {{ activeEnvironment?.title }} + {{ activeEnvironment.title }} diff --git a/packages/altair-app/src/app/modules/altair/components/plugin-manager/plugin-manager.component.html b/packages/altair-app/src/app/modules/altair/components/plugin-manager/plugin-manager.component.html index 2cc3737743..0793a56d36 100644 --- a/packages/altair-app/src/app/modules/altair/components/plugin-manager/plugin-manager.component.html +++ b/packages/altair-app/src/app/modules/altair/components/plugin-manager/plugin-manager.component.html @@ -43,7 +43,7 @@
{{ - selectedPluginItem?.manifest?.display_name || + selectedPluginItem.manifest.display_name || selectedPluginItem.name }}
diff --git a/packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.html b/packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.html index 5774cfc64c..7f24afac7a 100644 --- a/packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.html +++ b/packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.html @@ -83,7 +83,7 @@
@@ -146,7 +146,7 @@
diff --git a/packages/altair-app/src/app/modules/altair/effects/account.effect.ts b/packages/altair-app/src/app/modules/altair/effects/account.effect.ts index 110f8526e3..082d12aaf2 100644 --- a/packages/altair-app/src/app/modules/altair/effects/account.effect.ts +++ b/packages/altair-app/src/app/modules/altair/effects/account.effect.ts @@ -91,7 +91,8 @@ export class AccountEffects { }), catchError((error) => { debug.error(error); - this.notifyService.error( + this.notifyService.errorWithError( + error, 'Sorry, we could not log you in. Please check that your username and password are correct' ); return EMPTY; @@ -126,7 +127,8 @@ export class AccountEffects { }), catchError((error) => { debug.error(error); - this.notifyService.error( + this.notifyService.errorWithError( + error, 'Sorry, we could not log you out. Please try again.' ); return EMPTY; @@ -153,7 +155,7 @@ export class AccountEffects { ), catchError((err: UnknownError) => { debug.error(err); - this.notifyService.error('Could not load teams'); + this.notifyService.errorWithError(err, 'Could not load teams'); return EMPTY; }), repeat() diff --git a/packages/altair-app/src/app/modules/altair/effects/query-collection.effect.ts b/packages/altair-app/src/app/modules/altair/effects/query-collection.effect.ts index 264c792198..1fd011befa 100644 --- a/packages/altair-app/src/app/modules/altair/effects/query-collection.effect.ts +++ b/packages/altair-app/src/app/modules/altair/effects/query-collection.effect.ts @@ -19,6 +19,7 @@ import * as collectionActions from '../store/collection/collection.action'; import * as accountActions from '../store/account/account.action'; import * as dialogsActions from '../store/dialogs/dialogs.action'; import * as windowsMetaActions from '../store/windows-meta/windows-meta.action'; +import * as windowsActions from '../store/windows/windows.action'; import * as localActions from '../store/local/local.action'; import * as layoutActions from '../store/layout/layout.action'; import { @@ -106,7 +107,7 @@ export class QueryCollectionEffects { map(() => new collectionActions.LoadCollectionsAction()), catchError((err: UnknownError) => { debug.error(err); - this.notifyService.error('Could not create collection'); + this.notifyService.errorWithError(err, 'Could not create collection'); return EMPTY; }), repeat() @@ -153,7 +154,10 @@ export class QueryCollectionEffects { map(() => new collectionActions.LoadCollectionsAction()), catchError((err: UnknownError) => { debug.error(err); - this.notifyService.error('Could not add query to collection'); + this.notifyService.errorWithError( + err, + 'Could not add query to collection' + ); return EMPTY; }), repeat() @@ -209,7 +213,10 @@ export class QueryCollectionEffects { map(() => new collectionActions.LoadCollectionsAction()), catchError((err: UnknownError) => { debug.error(err); - this.notifyService.error('Could not update query in collection'); + this.notifyService.errorWithError( + err, + 'Could not update query in collection' + ); return EMPTY; }), repeat() @@ -224,9 +231,12 @@ export class QueryCollectionEffects { (collections) => new collectionActions.SetCollectionsAction({ collections }) ), + tap(() => { + this.store.dispatch(new windowsActions.ReloadCollectionWindowsAction()); + }), catchError((err: UnknownError) => { debug.error(err); - this.notifyService.error('Could not load collection'); + this.notifyService.errorWithError(err, 'Could not load collection'); return EMPTY; }), repeat() @@ -246,7 +256,10 @@ export class QueryCollectionEffects { map(() => new collectionActions.LoadCollectionsAction()), catchError((err: UnknownError) => { debug.error(err); - this.notifyService.error('Could not delete query from collection'); + this.notifyService.errorWithError( + err, + 'Could not delete query from collection' + ); return EMPTY; }), repeat() @@ -266,7 +279,7 @@ export class QueryCollectionEffects { map(() => new collectionActions.LoadCollectionsAction()), catchError((err: UnknownError) => { debug.error(err); - this.notifyService.error('Could not update collection'); + this.notifyService.errorWithError(err, 'Could not update collection'); return EMPTY; }), repeat() @@ -285,7 +298,10 @@ export class QueryCollectionEffects { map(() => new collectionActions.LoadCollectionsAction()), catchError((err: UnknownError) => { debug.error(err); - this.notifyService.error('Could not delete query from collection'); + this.notifyService.errorWithError( + err, + 'Could not delete query from collection' + ); return EMPTY; }), repeat() @@ -309,7 +325,7 @@ export class QueryCollectionEffects { }), catchError((err: UnknownError) => { debug.error(err); - this.notifyService.error('Could not export collection'); + this.notifyService.errorWithError(err, 'Could not export collection'); return EMPTY; }), repeat() @@ -339,7 +355,10 @@ export class QueryCollectionEffects { map(() => new collectionActions.LoadCollectionsAction()), catchError((error) => { debug.error(error); - this.notifyService.error(`Something went wrong importing collection`); + this.notifyService.errorWithError( + error, + `Something went wrong importing collection` + ); return EMPTY; }), repeat() @@ -359,7 +378,8 @@ export class QueryCollectionEffects { map(() => new collectionActions.LoadCollectionsAction()), catchError((error) => { debug.error(error); - this.notifyService.error( + this.notifyService.errorWithError( + error, `Something went wrong syncing remote collections.` ); return EMPTY; @@ -379,7 +399,8 @@ export class QueryCollectionEffects { }), catchError((error) => { debug.error(error); - this.notifyService.error( + this.notifyService.errorWithError( + error, `Something went wrong syncing remote collections.` ); return EMPTY; @@ -409,7 +430,7 @@ export class QueryCollectionEffects { map(() => new collectionActions.LoadCollectionsAction()), catchError((err: UnknownError) => { debug.error(err); - this.notifyService.error('Could not sync collection'); + this.notifyService.errorWithError(err, 'Could not sync collection'); return EMPTY; }), repeat() diff --git a/packages/altair-app/src/app/modules/altair/effects/query.effect.ts b/packages/altair-app/src/app/modules/altair/effects/query.effect.ts index 3eaee268d8..46a2dfdba8 100644 --- a/packages/altair-app/src/app/modules/altair/effects/query.effect.ts +++ b/packages/altair-app/src/app/modules/altair/effects/query.effect.ts @@ -221,7 +221,10 @@ export class QueryEffects { ) ); debug.error(err); - this.notifyService.error('Could not select operation'); + this.notifyService.errorWithError( + err, + 'Could not select operation' + ); return EMPTY; } @@ -237,7 +240,8 @@ export class QueryEffects { JSON.parse(variables); } } catch (err) { - this.notifyService.error( + this.notifyService.errorWithError( + err, 'Looks like your variables is not a valid JSON string.' ); this.store.dispatch( @@ -470,7 +474,10 @@ export class QueryEffects { }) .catch((error) => { debug.error(error); - this.notifyService.error(`Could not set schema SDL.`); + this.notifyService.errorWithError( + error, + `Could not set schema SDL.` + ); }); } @@ -497,7 +504,8 @@ export class QueryEffects { } } catch (error) { debug.error(error); - this.notifyService.error( + this.notifyService.errorWithError( + error, `There was a problem loading the schema.` ); debug.error('Error while loading schema', error); @@ -617,11 +625,13 @@ export class QueryEffects { Please check with the server administrator. `); } else { - debug.error(err); - this.notifyService.error(` + this.notifyService.errorWithError( + err, + ` Seems like something is broken. Please check that the URL is valid, and the server is up and running properly. - `); + ` + ); } return of(null); } @@ -700,7 +710,8 @@ export class QueryEffects { }), catchError((error: UnknownError) => { debug.error(error); - this.notifyService.error( + this.notifyService.errorWithError( + error, 'Error getting the introspection results.' ); return EMPTY; @@ -908,7 +919,7 @@ export class QueryEffects { }) ); debug.error(err); - this.notifyService.error(`Could not select operation.`); + this.notifyService.errorWithError(err, `Could not select operation.`); return EMPTY; } @@ -1099,8 +1110,8 @@ export class QueryEffects { const errorMessage = error.message ? error.message : error.toString(); - debug.error(error); - this.notifyService.error( + this.notifyService.errorWithError( + error, `Your query does not appear to be valid. Please check it` ); }); @@ -1137,12 +1148,8 @@ export class QueryEffects { } }) .catch((error) => { - debug.log(error); - const errorMessage = error.message - ? error.message - : error.toString(); - debug.error(error); - this.notifyService.error( + this.notifyService.errorWithError( + error, `Your query does not appear to be valid. Please check it.` ); }); @@ -1178,11 +1185,8 @@ export class QueryEffects { } }) .catch((error) => { - const errorMessage = error.message - ? error.message - : error.toString(); - debug.error(error); - this.notifyService.error( + this.notifyService.errorWithError( + error, `Could not export SDL. Your schema might be invalid.` ); }); @@ -1263,8 +1267,10 @@ export class QueryEffects { copyToClipboard(curlCommand); this.notifyService.success('Copied cURL command to clipboard.'); } catch (err) { - debug.log('Error while copying as curl', err); - this.notifyService.error('Error while copying as curl'); + this.notifyService.errorWithError( + err, + 'Error while copying as curl' + ); } return EMPTY; }) @@ -1294,8 +1300,8 @@ export class QueryEffects { ); } } catch (error) { - debug.log(error); - this.notifyService.error( + this.notifyService.errorWithError( + error, `Your query does not appear to be valid. Please check it.` ); } @@ -1344,7 +1350,8 @@ export class QueryEffects { ) ); } catch (err) { - this.notifyService.error( + this.notifyService.errorWithError( + err, 'Looks like your variables are not formatted properly' ); return EMPTY; @@ -1358,8 +1365,8 @@ export class QueryEffects { } } } catch (error) { - debug.log(error); - this.notifyService.error( + this.notifyService.errorWithError( + error, `Your query does not appear to be valid. Please check it.` ); } diff --git a/packages/altair-app/src/app/modules/altair/effects/windows.effect.ts b/packages/altair-app/src/app/modules/altair/effects/windows.effect.ts index ff10e47fdf..5e0474cc71 100644 --- a/packages/altair-app/src/app/modules/altair/effects/windows.effect.ts +++ b/packages/altair-app/src/app/modules/altair/effects/windows.effect.ts @@ -182,6 +182,46 @@ export class WindowsEffects { { dispatch: false } ); + reloadCollectionWindows$: Observable = createEffect( + () => { + return this.actions$.pipe( + ofType(windowActions.RELOAD_COLLECTION_WINDOWS), + withLatestFrom( + this.store, + (action: windowActions.ReloadCollectionWindowsAction, state) => { + return { + windows: state.windows, + collection: state.collection, + action, + }; + } + ), + switchMap((data) => { + Object.values(data.windows).forEach((window) => { + if ( + !window.layout.collectionId || + !window.layout.windowIdInCollection + ) { + return; + } + const collection = data.collection.list.find( + (c) => c.id === window.layout.collectionId + ); + const payload = collection?.queries.find( + (q) => q.id === window.layout.windowIdInCollection + ); + + if (payload) { + this.windowService.updateWindowState(window.windowId, payload); + } + }); + return EMPTY; + }) + ); + }, + { dispatch: false } + ); + constructor( private actions$: Actions, private store: Store, diff --git a/packages/altair-app/src/app/modules/altair/services/gql/__snapshots__/generateQuery.spec.ts.snap b/packages/altair-app/src/app/modules/altair/services/gql/__snapshots__/generateQuery.spec.ts.snap index bbeb08ccd3..797e8bb5f7 100644 --- a/packages/altair-app/src/app/modules/altair/services/gql/__snapshots__/generateQuery.spec.ts.snap +++ b/packages/altair-app/src/app/modules/altair/services/gql/__snapshots__/generateQuery.spec.ts.snap @@ -441,7 +441,7 @@ exports[`generateQuery fragment generates expected fragment with specified tab s exports[`generateQuery query generates expected query 1`] = ` "{ - GOTHouses(name: \\"string\\") { + GOTHouses(name: "string") { id url name @@ -484,7 +484,7 @@ exports[`generateQuery query generates expected query with default enum argument exports[`generateQuery query generates expected query with default string argument 1`] = ` "{ - GOTBooks(name: \\"my-book\\") { + GOTBooks(name: "my-book") { id url name @@ -526,7 +526,7 @@ exports[`generateQuery query generates expected query with int argument 1`] = ` exports[`generateQuery query generates expected query with list argument 1`] = ` "{ - withStringList(list: [\\"string\\"]) { + withStringList(list: ["string"]) { id url name @@ -575,7 +575,7 @@ exports[`generateQuery query generates expected query with object argument 1`] = exports[`generateQuery query generates expected query with specified max depth 1`] = ` "{ - GOTHouses(name: \\"string\\") { + GOTHouses(name: "string") { id url name @@ -980,7 +980,7 @@ exports[`generateQuery query generates expected query with specified max depth 1 exports[`generateQuery query generates expected query with specified tab size 1`] = ` "{ - GOTHouses(name: \\"string\\") { + GOTHouses(name: "string") { id url name @@ -997,7 +997,7 @@ exports[`generateQuery query generates expected query with specified tab size 1` exports[`generateQuery query generates expected query with string argument 1`] = ` "{ - withString(name: \\"string\\") { + withString(name: "string") { id url name diff --git a/packages/altair-app/src/app/modules/altair/services/gql/__snapshots__/gql.service.spec.ts.snap b/packages/altair-app/src/app/modules/altair/services/gql/__snapshots__/gql.service.spec.ts.snap index a4ff1f5407..b2c8497fd8 100644 --- a/packages/altair-app/src/app/modules/altair/services/gql/__snapshots__/gql.service.spec.ts.snap +++ b/packages/altair-app/src/app/modules/altair/services/gql/__snapshots__/gql.service.spec.ts.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`GqlService .fillAllFields() should return query with fields filled 1`] = ` -Object { - "insertions": Array [ - Object { +{ + "insertions": [ + { "index": 51, "string": " { id @@ -20,7 +20,7 @@ Object { ], "result": " query { - GOTHouses(name: \\"first\\") { + GOTHouses(name: "first") { id url name @@ -39,18 +39,18 @@ Object { exports[`GqlService .getIntrospectionSchema() should return schema for introspection data 1`] = ` GraphQLSchema { "__validationErrors": undefined, - "_directives": Array [ + "_directives": [ "@cacheControl", "@skip", "@include", "@deprecated", ], - "_implementationsMap": Object {}, + "_implementationsMap": {}, "_mutationType": "Mutation", "_queryType": "Query", - "_subTypeMap": Object {}, + "_subTypeMap": {}, "_subscriptionType": "Subscription", - "_typeMap": Object { + "_typeMap": { "Boolean": "Boolean", "CacheControlScope": "CacheControlScope", "File": "File", @@ -82,36 +82,36 @@ GraphQLSchema { `; exports[`GqlService .parseQuery() should return GraphQL document 1`] = ` -Object { - "definitions": Array [ - Object { - "directives": Array [], +{ + "definitions": [ + { + "directives": [], "kind": "OperationDefinition", - "loc": Object { + "loc": { "end": 42, "start": 9, }, "name": undefined, "operation": "query", - "selectionSet": Object { + "selectionSet": { "kind": "SelectionSet", - "loc": Object { + "loc": { "end": 42, "start": 15, }, - "selections": Array [ - Object { + "selections": [ + { "alias": undefined, - "arguments": Array [], - "directives": Array [], + "arguments": [], + "directives": [], "kind": "Field", - "loc": Object { + "loc": { "end": 32, "start": 27, }, - "name": Object { + "name": { "kind": "Name", - "loc": Object { + "loc": { "end": 32, "start": 27, }, @@ -121,11 +121,11 @@ Object { }, ], }, - "variableDefinitions": Array [], + "variableDefinitions": [], }, ], "kind": "Document", - "loc": Object { + "loc": { "end": 49, "start": 0, }, @@ -158,7 +158,7 @@ fragment GOTHouseFields on GOTHouse { `; exports[`GqlService .refactorQuery() should return edited query with generated name 2`] = ` -Object { +{ "name": "first", "name2000": "second", } diff --git a/packages/altair-app/src/app/modules/altair/services/notify/notify.service.ts b/packages/altair-app/src/app/modules/altair/services/notify/notify.service.ts index 25b84c8d0c..85b0827529 100644 --- a/packages/altair-app/src/app/modules/altair/services/notify/notify.service.ts +++ b/packages/altair-app/src/app/modules/altair/services/notify/notify.service.ts @@ -8,6 +8,8 @@ import { IDictionary } from '../../interfaces/shared'; import { first, take } from 'rxjs/operators'; import { RootState } from 'altair-graphql-core/build/types/state/state.interfaces'; import { ConfirmToastComponent } from '../../components/confirm-toast/confirm-toast.component'; +import sanitize from 'sanitize-html'; +import { debug } from '../../utils/logger'; interface PushNotifyOptions { onclick?: () => void; @@ -33,6 +35,16 @@ export class NotifyService { error(message: string, title = '', opts: NotifyOptions = {}) { this.exec('error', message, title, opts); } + + errorWithError( + err: unknown, + message: string, + title = '', + opts: NotifyOptions = {} + ) { + debug.error(err); + this.exec('error', this.calculateErrorMessage(err) ?? message, title, opts); + } warning(message: string, title = '', opts: NotifyOptions = {}) { this.store .select((state) => state.settings['alert.disableWarnings']) @@ -198,4 +210,27 @@ export class NotifyService { } ); } + + private calculateErrorMessage(err: unknown) { + if (!err) { + return; + } + if (typeof err === 'string') { + return sanitize(err); + } + + if (typeof err === 'object') { + if ('error' in err && err.error && typeof err.error === 'object') { + if ('code' in err.error && 'message' in err.error) { + if (typeof err.error.message === 'string') { + return sanitize(err.error.message); + } + } + } + + if ('message' in err && typeof err.message === 'string') { + return sanitize(err.message); + } + } + } } diff --git a/packages/altair-app/src/app/modules/altair/services/pre-request/pre-request.service.ts b/packages/altair-app/src/app/modules/altair/services/pre-request/pre-request.service.ts index cb8e13e1fe..f1f3efa5af 100644 --- a/packages/altair-app/src/app/modules/altair/services/pre-request/pre-request.service.ts +++ b/packages/altair-app/src/app/modules/altair/services/pre-request/pre-request.service.ts @@ -152,7 +152,8 @@ export class PreRequestService { 'Request script' ); } catch (error) { - this.notifyService.error( + this.notifyService.errorWithError( + error, `Could not update active environment variables.`, 'Request script' ); diff --git a/packages/altair-app/src/app/modules/altair/services/window.service.ts b/packages/altair-app/src/app/modules/altair/services/window.service.ts index b68e120d89..5ff51356b3 100644 --- a/packages/altair-app/src/app/modules/altair/services/window.service.ts +++ b/packages/altair-app/src/app/modules/altair/services/window.service.ts @@ -242,107 +242,120 @@ export class WindowService { }).subscribe((newWindow) => { const windowId = newWindow.windowId; - if (data.apiUrl) { - this.store.dispatch( - new queryActions.SetUrlAction({ url: data.apiUrl }, windowId) - ); - this.store.dispatch( - new queryActions.SendIntrospectionQueryRequestAction(windowId) - ); - } + this.updateWindowState(windowId, data); - if (data.query) { - this.store.dispatch( - new queryActions.SetQueryAction(data.query, windowId) - ); - } + this.store.dispatch( + new windowsMetaActions.SetActiveWindowIdAction({ windowId }) + ); + }); + } catch (err) { + debug.log('Something went wrong while importing the data.', err); + } + } - if (data.headers.length) { - this.store.dispatch( - new headerActions.SetHeadersAction( - { headers: data.headers }, - windowId - ) - ); - } + updateWindowState(windowId: string, data: ExportWindowState) { + this.getWindowState(windowId).subscribe((window) => { + this.store.dispatch( + new layoutActions.SetWindowNameAction(windowId, { + title: data.windowName, + setByUser: true, + }) + ); - if (data.variables) { - this.store.dispatch( - new variableActions.UpdateVariablesAction(data.variables, windowId) - ); - this.store.dispatch( - new dialogsActions.ToggleVariableDialogAction(windowId) - ); - } + if (data.apiUrl && data.apiUrl !== window?.query.url) { + this.store.dispatch( + new queryActions.SetUrlAction({ url: data.apiUrl }, windowId) + ); + this.store.dispatch( + new queryActions.SendIntrospectionQueryRequestAction(windowId) + ); + } - if (data.subscriptionUrl) { - this.store.dispatch( - new queryActions.SetSubscriptionUrlAction( - { subscriptionUrl: data.subscriptionUrl }, - windowId - ) - ); - } + if (data.query) { + this.store.dispatch( + new queryActions.SetQueryAction(data.query, windowId) + ); + } - if (data.subscriptionConnectionParams) { - this.store.dispatch( - new queryActions.SetSubscriptionConnectionParamsAction(windowId, { - connectionParams: data.subscriptionConnectionParams, - }) - ); - } + if (data.headers.length) { + this.store.dispatch( + new headerActions.SetHeadersAction( + { headers: data.headers }, + windowId + ) + ); + } - if (data.subscriptionProvider) { - this.store.dispatch( - new queryActions.SetSubscriptionProviderIdAction(windowId, { - providerId: data.subscriptionProvider, - }) - ); - } + if (data.variables) { + this.store.dispatch( + new variableActions.UpdateVariablesAction(data.variables, windowId) + ); + this.store.dispatch( + new dialogsActions.ToggleVariableDialogAction(windowId) + ); + } - if (data.preRequestScriptEnabled) { - this.store.dispatch( - new preRequestActions.SetPreRequestEnabledAction(windowId, { - enabled: data.preRequestScriptEnabled, - }) - ); - } - if (data.preRequestScript) { - this.store.dispatch( - new preRequestActions.SetPreRequestScriptAction(windowId, { - script: data.preRequestScript, - }) - ); - } + if (data.subscriptionUrl) { + this.store.dispatch( + new queryActions.SetSubscriptionUrlAction( + { subscriptionUrl: data.subscriptionUrl }, + windowId + ) + ); + } - if (data.postRequestScriptEnabled) { - this.store.dispatch( - new postRequestActions.SetPostRequestEnabledAction(windowId, { - enabled: data.postRequestScriptEnabled, - }) - ); - } - if (data.postRequestScript) { - this.store.dispatch( - new postRequestActions.SetPostRequestScriptAction(windowId, { - script: data.postRequestScript, - }) - ); - } + if (data.subscriptionConnectionParams) { + this.store.dispatch( + new queryActions.SetSubscriptionConnectionParamsAction(windowId, { + connectionParams: data.subscriptionConnectionParams, + }) + ); + } - if (data.gqlSchema) { - this.store.dispatch( - new gqlSchemaActions.SetSchemaAction(windowId, data.gqlSchema) - ); - } + if (data.subscriptionProvider) { + this.store.dispatch( + new queryActions.SetSubscriptionProviderIdAction(windowId, { + providerId: data.subscriptionProvider, + }) + ); + } + if (data.preRequestScriptEnabled) { this.store.dispatch( - new windowsMetaActions.SetActiveWindowIdAction({ windowId }) + new preRequestActions.SetPreRequestEnabledAction(windowId, { + enabled: data.preRequestScriptEnabled, + }) ); - }); - } catch (err) { - debug.log('Something went wrong while importing the data.', err); - } + } + if (data.preRequestScript) { + this.store.dispatch( + new preRequestActions.SetPreRequestScriptAction(windowId, { + script: data.preRequestScript, + }) + ); + } + + if (data.postRequestScriptEnabled) { + this.store.dispatch( + new postRequestActions.SetPostRequestEnabledAction(windowId, { + enabled: data.postRequestScriptEnabled, + }) + ); + } + if (data.postRequestScript) { + this.store.dispatch( + new postRequestActions.SetPostRequestScriptAction(windowId, { + script: data.postRequestScript, + }) + ); + } + + if (data.gqlSchema) { + this.store.dispatch( + new gqlSchemaActions.SetSchemaAction(windowId, data.gqlSchema) + ); + } + }); } /** diff --git a/packages/altair-app/src/app/modules/altair/store/index.ts b/packages/altair-app/src/app/modules/altair/store/index.ts index bc1fe3ad0b..35ccab8072 100644 --- a/packages/altair-app/src/app/modules/altair/store/index.ts +++ b/packages/altair-app/src/app/modules/altair/store/index.ts @@ -72,12 +72,12 @@ export function log( } export function asyncStorageSyncReducer( - _reducer: ActionReducer -): ActionReducer { + _reducer: ActionReducer +): ActionReducer { return asyncStorageSync(localStorageSyncConfig)(_reducer); } -export const metaReducers: MetaReducer[] = [ +export const metaReducers: MetaReducer[] = [ asyncStorageSyncReducer, // !environment.production ? storeFreeze : null, log, diff --git a/packages/altair-app/src/app/modules/altair/store/windows/windows.action.ts b/packages/altair-app/src/app/modules/altair/store/windows/windows.action.ts index 0518562fed..b8723e6023 100644 --- a/packages/altair-app/src/app/modules/altair/store/windows/windows.action.ts +++ b/packages/altair-app/src/app/modules/altair/store/windows/windows.action.ts @@ -1,4 +1,6 @@ import { Action as NGRXAction } from '@ngrx/store'; +import { PerWindowState } from 'altair-graphql-core/build/types/state/per-window.interfaces'; +import { WindowState } from 'altair-graphql-core/build/types/state/window.interfaces'; export const ADD_WINDOW = 'ADD_WINDOW'; export const SET_WINDOWS = 'SET_WINDOWS'; @@ -7,8 +9,8 @@ export const REMOVE_WINDOW = 'REMOVE_WINDOW'; export const EXPORT_WINDOW = 'EXPORT_WINDOW'; export const IMPORT_WINDOW = 'IMPORT_WINDOW'; export const IMPORT_WINDOW_FROM_CURL = 'IMPORT_WINDOW_FROM_CURL'; - export const REOPEN_CLOSED_WINDOW = 'REOPEN_CLOSED_WINDOW'; +export const RELOAD_COLLECTION_WINDOWS = 'RELOAD_COLLECTION_WINDOWS'; interface AddWindowPayload { windowId: string; @@ -26,7 +28,7 @@ export class AddWindowAction implements NGRXAction { export class SetWindowsAction implements NGRXAction { readonly type = SET_WINDOWS; - constructor(public payload: Array) {} + constructor(public payload: PerWindowState[]) {} } export class RemoveWindowAction implements NGRXAction { @@ -55,6 +57,10 @@ export class ReopenClosedWindowAction implements NGRXAction { readonly type = REOPEN_CLOSED_WINDOW; } +export class ReloadCollectionWindowsAction implements NGRXAction { + readonly type = RELOAD_COLLECTION_WINDOWS; +} + export type Action = | AddWindowAction | SetWindowsAction @@ -62,4 +68,5 @@ export type Action = | ExportWindowAction | ImportWindowAction | ImportWindowFromCurlAction - | ReopenClosedWindowAction; + | ReopenClosedWindowAction + | ReloadCollectionWindowsAction; diff --git a/packages/altair-app/src/testing/__tests__/__snapshots__/utils.spec.ts.snap b/packages/altair-app/src/testing/__tests__/__snapshots__/utils.spec.ts.snap index c363cf50e6..ed91e95060 100644 --- a/packages/altair-app/src/testing/__tests__/__snapshots__/utils.spec.ts.snap +++ b/packages/altair-app/src/testing/__tests__/__snapshots__/utils.spec.ts.snap @@ -2,15 +2,15 @@ exports[`utils buildTestHostComponentTemplate should return expected template string 1`] = ` " -
+
" diff --git a/packages/altair-app/src/tsconfig.app.json b/packages/altair-app/src/tsconfig.app.json index 365a9abb18..af5db98575 100644 --- a/packages/altair-app/src/tsconfig.app.json +++ b/packages/altair-app/src/tsconfig.app.json @@ -2,10 +2,7 @@ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/app", - "baseUrl": "", - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "strictNullChecks": true + "baseUrl": "" }, "files": ["main.ts", "polyfills.ts"], "include": ["**/*.d.ts"] diff --git a/packages/altair-app/tsconfig.json b/packages/altair-app/tsconfig.json index 6358f48799..3eec802d6c 100644 --- a/packages/altair-app/tsconfig.json +++ b/packages/altair-app/tsconfig.json @@ -10,8 +10,9 @@ "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, - "target": "es2020", + "target": "ES2022", "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, // TODO: Consider figuring out if it's possible to fix the third party library typings so this can be removed "skipLibCheck": true, "resolveJsonModule": true, @@ -19,7 +20,10 @@ "types": ["jest", "node", "chrome", "firefox-webext-browser"], "downlevelIteration": true, "lib": ["es2017", "dom", "dom.iterable", "esnext", "esnext.asynciterable"], - "module": "es2020", + "module": "es2022", + "esModuleInterop": true, + "strictNullChecks": true, + "useDefineForClassFields": false }, "angularCompilerOptions": { "preserveWhitespaces": true, diff --git a/packages/altair-app/tsconfig.spec.json b/packages/altair-app/tsconfig.spec.json index f87cffc606..3b3fc413a9 100644 --- a/packages/altair-app/tsconfig.spec.json +++ b/packages/altair-app/tsconfig.spec.json @@ -6,7 +6,7 @@ "baseUrl": "./src", "module": "commonjs", "esModuleInterop": true, - "emitDecoratorMetadata": true, + "emitDecoratorMetadata": false, "allowJs": true }, "files": ["polyfills.ts"], diff --git a/packages/altair-core/src/types/state/window.interfaces.ts b/packages/altair-core/src/types/state/window.interfaces.ts index 145d09a1d5..29092715a0 100644 --- a/packages/altair-core/src/types/state/window.interfaces.ts +++ b/packages/altair-core/src/types/state/window.interfaces.ts @@ -3,7 +3,7 @@ import { SubscriptionProviderIds } from '../../subscriptions'; import { PerWindowState } from './per-window.interfaces'; export interface WindowState { - [id: string]: PerWindowState | undefined; + [id: string]: PerWindowState; } /** diff --git a/packages/altair-db/prisma/schema.prisma b/packages/altair-db/prisma/schema.prisma index 43879a4e7f..786f7bbdef 100644 --- a/packages/altair-db/prisma/schema.prisma +++ b/packages/altair-db/prisma/schema.prisma @@ -132,7 +132,7 @@ model PlanConfig { model UserPlan { userId String @unique planRole String // as defined in the Stripe product role metadata - quantity Int + quantity Int // indicates number of seats (used for determine maximum team member count) user User @relation(fields: [userId], references: [id]) planConfig PlanConfig @relation(fields: [planRole], references: [id]) } diff --git a/packages/altair-electron/package.json b/packages/altair-electron/package.json index 308a2e0ca7..6d54fcb2aa 100644 --- a/packages/altair-electron/package.json +++ b/packages/altair-electron/package.json @@ -38,7 +38,7 @@ }, "devDependencies": { "@jest/globals": "28.0.0", - "@playwright/test": "^1.16.3", + "@playwright/test": "1.31.2", "@types/jest": "^28.1.7", "@types/mime-types": "^2.1.1", "devtron": "^1.4.0", @@ -50,11 +50,11 @@ "electron-notarize": "^1.1.1", "electron-reloader": "^1.2.1", "eslint": "^7.3.1", - "jest": "28.0.0", + "jest": "29.4.1", "jest-circus": "28.0.0", "playwright": "^1.18.1", "spectron": "^15.0.0", - "ts-jest": "^28.0.8", + "ts-jest": "29.0.5", "typescript": "^4.9.4", "webdriverio": "^7.12.5" }, diff --git a/packages/altair-koa-middleware/package.json b/packages/altair-koa-middleware/package.json index 711e5ed6a1..1538da3207 100644 --- a/packages/altair-koa-middleware/package.json +++ b/packages/altair-koa-middleware/package.json @@ -40,11 +40,11 @@ "@types/koa-send": "^4.1.3", "@types/koa__router": "^8.0.8", "@types/supertest": "^2.0.11", - "jest": "28.0.0", + "jest": "29.4.1", "koa": "^2.13.1", "nodemon": "^2.0.12", "supertest": "^6.1.6", - "ts-jest": "28.0.7", + "ts-jest": "29.0.5", "ts-node": "^10.2.1", "typescript": "^4.9.4" }, diff --git a/packages/altair-static/package.json b/packages/altair-static/package.json index b1c650020b..90f76a8c67 100644 --- a/packages/altair-static/package.json +++ b/packages/altair-static/package.json @@ -35,8 +35,8 @@ "altair-graphql-core": "^5.0.18", "dts-bundle-generator": "^6.11.0", "esbuild": "^0.14.43", - "jest": "28.0.0", - "ts-jest": "28.0.7", + "jest": "29.4.1", + "ts-jest": "29.0.5", "typescript": "^4.9.4" }, "funding": { diff --git a/packages/altair-static/src/__snapshots__/index.test.ts.snap b/packages/altair-static/src/__snapshots__/index.test.ts.snap index bca0add90d..bb5efc841b 100644 --- a/packages/altair-static/src/__snapshots__/index.test.ts.snap +++ b/packages/altair-static/src/__snapshots__/index.test.ts.snap @@ -4,12 +4,12 @@ exports[`renderAltair should return expected string 1`] = ` " - + Altair - - - - + + + + @@ -20,36 +20,36 @@ exports[`renderAltair should return expected string 1`] = ` display: none; } -
-
-
- \\"Altair\\" +
+
+
+ Altair
-
- - - +
+ + +