Skip to content

Commit

Permalink
Added settings dialog and implemented dark theme.
Browse files Browse the repository at this point in the history
Added condition to run e2e only on linux.
Closes #200, #183.
  • Loading branch information
imolorhe committed Jan 13, 2018
1 parent 6552fe7 commit be9f25c
Show file tree
Hide file tree
Showing 22 changed files with 311 additions and 78 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -31,7 +31,7 @@ before_script:
script:
- ng lint
- if [[ "$TRAVIS_OS_NAME" = "linux" ]]; then karma start karma.conf.js --single-run; fi
- ng e2e
- if [[ "$TRAVIS_OS_NAME" = "linux" ]]; then ng e2e
before_deploy:
- if [ ! -z "$TRAVIS_TAG" ]; then npm run build-electron; fi
deploy:
Expand Down
6 changes: 5 additions & 1 deletion src/app/actions/layout/layout.ts
Expand Up @@ -29,4 +29,8 @@ export class NotifyExperimentalAction implements Action {
constructor(public windowId: string) {}
}

export type Action = StartLoadingAction | StopLoadingAction | SetWindowNameAction | NotifyExperimentalAction;
export type Action =
| StartLoadingAction
| StopLoadingAction
| SetWindowNameAction
| NotifyExperimentalAction;
33 changes: 33 additions & 0 deletions src/app/actions/settings/settings.ts
@@ -0,0 +1,33 @@
import { Action } from '@ngrx/store';

export const SHOW_SETTINGS = 'SHOW_SETTINGS';
export const HIDE_SETTINGS = 'HIDE_SETTINGS';

export const SET_THEME = 'SET_THEME';
export const SET_LANGUAGE = 'SET_LANGUAGE';

export class ShowSettingsAction implements Action {
readonly type = SHOW_SETTINGS;
}

export class HideSettingsAction implements Action {
readonly type = HIDE_SETTINGS;
}

export class SetThemeAction implements Action {
readonly type = SET_THEME;

constructor(public payload: { value: string }) {}
}

export class SetLanguageAction implements Action {
readonly type = SET_LANGUAGE;

constructor(public payload: { value: string }) { }
}

export type Action =
| ShowSettingsAction
| HideSettingsAction
| SetThemeAction
| SetLanguageAction;
42 changes: 22 additions & 20 deletions src/app/components/index.ts
Expand Up @@ -19,30 +19,32 @@ import { WindowSwitcherComponent } from './window-switcher/window-switcher.compo
import { SubscriptionUrlDialogComponent } from './subscription-url-dialog/subscription-url-dialog.component';
import { SubscriptionResultItemComponent } from './subscription-result-item/subscription-result-item.component';
import { HistoryDialogComponent } from './history-dialog/history-dialog.component';
import { SettingsDialogComponent } from './settings-dialog/settings-dialog.component';

const COMPONENTS = [
QueryEditorComponent,
QueryResultComponent,
ActionBarComponent,
SetVariableDialogComponent,
ForkRepoComponent,
WindowSwitcherComponent,
SubscriptionUrlDialogComponent,
SubscriptionResultItemComponent,
UrlBoxComponent,
HistoryDialogComponent
QueryEditorComponent,
QueryResultComponent,
ActionBarComponent,
SetVariableDialogComponent,
ForkRepoComponent,
WindowSwitcherComponent,
SubscriptionUrlDialogComponent,
SubscriptionResultItemComponent,
UrlBoxComponent,
HistoryDialogComponent,
SettingsDialogComponent
];

@NgModule({
imports: [
CommonModule,
FormsModule,
CodemirrorModule,
PipesModule,
SharedModule,
ClarityModule
],
declarations: COMPONENTS,
exports: [...COMPONENTS ]
imports: [
CommonModule,
FormsModule,
CodemirrorModule,
PipesModule,
SharedModule,
ClarityModule
],
declarations: COMPONENTS,
exports: [...COMPONENTS ]
})
export class ComponentModule {}
34 changes: 34 additions & 0 deletions src/app/components/settings-dialog/settings-dialog.component.html
@@ -0,0 +1,34 @@
<clr-modal [clrModalOpen]="settings.isShown" (clrModalOpenChange)="toggleDialogChange.next($event)">
<h3 class="modal-title">
<div class="app-dialog-header">
<div class="app-dialog-title">{{ 'SETTINGS_TEXT' | translate }}</div>
{{ 'SETTINGS_SUB_TEXT' | translate }}
</div>
</h3>
<div class="modal-body">
<div class="app-dialog-body">
<div class="app-dialog-section">
<label>{{ 'SETTINGS_THEME_TEXT' | translate }}</label>
<select class="dialog-select" (change)="onSelectTheme($event.target.value)">
<option *ngFor="let theme of themes" value="{{ theme }}" [selected]="theme === settings.theme">
{{ theme | titlecase }}
</option>
</select>
</div>

<div class="app-dialog-section">
<label>{{ 'SETTINGS_LANGUAGE_TEXT' | translate }}</label>
<select class="dialog-select" (change)="onSelectLanguage($event.target.value)">
<option *ngFor="let language of languages" value="{{ language[0] }}" [selected]="language === settings.language">
{{ language[1] | titlecase }}
</option>
</select>
</div>
</div>
</div>
<div class="modal-footer">
<div class="app-dialog-footer">
<button class="app-button active-primary right" (click)="toggleDialogChange.next(false)">{{ 'SAVE_BUTTON' | translate }}</button>
</div>
</div>
</clr-modal>
Empty file.
@@ -0,0 +1,36 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { FormsModule } from '@angular/forms';
import { ClarityModule } from 'clarity-angular';
import { CodemirrorModule } from 'ng2-codemirror';
import { TranslateModule } from '@ngx-translate/core';

import { SettingsDialogComponent } from './settings-dialog.component';

describe('SettingsDialogComponent', () => {
let component: SettingsDialogComponent;
let fixture: ComponentFixture<SettingsDialogComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SettingsDialogComponent ],
imports: [
FormsModule,
CodemirrorModule,
ClarityModule.forRoot(),
TranslateModule.forRoot()
]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(SettingsDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
33 changes: 33 additions & 0 deletions src/app/components/settings-dialog/settings-dialog.component.ts
@@ -0,0 +1,33 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';

import config from '../../config';

@Component({
selector: 'app-settings-dialog',
templateUrl: './settings-dialog.component.html',
styleUrls: ['./settings-dialog.component.scss']
})
export class SettingsDialogComponent implements OnInit {

@Input() settings = {};
@Output() toggleDialogChange = new EventEmitter();
@Output() themeChange = new EventEmitter();
@Output() languageChange = new EventEmitter();

themes = config.themes;
languages = Object.entries(config.languages);

constructor() {}

ngOnInit() {
}

onSelectTheme(theme) {
return this.themeChange.next(theme);
}

onSelectLanguage(language) {
return this.languageChange.next(language);
}

}
5 changes: 3 additions & 2 deletions src/app/config.ts
Expand Up @@ -5,6 +5,7 @@ export default {
add_query_depth_limit: 3,
max_windows: 10,
default_language: 'en',
languages: ['en'],
query_history_depth: isElectron ? 25 : 7
languages: { en: 'English' },
query_history_depth: isElectron ? 25 : 7,
themes: ['light', 'dark']
};
16 changes: 12 additions & 4 deletions src/app/containers/app/app.component.html
@@ -1,4 +1,4 @@
<div class="app-wrapper">
<div class="app-wrapper" [ngClass]="(settings$ | async).theme + '-theme'">
<div class="main-container">
<div class="loading-screen styled" *ngIf="!isReady">
<div class="loading-screen-inner">
Expand All @@ -24,14 +24,14 @@
(activeWindowChange)="setActiveWindow($event)"
(removeWindowChange)="removeWindow($event)"
(windowNameChange)="setWindowName($event)"></app-window-switcher>
<div class="header-actions" *ngIf="false">
<div class="header-actions">
<clr-dropdown>
<button class="nav-icon" type="button" clrDropdownTrigger>
<clr-icon shape="cog"></clr-icon>
<clr-icon shape="caret down"></clr-icon>
</button>
<clr-dropdown-menu clrPosition="bottom-right" *clrIfOpen>
<button type="button" clrDropdownItem>Settings</button>
<button type="button" clrDropdownItem (click)="showSettingsDialog()">Settings</button>
<button type="button" (click)="externalLink($event, 'https://github.com/imolorhe/altair')" clrDropdownItem>View on GitHub</button>
</clr-dropdown-menu>
</clr-dropdown>
Expand All @@ -40,7 +40,15 @@
<ng-container *ngFor="let windowId of windowIds">
<app-window [windowId]="windowId" [class.hide]="windowId !== activeWindowId"></app-window>
</ng-container>
<div class="dialogs">
<app-settings-dialog
[settings]="settings$ | async"
(toggleDialogChange)="$event ? showSettingsDialog() : hideSettingsDialog()"
(themeChange)="onThemeChange($event)"
(languageChange)="onLanguageChange($event)"
></app-settings-dialog>
</div>
</div>
<!-- The github link has been added to the settings dropdown -->
<app-fork-repo *ngIf="!isElectron"></app-fork-repo>
<!-- <app-fork-repo *ngIf="!isElectron"></app-fork-repo> -->
</div>
26 changes: 24 additions & 2 deletions src/app/containers/app/app.component.ts
Expand Up @@ -9,6 +9,7 @@ import isElectron from '../../utils/is_electron';
import * as fromRoot from '../../reducers';
import * as fromHeader from '../../reducers/headers/headers';
import * as fromVariable from '../../reducers/variables/variables';
import * as fromSettings from '../../reducers/settings/settings';

import * as queryActions from '../../actions/query/query';
import * as headerActions from '../../actions/headers/headers';
Expand All @@ -18,6 +19,7 @@ import * as layoutActions from '../../actions/layout/layout';
import * as docsActions from '../../actions/docs/docs';
import * as windowsActions from '../../actions/windows/windows';
import * as windowsMetaActions from '../../actions/windows-meta/windows-meta';
import * as settingsActions from '../../actions/settings/settings';

import { QueryService } from '../../services/query.service';
import { GqlService } from '../../services/gql.service';
Expand All @@ -30,7 +32,9 @@ import config from '../../config';
templateUrl: './app.component.html',
})
export class AppComponent {
windowIds$: Observable<any>;
windowIds$: Observable<any[]>;
settings$: Observable<fromSettings.State>;

windowIds = [];
windowsArr = [];
activeWindowId = '';
Expand All @@ -43,6 +47,8 @@ export class AppComponent {
private translate: TranslateService,
private electron: ElectronService
) {
this.settings$ = this.store.select('settings');

this.setDefaultLanguage();
this.setAvailableLanguages();

Expand Down Expand Up @@ -89,7 +95,7 @@ export class AppComponent {
}

setAvailableLanguages(): void {
const availableLanguages = config.languages;
const availableLanguages = Object.keys(config.languages);
this.translate.addLangs(availableLanguages);
}

Expand Down Expand Up @@ -123,6 +129,22 @@ export class AppComponent {
this.store.dispatch(new layoutActions.SetWindowNameAction(windowId, windowName));
}

showSettingsDialog() {
this.store.dispatch(new settingsActions.ShowSettingsAction());
}

hideSettingsDialog() {
this.store.dispatch(new settingsActions.HideSettingsAction());
}

onThemeChange(theme) {
this.store.dispatch(new settingsActions.SetThemeAction({ value: theme }));
}

onLanguageChange(language) {
this.store.dispatch(new settingsActions.SetLanguageAction({ value: language }));
}

/**
* Transform an object into an array
* @param obj
Expand Down
7 changes: 5 additions & 2 deletions src/app/reducers/index.ts
Expand Up @@ -15,6 +15,7 @@ import * as fromDocs from './docs/docs';
import * as fromWindows from './windows';
import * as fromHistory from './history/history';
import * as fromWindowsMeta from './windows-meta/windows-meta';
import * as fromSettings from './settings/settings';

export interface PerWindowState {
layout: fromLayout.State;
Expand Down Expand Up @@ -42,6 +43,7 @@ const perWindowReducers = {
export interface State {
windows: fromWindows.State;
windowsMeta: fromWindowsMeta.State;
settings: fromSettings.State;
}

// Meta reducer to log actions
Expand All @@ -55,14 +57,15 @@ export const log = (_reducer) => (state: State, action: Action) => {
export const keySerializer = (key) => 'altair_' + key;

export const metaReducers: MetaReducer<any>[] = [
localStorageSync({ keys: ['windows', 'windowsMeta'], rehydrate: true, storageKeySerializer: keySerializer }),
localStorageSync({ keys: ['windows', 'windowsMeta', 'settings'], rehydrate: true, storageKeySerializer: keySerializer }),
// !environment.production ? storeFreeze : null,
log
];

export const reducer: ActionReducerMap<State> = {
windows: fromWindows.windows(combineReducers(perWindowReducers)),
windowsMeta: fromWindowsMeta.windowsMetaReducer
windowsMeta: fromWindowsMeta.windowsMetaReducer,
settings: fromSettings.settingsReducer
};

export const selectWindowState = (windowId: string) => (state: State) => state.windows[windowId];
Expand Down

0 comments on commit be9f25c

Please sign in to comment.