From 278db4c57dbddf0bd812f8a71eb81d8676ed1df0 Mon Sep 17 00:00:00 2001 From: Samuel Imolorhe Date: Thu, 20 Feb 2025 01:07:04 +0100 Subject: [PATCH 1/2] Several minor improvements to the app Compute the window-in-collection state instead of storing in store Only save current window to collection and don't overwrite other unsaved windows Stop toggling variable dialog when saving to collection --- .../components/header/header.component.html | 29 +++++++------ .../components/header/header.component.ts | 2 + .../window-switcher.component.html | 10 ++++- .../window-switcher.component.ts | 41 +++++++++++++++---- .../containers/altair/altair.component.html | 3 +- .../altair/effects/query-collection.effect.ts | 1 + .../modules/altair/effects/windows.effect.ts | 3 +- .../modules/altair/services/window.service.ts | 40 ------------------ .../src/app/modules/altair/store/index.ts | 17 +------- .../modules/altair/store/windows/selectors.ts | 23 +++++++++++ 10 files changed, 88 insertions(+), 81 deletions(-) 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 3b179032e2..49a9cc39da 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 @@ -1,7 +1,7 @@
+ [ngClass]="{ 'header__logo-wrapper--experimental': settings?.enableExperimental }" +>
@@ -11,6 +11,7 @@ [activeWindowId]="activeWindowId" [closedWindows]="closedWindows" [isElectron]="isElectron" + [collections]="collections" [enableScrollbar]="settings?.enableTablistScrollbar" (newWindowChange)="newWindowChange.emit($event)" (activeWindowChange)="activeWindowChange.emit($event)" @@ -31,7 +32,7 @@ nzTooltipPlacement="bottom" class="header__menu-item" [ngClass]="{ 'header__menu-item--active': panel.isActive }" - > + > + >
{{ panel.title }}
@@ -58,7 +59,7 @@ nzTrigger="click" [nzDropdownMenu]="environmentsMenu" class="header__menu-item" - > + > @if (activeEnvironment) { @@ -76,20 +77,18 @@
    @if (environments?.subEnvironments?.length) { @for ( - environment of environments?.subEnvironments; track trackById($index, - environment)) { + environment of environments?.subEnvironments; + track trackById($index, environment) + ) {
  • + > {{ environment.title }}
  • } -
  • +
  • {{ 'NO_ENVIRONMENT_TEXT' | translate }}
  • @@ -104,7 +103,7 @@ nzTrigger="click" [nzDropdownMenu]="settingsMenu" class="header__menu-item" - > + > @@ -121,7 +120,7 @@
  • + > {{ 'STAR_ON_GITHUB_TEXT' | translate }}
  • + > {{ 'REPORT_BUG_TEXT' | translate }}
  • diff --git a/packages/altair-app/src/app/modules/altair/components/header/header.component.ts b/packages/altair-app/src/app/modules/altair/components/header/header.component.ts index e21c957c4b..822c14427f 100644 --- a/packages/altair-app/src/app/modules/altair/components/header/header.component.ts +++ b/packages/altair-app/src/app/modules/altair/components/header/header.component.ts @@ -8,6 +8,7 @@ import { PerWindowState } from 'altair-graphql-core/build/types/state/per-window import { SettingsState } from 'altair-graphql-core/build/types/state/settings.interfaces'; import { WindowState } from 'altair-graphql-core/build/types/state/window.interfaces'; import { externalLink } from '../../utils'; +import { IQueryCollection } from 'altair-graphql-core/build/types/state/collection.interfaces'; @Component({ selector: 'app-header', @@ -21,6 +22,7 @@ export class HeaderComponent { @Input() activeWindowId = ''; @Input() isElectron = false; @Input() headerPanels: AltairPanel[] = []; + @Input() collections: IQueryCollection[] = []; @Input() activeEnvironment?: EnvironmentState; @Input() environments?: EnvironmentsState; @Input() settings?: SettingsState; diff --git a/packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.html b/packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.html index b40602289f..a3d98932ef 100644 --- a/packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.html +++ b/packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.html @@ -15,7 +15,7 @@ (dblclick)="editWindowNameInput(windowId, wTitle)" (contextmenu)="contextMenu($event, tabContextMenu)" > - @if (windows[windowId]?.layout?.windowIdInCollection) { + @if (isWindowInCollection(windowId)) { {{ windows[windowId]?.layout?.title || '' }}
+ + * + @if (windowIds.length > 1) {
collection.id === collectionId + ); + + if (!collection) { + return false; + } + + return !!collection.queries.find((query) => query.id === windowIdInCollection); + } + + windowHasUnsavedChanges(windowId: string) { + const window = this.windows[windowId]; + if (!window) { + return false; + } + if (!this.isWindowInCollection(windowId)) { + return false; + } + return windowHasUnsavedChanges(window, this.collections); + } } diff --git a/packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html b/packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html index 6f922e71a2..9162260f5a 100644 --- a/packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html +++ b/packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html @@ -31,6 +31,7 @@ [activeEnvironment]="activeEnvironment$ | async" [environments]="environments$ | async" [settings]="settings$ | async" + [collections]="sortedCollections$ | async" (newWindowChange)="newWindow()" (activeWindowChange)="setActiveWindow($event)" (removeWindowChange)="removeWindow($event)" @@ -258,7 +259,7 @@ attr.aria-label="{{ 'ACCOUNT_TITLE' | translate }}" track-id="show_collections" [ngClass]="{ - 'side-menu-item--active': (account$ | async)?.loggedIn + 'side-menu-item--active': (account$ | async)?.loggedIn, }" >
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 0dc6259b04..2f239a6c7f 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 @@ -157,6 +157,7 @@ export class QueryCollectionEffects { ); }), tap(() => this.notifyService.success('Added query to collection.')), + // TODO: Reload only changed map(() => new collectionActions.LoadCollectionsAction()), catchError((err: UnknownError) => { return fromPromise(getErrorResponse(err)).pipe( 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 84f2c544c2..3c5e8dbc22 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 @@ -14,6 +14,7 @@ import { WindowService } from '../services/window.service'; import { downloadJson, openFile } from '../utils'; import { RootState } from 'altair-graphql-core/build/types/state/state.interfaces'; import { debug } from '../utils/logger'; +import { windowHasUnsavedChanges } from '../store'; @Injectable() export class WindowsEffects { @@ -202,7 +203,7 @@ export class WindowsEffects { (q) => q.id === window.layout.windowIdInCollection ); - if (payload) { + if (payload && !windowHasUnsavedChanges(window, data.collection.list)) { this.windowService .updateWindowState(window.windowId, payload) .catch((err) => { 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 dd69eb2a45..a9e0ba9b5d 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 @@ -300,9 +300,6 @@ export class WindowService { this.store.dispatch( new variableActions.UpdateVariablesAction(data.variables, windowId) ); - this.store.dispatch( - new dialogsActions.ToggleVariableDialogAction(windowId) - ); } if (data.subscriptionUrl) { this.store.dispatch( @@ -526,43 +523,6 @@ export class WindowService { * Carry out any necessary house cleaning tasks. */ setupWindow(windowId: string) { - // Validate that query is ACTUALLY in an existing collection - this.getWindowState(windowId) - .pipe( - switchMap((data) => { - if (data?.layout.collectionId && data?.layout.windowIdInCollection) { - return from( - this.collectionService.getCollectionByID(data.layout.collectionId) - ).pipe( - catchError(() => { - // continue to evaluation logic in map() below if collection is not found - // (EMPTY would stop the observable chain) - return of(undefined); - }), - map((collection) => { - if (collection) { - const query = collection.queries.find( - (q) => q.id === data.layout.windowIdInCollection - ); - return !!query; - } - - return false; - }) - ); - } - - return EMPTY; - }) - ) - .subscribe((isValidCollectionQuery) => { - if (!isValidCollectionQuery) { - this.store.dispatch( - new layoutActions.SetWindowIdInCollectionAction(windowId, {}) - ); - } - }); - this.store.dispatch(new streamActions.StopStreamClientAction(windowId)); this.store.dispatch(new streamActions.StartStreamClientAction(windowId)); 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 22d1f83912..5a2246cb56 100644 --- a/packages/altair-app/src/app/modules/altair/store/index.ts +++ b/packages/altair-app/src/app/modules/altair/store/index.ts @@ -36,7 +36,7 @@ import { asyncStorageSync } from './async-storage-sync'; import { localStorageSyncConfig } from './local-storage-sync-config'; import { RootState } from 'altair-graphql-core/build/types/state/state.interfaces'; import { AllActions } from './action'; -import { selectWindowState } from './windows/selectors'; +import { selectWindowState, windowHasUnsavedChanges } from './windows/selectors'; import { getQueryState } from './query/selectors'; import { selectCollections } from './collection/selectors'; import { str } from '../utils'; @@ -136,20 +136,7 @@ export const selectHasUnsavedChanges = (windowId: string) => { selectWindowState(windowId), selectCollections, (windowState, collections) => { - if (!windowState || !collections) { - return false; - } - const collection = collections.find( - (c) => str(c.id) === str(windowState.layout.collectionId) - ); - const queryInCollection = collection?.queries.find( - (q) => str(q.id) === str(windowState.layout.windowIdInCollection ?? '') - ); - - return ( - queryInCollection?.query !== windowState.query.query || - queryInCollection?.variables !== windowState.variables.variables - ); + return windowHasUnsavedChanges(windowState, collections); } ); }; diff --git a/packages/altair-app/src/app/modules/altair/store/windows/selectors.ts b/packages/altair-app/src/app/modules/altair/store/windows/selectors.ts index 832242f2d6..a9237c724b 100644 --- a/packages/altair-app/src/app/modules/altair/store/windows/selectors.ts +++ b/packages/altair-app/src/app/modules/altair/store/windows/selectors.ts @@ -1,5 +1,28 @@ +import { IQueryCollection } from 'altair-graphql-core/build/types/state/collection.interfaces'; +import { PerWindowState } from 'altair-graphql-core/build/types/state/per-window.interfaces'; import { RootState } from 'altair-graphql-core/build/types/state/state.interfaces'; +import { str } from '../../utils'; export const selectWindowState = (windowId: string) => (state: RootState) => { return state.windows[windowId]; }; + +export const windowHasUnsavedChanges = ( + windowState?: PerWindowState, + collections?: IQueryCollection[] +) => { + if (!windowState || !collections) { + return false; + } + const collection = collections.find( + (c) => str(c.id) === str(windowState.layout.collectionId) + ); + const queryInCollection = collection?.queries.find( + (q) => str(q.id) === str(windowState.layout.windowIdInCollection ?? '') + ); + + return ( + queryInCollection?.query !== windowState.query.query || + queryInCollection?.variables !== windowState.variables.variables + ); +}; From d87425c2b5bb7ddf67155f1348c9653c2e88a79e Mon Sep 17 00:00:00 2001 From: Samuel Imolorhe Date: Thu, 20 Feb 2025 01:15:41 +0100 Subject: [PATCH 2/2] removed unnecessary comment --- .../altair/effects/query-collection.effect.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) 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 2f239a6c7f..dac27d33cf 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 @@ -1,4 +1,4 @@ -import { EMPTY, Observable, of, zip, forkJoin, from, pipe } from 'rxjs'; +import { EMPTY, Observable, of, zip, forkJoin, from } from 'rxjs'; import { map, @@ -6,21 +6,16 @@ import { switchMap, tap, catchError, - filter, repeat, } from 'rxjs/operators'; import { Injectable } from '@angular/core'; import { Store, Action } from '@ngrx/store'; import { createEffect, Actions, ofType } from '@ngrx/effects'; -import * as fromRoot from '../store'; - 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 { QueryCollectionService, @@ -28,7 +23,7 @@ import { NotifyService, ApiService, } from '../services'; -import { downloadJson, fromPromise, openFile, openFiles } from '../utils'; +import { downloadJson, fromPromise, openFiles } from '../utils'; import { RootState } from 'altair-graphql-core/build/types/state/state.interfaces'; import { IQuery } from 'altair-graphql-core/build/types/state/collection.interfaces'; import { UnknownError } from '../interfaces/shared'; @@ -157,7 +152,6 @@ export class QueryCollectionEffects { ); }), tap(() => this.notifyService.success('Added query to collection.')), - // TODO: Reload only changed map(() => new collectionActions.LoadCollectionsAction()), catchError((err: UnknownError) => { return fromPromise(getErrorResponse(err)).pipe( @@ -438,7 +432,7 @@ export class QueryCollectionEffects { switchMap(() => { return this.apiService.listenForCollectionChanges(); }), - map((x) => { + map(() => { return new collectionActions.LoadCollectionsAction(); }), catchError((error) => {