refactor: fix code formatting

This commit is contained in:
Johannes Millan 2020-01-06 19:53:26 +01:00
parent 31aa8cff91
commit 56d2adcd70
104 changed files with 4966 additions and 3986 deletions

View file

@ -1,5 +1,6 @@
<!-- TODO better readable solution ? -->
<ng-container *ngIf="(isAllDataLoadedInitially$|async)" [dir]="isRTL ? 'rtl' : 'ltr'">
<ng-container *ngIf="(isAllDataLoadedInitially$|async)"
[dir]="isRTL ? 'rtl' : 'ltr'">
<!--TODO move inside page container somehow -->
<add-task-bar (blurred)="layoutService.hideAddTaskBar()"
@ -24,15 +25,15 @@
</mat-sidenav>
<mat-sidenav-content>
<header class="header-wrapper"
[class.isNotScrolled]="!(layoutService.isScrolled$|async)">
<header [class.isNotScrolled]="!(layoutService.isScrolled$|async)"
class="header-wrapper">
<main-header></main-header>
<bookmark-bar></bookmark-bar>
<banner></banner>
</header>
<div [@warpRoute]="getPage(o)"
#routeWrapper
<div #routeWrapper
[@warpRoute]="getPage(o)"
class="route-wrapper">
<router-outlet #o="outlet"></router-outlet>
</div>

View file

@ -1,4 +1,4 @@
import {ChangeDetectionStrategy, Component, HostListener, ViewChild, ViewContainerRef, OnDestroy} from '@angular/core';
import {ChangeDetectionStrategy, Component, HostListener, OnDestroy, ViewChild, ViewContainerRef} from '@angular/core';
import {ProjectService} from './features/project/project.service';
import {ChromeExtensionInterfaceService} from './core/chrome-extension-interface/chrome-extension-interface.service';
import {ShortcutService} from './core-ui/shortcut/shortcut.service';
@ -26,7 +26,7 @@ import {TranslateService} from '@ngx-translate/core';
import {GlobalThemeService} from './core/theme/global-theme.service';
import {UiHelperService} from './features/ui-helper/ui-helper.service';
import {TaskService} from './features/tasks/task.service';
import { LanguageService } from './core/language/language.service';
import {LanguageService} from './core/language/language.service';
@Component({
@ -41,7 +41,7 @@ import { LanguageService } from './core/language/language.service';
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent implements OnDestroy{
export class AppComponent implements OnDestroy {
isAllDataLoadedInitially$: Observable<boolean> = combineLatest([
this._projectService.isRelatedDataLoadedForCurrentProject$,
this._store.select(selectIsTaskDataLoaded),
@ -53,9 +53,8 @@ export class AppComponent implements OnDestroy{
@ViewChild('notesElRef', {read: ViewContainerRef, static: false}) notesElRef: ViewContainerRef;
@ViewChild('sideNavElRef', {read: ViewContainerRef, static: false}) sideNavElRef: ViewContainerRef;
private _subs : Subscription = new Subscription();
isRTL : boolean;
isRTL: boolean;
private _subs: Subscription = new Subscription();
constructor(
private _configService: GlobalConfigService,
@ -70,13 +69,13 @@ export class AppComponent implements OnDestroy{
private _globalThemeService: GlobalThemeService,
private _uiHelperService: UiHelperService,
private _store: Store<any>,
private _languageService : LanguageService,
private _languageService: LanguageService,
public readonly layoutService: LayoutService,
public readonly bookmarkService: BookmarkService,
public readonly taskService: TaskService,
public projectService: ProjectService,
) {
this._subs = this._languageService.isLangRTL.subscribe( (val) => {
this._subs = this._languageService.isLangRTL.subscribe((val) => {
this.isRTL = val;
document.dir = this.isRTL ? 'rtl' : 'ltr';
});
@ -187,6 +186,9 @@ export class AppComponent implements OnDestroy{
this.sideNavElRef.element.nativeElement.scrollIntoView({behavior: 'smooth'});
}
ngOnDestroy() {
this._subs.unsubscribe();
}
private _initElectronErrorHandler() {
this._electronService.ipcRenderer.on(IPC.ERROR, (ev, data: {
@ -205,8 +207,4 @@ export class AppComponent implements OnDestroy{
console.error(data);
});
}
ngOnDestroy() {
this._subs.unsubscribe();
}
}

View file

@ -26,11 +26,6 @@ const BOTH_OVER = 780;
})
export class LayoutService {
isShowAddTaskBar$: Observable<boolean> = this._store$.pipe(select(selectIsShowAddTaskBar));
private _isShowSideNav$: Observable<boolean> = this._store$.pipe(select(selectIsShowSideNav));
private _isShowNotes$: Observable<boolean> = this._store$.pipe(select(selectIsShowNotes));
isNavAlwaysVisible$: Observable<boolean> = this._breakPointObserver.observe([
`(min-width: ${NAV_ALWAYS_VISIBLE}px)`,
]).pipe(map(result => result.matches));
@ -40,7 +35,9 @@ export class LayoutService {
isNotesOver$: Observable<boolean> = this._breakPointObserver.observe([
`(min-width: ${BOTH_OVER}px)`,
]).pipe(map(result => !result.matches));
isNavOver$: Observable<boolean> = this.isNotesNextNavOver$.pipe(map(v => !v));
isScrolled$ = new BehaviorSubject<boolean>(false);
private _isShowSideNav$: Observable<boolean> = this._store$.pipe(select(selectIsShowSideNav));
isShowSideNav$: Observable<boolean> = this._isShowSideNav$.pipe(
switchMap((isShow) => {
return isShow
@ -49,8 +46,6 @@ export class LayoutService {
}),
);
isNavOver$: Observable<boolean> = this.isNotesNextNavOver$.pipe(map(v => !v));
// isShowNotes$: Observable<boolean> = this._isShowNotes$.pipe(
// switchMap((isShow) => {
@ -59,8 +54,7 @@ export class LayoutService {
// : this.isBothAlwaysVisible$;
// }),
// );
isScrolled$ = new BehaviorSubject<boolean>(false);
private _isShowNotes$: Observable<boolean> = this._store$.pipe(select(selectIsShowNotes));
constructor(
private _store$: Store<LayoutState>,

View file

@ -1,21 +1,21 @@
<!--<div class="wrapper ">-->
<div class="wrapper">
<button *ngIf="!(layoutService.isNavAlwaysVisible$|async)"
<button (click)="layoutService.toggleSideNav()"
*ngIf="!(layoutService.isNavAlwaysVisible$|async)"
class="burger-trigger"
(click)="layoutService.toggleSideNav()"
mat-icon-button>
<mat-icon>menu</mat-icon>
</button>
<div class="current-project-title"
<div [matTooltip]="T.MH.GO_TO_TASK_LIST|translate"
class="current-project-title"
mat-ripple
[matTooltip]="T.MH.GO_TO_TASK_LIST|translate"
routerLink="work-view">{{(projectService.currentProject$|async).title}}</div>
<button mat-icon-button
<button [matTooltip]="T.MH.PROJECT_SETTINGS|translate"
class="project-settings-btn"
[matTooltip]="T.MH.PROJECT_SETTINGS|translate"
mat-icon-button
routerLink="project-settings">
<mat-icon>more_vert</mat-icon>
</button>
@ -53,45 +53,45 @@
<nav class="action-nav">
<button (click)="layoutService.showAddTaskBar()"
mat-icon-button
[matTooltip]="T.MH.ADD_NEW_TASK|translate">
[matTooltip]="T.MH.ADD_NEW_TASK|translate"
mat-icon-button>
<mat-icon>add</mat-icon>
</button>
<button (click)="bookmarkService.toggleBookmarks()"
class="bookmark-btn"
mat-icon-button
[class.isOpen]="bookmarkService.isShowBookmarks$|async"
[matTooltip]="T.MH.TOGGLE_SHOW_BOOKMARKS|translate">
[matTooltip]="T.MH.TOGGLE_SHOW_BOOKMARKS|translate"
class="bookmark-btn"
mat-icon-button>
<mat-icon>bookmark</mat-icon>
</button>
<!-- <button *ngIf="!(layoutService.isBothAlwaysVisible$|async)"-->
<!-- (click)="layoutService.toggleNotes()"-->
<!-- mat-icon-button-->
<!-- [matTooltip]="T.MH.TOGGLE_SHOW_NOTES|translate">-->
<!-- <mat-icon [class.rotate]="(layoutService.isShowNotes$|async)"-->
<!-- class="note-ico">comment-->
<!-- </mat-icon>-->
<!-- </button>-->
<!-- <button *ngIf="!(layoutService.isBothAlwaysVisible$|async)"-->
<!-- (click)="layoutService.toggleNotes()"-->
<!-- mat-icon-button-->
<!-- [matTooltip]="T.MH.TOGGLE_SHOW_NOTES|translate">-->
<!-- <mat-icon [class.rotate]="(layoutService.isShowNotes$|async)"-->
<!-- class="note-ico">comment-->
<!-- </mat-icon>-->
<!-- </button>-->
<button class="hide-xs"
[matTooltip]="T.WW.HELP_PROCRASTINATION|translate"
<button [matTooltip]="T.WW.HELP_PROCRASTINATION|translate"
class="hide-xs"
mat-icon-button
routerLink="/procrastination">
<mat-icon>flash_on</mat-icon>
</button>
<div class="play-btn-wrapper">
<div class="current-task-title"
<div *ngIf="(isShowTaskTitle$|async)"
@fade
*ngIf="(isShowTaskTitle$|async)">{{(taskService.currentTask$|async)?.title}}
class="current-task-title">{{(taskService.currentTask$|async)?.title}}
</div>
<button (click)="taskService.toggleStartTask()"
[color]="(taskService.currentTaskId$|async)? 'accent': 'primary'"
[matTooltip]="T.MH.TOGGLE_TRACK_TIME|translate"
class="play-btn mat-elevation-z3"
mat-mini-fab
[matTooltip]="T.MH.TOGGLE_TRACK_TIME|translate">
mat-mini-fab>
<mat-icon *ngIf="!(taskService.currentTaskId$|async)">play_arrow</mat-icon>
<mat-icon *ngIf="(taskService.currentTaskId$|async)">pause</mat-icon>
<svg class="circle-svg"

View file

@ -256,7 +256,7 @@ button {
display: none;
}
@include darkTheme(){
@include darkTheme() {
background: $dark-theme-bg-lighter;
}

View file

@ -17,7 +17,7 @@ import {combineLatest, Observable} from 'rxjs';
changeDetection: ChangeDetectionStrategy.OnPush,
animations: [fadeAnimation]
})
export class MainHeaderComponent implements OnInit{
export class MainHeaderComponent implements OnInit {
T = T;
progressCircleRadius = 10;
circumference = this.progressCircleRadius * Math.PI * 2;

View file

@ -40,17 +40,17 @@
class="project-color"></div>
<button (click)="switchProject(project.id, 'work-view')"
mat-menu-item>
<mat-icon drag-handle
class="drag-handle">list
<mat-icon class="drag-handle"
drag-handle>list
</mat-icon>
{{project.title}}
</button>
<button
(click)="switchProject(project.id, 'project-settings')"
class="project-settings-btn"
mat-icon-button
routerLinkActive="isActiveRoute"
(click)="switchProject(project.id, 'project-settings')">
routerLinkActive="isActiveRoute">
<mat-icon>more_vert</mat-icon>
</button>
</div>
@ -81,9 +81,9 @@
<span class="text">{{T.MH.SETTINGS|translate}}</span>
</button>
<button class="route-link scroll-down-btn"
mat-menu-item
(click)="onScrollToNotesClick()">
<button (click)="onScrollToNotesClick()"
class="route-link scroll-down-btn"
mat-menu-item>
<mat-icon>notes</mat-icon>
<span class="text">{{T.MH.NOTES|translate}}</span>
<mat-icon>arrow_downwards</mat-icon>

View file

@ -13,9 +13,10 @@ import {T} from '../../../t.const';
changeDetection: ChangeDetectionStrategy.OnPush,
animations: [slideAnimation]
})
export class BannerComponent{
export class BannerComponent {
T = T;
height = 120;
private _dirtyReference: string;
// TODO maybe improve if initial delay is annoying
activeBanner$: Observable<Banner> = this.bannerService.activeBanner$.pipe(
concatMap((activeBanner) => {
@ -36,9 +37,11 @@ export class BannerComponent{
}
})
);
height = 120;
private _dirtyReference: string;
constructor(
public bannerService: BannerService,
) {
}
@ViewChild('wrapperEl', {static: false}) set wrapperEl(content: ElementRef) {
if (content && content.nativeElement) {
@ -46,11 +49,6 @@ export class BannerComponent{
}
}
constructor(
public bannerService: BannerService,
) {
}
dismiss(bannerId) {
this.bannerService.dismiss(bannerId);
}

View file

@ -4,7 +4,7 @@ import {DateTimeAdapter} from 'ng-pick-datetime';
import {DateAdapter} from '@angular/material';
import * as moment from 'moment';
import {AUTO_SWITCH_LNGS, LanguageCode, LanguageCodeMomentMap} from '../../app.constants';
import { BehaviorSubject, Observable } from 'rxjs';
import {BehaviorSubject, Observable} from 'rxjs';
@Injectable({
providedIn: 'root'
@ -12,10 +12,10 @@ import { BehaviorSubject, Observable } from 'rxjs';
export class LanguageService {
// Temporary solution for knowing the rtl languages
rtlLanguages: LanguageCode[] = [LanguageCode.ar];
// I think a better approach is to add a field in every [lang].json file to specify the direction of the language
private isRTL : BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
isLangRTL : Observable<boolean> = this.isRTL.asObservable();
rtlLanguages : LanguageCode[] = [LanguageCode.ar];
private isRTL: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
isLangRTL: Observable<boolean> = this.isRTL.asObservable();
constructor(
private _translateService: TranslateService,
@ -52,7 +52,7 @@ export class LanguageService {
this._dateTimeAdapter.setLocale(momLng);
}
private _isRTL (lng : LanguageCode) {
private _isRTL(lng: LanguageCode) {
return this.rtlLanguages.indexOf(lng) !== -1;
}
}

View file

@ -59,17 +59,10 @@ import {migrateGlobalConfigState} from '../../features/config/migrate-global-con
providedIn: 'root',
})
export class PersistenceService {
private _isBlockSaving = false;
// needs to be assigned before the creations
private _baseModels = [];
private _projectModels = [];
// TODO auto generate ls keys from appDataKey where possible
project = this._cmBase<ProjectState>(LS_PROJECT_META_LIST, 'project', migrateProjectState);
globalConfig = this._cmBase<GlobalConfigState>(LS_GLOBAL_CFG, 'globalConfig', migrateGlobalConfigState);
reminders = this._cmBase<Reminder[]>(LS_REMINDER, 'reminders');
task = this._cmProject<TaskState, Task>(
LS_TASK_STATE,
'task',
@ -81,7 +74,6 @@ export class PersistenceService {
'taskRepeatCfg',
taskRepeatCfgReducer,
);
taskArchive = this._cmProject<TaskArchive, TaskWithIssueData>(
LS_TASK_ARCHIVE,
'taskArchive',
@ -120,7 +112,10 @@ export class PersistenceService {
'obstruction',
obstructionReducer,
);
private _isBlockSaving = false;
// needs to be assigned before the creations
private _baseModels = [];
private _projectModels = [];
constructor(
private _snackService: SnackService,
@ -407,6 +402,18 @@ export class PersistenceService {
}
}
async _loadAppBaseData(): Promise<AppBaseData> {
const promises = this._baseModels.map(async (modelCfg) => {
const modelState = await modelCfg.load();
return {
[modelCfg.appDataKey]: modelState,
};
});
const baseDataArray: Partial<AppBaseData>[] = await Promise.all(promises);
return Object.assign({}, ...baseDataArray);
}
// TODO maybe refactor to class?
// ------------------
private _cmBase<T>(
@ -424,7 +431,6 @@ export class PersistenceService {
return model;
}
// TODO maybe refactor to class?
// TODO maybe find a way to exec effects here as well
private _cmProject<S, M>(
lsKey: string,
@ -512,17 +518,6 @@ export class PersistenceService {
};
}
async _loadAppBaseData(): Promise<AppBaseData> {
const promises = this._baseModels.map(async (modelCfg) => {
const modelState = await modelCfg.load();
return {
[modelCfg.appDataKey]: modelState,
};
});
const baseDataArray: Partial<AppBaseData>[] = await Promise.all(promises);
return Object.assign({}, ...baseDataArray);
}
private async _loadAppDataForProjects(projectIds: string[]): Promise<AppDataForProjects> {
const forProjectsData = await Promise.all(this._projectModels.map(async (modelCfg) => {
const modelState = await this._loadForProjectIds(projectIds, modelCfg.load);

View file

@ -1,6 +1,6 @@
@import '../../../../variables';
:host{
:host {
background: inherit;
}

View file

@ -18,18 +18,18 @@
</mat-form-field>
<mat-form-field>
<input [(ngModel)]="attachmentCopy.title"
[placeholder]="(T.G.TITLE|translate)"
autofocus="autofocus"
matInput
name="title"
[placeholder]="(T.G.TITLE|translate)"
tabindex="1"
type="text">
</mat-form-field>
<mat-form-field>
<mat-select [(ngModel)]="attachmentCopy.type"
name="type"
[placeholder]="(T.F.ATTACHMENT.DIALOG_EDIT.SELECT_TYPE|translate)"
name="type"
required="true"
tabindex="1">
<mat-option *ngFor="let type of types"

View file

@ -1,4 +1,4 @@
h1, mat-dialog-actions{
h1, mat-dialog-actions {
:host-context([dir=rtl]) & {
direction: rtl;
}

View file

@ -11,21 +11,21 @@
<div class="controls-and-list-wrapper">
<div class="list-controls">
<button *ngIf="!isEditMode"
<button (menuClosed)="isContextMenuDisabled = false"
(menuOpened)="isContextMenuDisabled = true"
*ngIf="!isEditMode"
[matMenuTriggerFor]="menu"
[style.pointer-events]="isContextMenuDisabled ? 'none' : 'all'"
(menuOpened)="isContextMenuDisabled = true"
(menuClosed)="isContextMenuDisabled = false"
mat-stroked-button
[title]="T.F.TASK.CMP.OPEN_TASK_MENU|translate"
mat-stroked-button
tabindex="1">
<mat-icon>more_vert</mat-icon>
</button>
<button *ngIf="isEditMode"
(click)="isEditMode=false"
<button (click)="isEditMode=false"
*ngIf="isEditMode"
[title]="T.F.TASK.CMP.OPEN_TASK_MENU|translate"
color="accent"
mat-stroked-button
[title]="T.F.TASK.CMP.OPEN_TASK_MENU|translate"
tabindex="1">
<mat-icon>close</mat-icon>
</button>

View file

@ -27,13 +27,6 @@ export class BookmarkBarComponent implements OnDestroy {
T = T;
isContextMenuDisabled = false;
bookmarkBarHeight = 50;
@ViewChild('bookmarkBar', {read: ElementRef, static: false}) set bookmarkBarEl(content: ElementRef) {
if (content && content.nativeElement) {
this.bookmarkBarHeight = content.nativeElement.offsetHeight;
}
}
private _subs = new Subscription();
constructor(
@ -57,6 +50,12 @@ export class BookmarkBarComponent implements OnDestroy {
);
}
@ViewChild('bookmarkBar', {read: ElementRef, static: false}) set bookmarkBarEl(content: ElementRef) {
if (content && content.nativeElement) {
this.bookmarkBarHeight = content.nativeElement.offsetHeight;
}
}
ngOnDestroy() {
this._subs.unsubscribe();
}

View file

@ -9,10 +9,10 @@
<div class="form-wrapper">
<mat-form-field>
<input [(ngModel)]="bookmarkCopy.title"
[placeholder]="(T.G.TITLE|translate)"
autofocus="autofocus"
matInput
name="title"
[placeholder]="(T.G.TITLE|translate)"
tabindex="1"
type="text">
</mat-form-field>
@ -28,8 +28,8 @@
<mat-form-field>
<mat-select [(ngModel)]="bookmarkCopy.type"
name="type"
[placeholder]="(T.F.BOOKMARK.DIALOG_EDIT.SELECT_TYPE|translate)"
name="type"
required="true"
tabindex="1">
<mat-option *ngFor="let type of types"
@ -44,8 +44,8 @@
<input [(ngModel)]="bookmarkCopy.icon"
[formControl]="iconControl"
[matAutocomplete]="auto"
matInput
[placeholder]="(T.F.BOOKMARK.DIALOG_EDIT.SELECT_ICON|translate)"
matInput
type="text">
<mat-icon matPrefix="">{{bookmarkCopy.icon}}</mat-icon>
<mat-autocomplete #auto="matAutocomplete"

View file

@ -31,26 +31,10 @@ import {TranslateService} from '@ngx-translate/core';
})
export class ConfigSectionComponent implements OnInit, OnDestroy {
@Input() section: ConfigFormSection<{ [key: string]: any }>;
@Input() set cfg(v: any) {
this._cfg = v;
if (v && this._instance) {
this._instance.cfg = {...v};
}
}
get cfg() {
return this._cfg;
}
@Output() save: EventEmitter<{ sectionKey: GlobalConfigSectionKey | ProjectCfgFormKey, config: any }> = new EventEmitter();
@ViewChild('customForm', {read: ViewContainerRef, static: true}) customFormRef: ViewContainerRef;
isExpanded = false;
private _subs = new Subscription();
private _cfg: any;
private _instance;
private _viewDestroyTimeout: number;
@ -62,6 +46,19 @@ export class ConfigSectionComponent implements OnInit, OnDestroy {
) {
}
private _cfg: any;
get cfg() {
return this._cfg;
}
@Input() set cfg(v: any) {
this._cfg = v;
if (v && this._instance) {
this._instance.cfg = {...v};
}
}
ngOnInit(): void {
if (this.section && this.section.customSection) {
this._loadCustomSection(this.section.customSection);

View file

@ -22,8 +22,8 @@ const EXPIRES_SAFETY_MARGIN = 5 * 60 * 1000;
providedIn: 'root',
})
export class GoogleApiService {
public isLoggedIn: boolean;
private _session$: Observable<GoogleSession> = this._configService.googleSession$;
private _onTokenExpire$: Observable<number> = this._session$.pipe(
switchMap((session) => {
if (!session.accessToken) {
@ -37,8 +37,6 @@ export class GoogleApiService {
: EMPTY;
})
);
public isLoggedIn: boolean;
public isLoggedIn$: Observable<boolean> = merge(
this._session$,
this._onTokenExpire$,

View file

@ -2,8 +2,8 @@
<form #formRef="ngForm"
(submit)="submit()">
<mat-slide-toggle [ngModel]="cfg.isEnabled"
(ngModelChange)="toggleEnabled($event)"
<mat-slide-toggle (ngModelChange)="toggleEnabled($event)"
[ngModel]="cfg.isEnabled"
name="isEnabled">
{{T.F.GOOGLE.SYNC_CFG.ENABLE|translate}}
</mat-slide-toggle>
@ -54,9 +54,9 @@
class="form-inputs">
<mat-form-field>
<input [(ngModel)]="tmpSyncFile"
[placeholder]="T.F.GOOGLE.SYNC_CFG.SYNC_FILE_NAME|translate"
matInput
name="tmpSyncFile"
[placeholder]="T.F.GOOGLE.SYNC_CFG.SYNC_FILE_NAME|translate"
type="text">
<mat-icon matSuffix="">file_upload</mat-icon>
</mat-form-field>
@ -96,21 +96,21 @@
<mat-form-field *ngIf="cfg.isAutoLogin && cfg.isAutoSyncToRemote">
<input [(ngModel)]="cfg.syncInterval"
[isAllowSeconds]="true"
[placeholder]="T.F.GOOGLE.SYNC_CFG.SYNC_INTERVAL|translate"
inputDuration
matInput
name="syncInterval"
[placeholder]="T.F.GOOGLE.SYNC_CFG.SYNC_INTERVAL|translate"
type="text">
<mat-icon matSuffix="">timer</mat-icon>
</mat-form-field>
</section>
<a mat-button
<a class="md-stroked"
color=primary
class="md-stroked"
external-link
target="_blank"
href="https://myaccount.google.com/permissions">
href="https://myaccount.google.com/permissions"
mat-button
target="_blank">
<mat-icon>remove_circle</mat-icon>
Revoke permissions
</a>

View file

@ -26,8 +26,7 @@ import {GOOGLE_DRIVE_FEATURE_NAME} from './store/google-drive-sync.reducer';
DialogConfirmDriveSyncLoadComponent,
DialogConfirmDriveSyncSaveComponent,
],
exports: [
],
exports: [],
})
export class GoogleModule {
}

View file

@ -2,7 +2,19 @@ import {Injectable} from '@angular/core';
import {Actions, Effect, ofType} from '@ngrx/effects';
import {Store} from '@ngrx/store';
import {GlobalConfigActionTypes, UpdateGlobalConfigSection} from '../../config/store/global-config.actions';
import {catchError, concatMap, distinctUntilChanged, exhaustMap, filter, map, mapTo, switchMap, take, tap, withLatestFrom} from 'rxjs/operators';
import {
catchError,
concatMap,
distinctUntilChanged,
exhaustMap,
filter,
map,
mapTo,
switchMap,
take,
tap,
withLatestFrom
} from 'rxjs/operators';
import {combineLatest, EMPTY, from, interval, Observable, of, throwError, zip} from 'rxjs';
import {GoogleDriveSyncService} from '../google-drive-sync.service';
import {GoogleApiService} from '../google-api.service';

View file

@ -54,9 +54,9 @@
<div><span class="author-name">{{comment.user?.login}}</span>
<span class="when">{{T.F.GITHUB.ISSUE_CONTENT.AT|translate}} {{comment.created_at|date:'short'}}</span>
</div>
<div class="markdown"
*ngIf="comment.body"
[innerHTML]="comment?.body|markdown"></div>
<div *ngIf="comment.body"
[innerHTML]="comment?.body|markdown"
class="markdown"></div>
</div>
</div>
</div>

View file

@ -21,6 +21,8 @@ export class GithubIssueService {
// githubIssues$: Observable<GithubIssue[]> = this._store.pipe(select(selectAllGithubIssues));
// githubIssuesEntities$: Observable<Dictionary<GithubIssue>> = this._store.pipe(select(selectGithubIssueEntities));
private _fineWithDeletionIssueIds = [];
constructor(
private readonly _store: Store<any>,
private readonly _persistenceService: PersistenceService,
@ -29,9 +31,8 @@ export class GithubIssueService {
) {
}
private _fineWithDeletionIssueIds = [];
// META
// ----
async loadStateForProject(projectId: string) {
const lsGithubIssueState = await this._persistenceService.loadIssuesForProject(projectId, GITHUB_TYPE) as GithubIssueState;

View file

@ -89,7 +89,7 @@ export function githubIssueReducer(
if (tasksWithGithubIssue && tasksWithGithubIssue.length > 0) {
const issueIds = tasksWithGithubIssue.map(task => task.issueId)
// only remove if data is there in the first place
// only remove if data is there in the first place
.filter((issueId) => {
const ids = state.ids as number[];
const isInState = ids.includes(+issueId);

View file

@ -1,6 +1,5 @@
// TODO use as a checklist
import {GithubCfg} from './github';
import {FormlyFieldConfig} from '@ngx-formly/core';
import {T} from '../../../t.const';
import {ConfigFormSection, LimitedFormlyFieldConfig} from '../../config/global-config.model';

View file

@ -10,15 +10,16 @@
<mat-dialog-content>
<p>{{T.F.JIRA.DIALOG_WORKLOG.SUBMIT_WORKLOG_FOR|translate}} <strong>{{issue.key}} {{issue.summary}}</strong>.</p>
<p>{{T.F.JIRA.DIALOG_WORKLOG.CURRENTLY_LOGGED|translate}} <strong>{{(issue.timespent * 1000)|msToString}}</strong></p>
<p>{{T.F.JIRA.DIALOG_WORKLOG.CURRENTLY_LOGGED|translate}} <strong>{{(issue.timespent * 1000)|msToString}}</strong>
</p>
<div class="form-wrapper">
<mat-form-field>
<input [(ngModel)]="timeSpent"
[placeholder]="T.F.JIRA.DIALOG_WORKLOG.TIME_SPENT|translate"
inputDuration="optional"
matInput
name="timeSpent"
[placeholder]="T.F.JIRA.DIALOG_WORKLOG.TIME_SPENT|translate"
required
type="text">
@ -27,9 +28,9 @@
<mat-form-field>
<input [(ngModel)]="started"
[placeholder]="T.F.JIRA.DIALOG_WORKLOG.STARTED|translate "
matInput
name="date"
[placeholder]="T.F.JIRA.DIALOG_WORKLOG.STARTED|translate "
required
type="datetime-local">
<mat-error>{{T.F.JIRA.DIALOG_WORKLOG.INVALID_DATE|translate}}</mat-error>

View file

@ -9,7 +9,13 @@ import {
JIRA_REQUEST_TIMEOUT_DURATION
} from './jira.const';
import {ProjectService} from '../../project/project.service';
import {mapIssueResponse, mapIssuesResponse, mapResponse, mapToSearchResults, mapTransitionResponse} from './jira-issue/jira-issue-map.util';
import {
mapIssueResponse,
mapIssuesResponse,
mapResponse,
mapToSearchResults,
mapTransitionResponse
} from './jira-issue/jira-issue-map.util';
import {JiraOriginalStatus, JiraOriginalTransition, JiraOriginalUser} from './jira-api-responses';
import {JiraCfg} from './jira';
import {ElectronService} from 'ngx-electron';

View file

@ -6,8 +6,8 @@
[formGroup]="credentialsFormGroup">
<ng-template matStepLabel>{{T.F.JIRA.STEPPER.CREDENTIALS|translate}}</ng-template>
<p [ngClass]="HelperClasses.isHideForAdvancedFeatures"
[innerHTML]="T.G.EXTENSION_INFO|translate">
<p [innerHTML]="T.G.EXTENSION_INFO|translate"
[ngClass]="HelperClasses.isHideForAdvancedFeatures">
</p>
<formly-form (modelChange)="jiraCfg=$event"

View file

@ -2,9 +2,9 @@
<p [innerHTML]="T.G.EXTENSION_INFO|translate"></p>
</div>
<mat-slide-toggle [ngModel]="cfg.isEnabled"
(ngModelChange)="toggleEnabled($event)"
<mat-slide-toggle (ngModelChange)="toggleEnabled($event)"
[ngClass]="HelperClasses.isHideForNoAdvancedFeatures"
[ngModel]="cfg.isEnabled"
name="isEnabled"
style="margin-bottom: 8px;">
{{T.F.JIRA.CFG_CMP.ENABLE|translate}}
@ -36,9 +36,9 @@
<mat-form-field>
<input [formControl]="issueSuggestionsCtrl"
[matAutocomplete]="autoEl"
[placeholder]="T.F.JIRA.CFG_CMP.SELECT_ISSUE_FOR_TRANSITIONS|translate"
class="border-color-primary"
matInput
[placeholder]="T.F.JIRA.CFG_CMP.SELECT_ISSUE_FOR_TRANSITIONS|translate">
matInput>
<mat-autocomplete #autoEl="matAutocomplete"
(optionSelected)="updateTransitionOptions()"
@ -92,9 +92,9 @@
<input [(ngModel)]="cfg.storyPointFieldId"
[formControl]="customFieldSuggestionsCtrl"
[matAutocomplete]="storyPointAutoEl"
[placeholder]="T.F.JIRA.CFG_CMP.STORY_POINTS|translate"
class="border-color-primary"
matInput
[placeholder]="T.F.JIRA.CFG_CMP.STORY_POINTS|translate">
matInput>
<mat-autocomplete #storyPointAutoEl="matAutocomplete"
[autoActiveFirstOption]="true">

View file

@ -25,6 +25,52 @@ import {ProjectService} from '../../../project/project.service';
})
export class JiraCfgComponent implements OnInit, OnDestroy {
@Input() section: ConfigFormSection<JiraCfg>;
@Output() save: EventEmitter<{ sectionKey: GlobalConfigSectionKey | ProjectCfgFormKey, config: any }> = new EventEmitter();
T = T;
HelperClasses = HelperClasses;
issueSuggestionsCtrl: FormControl = new FormControl();
customFieldSuggestionsCtrl: FormControl = new FormControl();
customFields: any [] = [];
customFieldsPromise: Promise<any>;
isLoading$ = new BehaviorSubject(false);
fields: FormlyFieldConfig[];
form = new FormGroup({});
options: FormlyFormOptions = {};
filteredIssueSuggestions$: Observable<SearchResultItem[]> = this.issueSuggestionsCtrl.valueChanges.pipe(
debounceTime(300),
tap(() => this.isLoading$.next(true)),
switchMap((searchTerm) => {
return (searchTerm && searchTerm.length > 1)
? this._jiraApiService.issuePicker$(searchTerm)
.pipe(
catchError(() => {
return [];
})
)
// Note: the outer array signifies the observable stream the other is the value
: [[]];
}),
tap((suggestions) => {
this.isLoading$.next(false);
}),
);
filteredCustomFieldSuggestions$: Observable<any[]> = this.customFieldSuggestionsCtrl.valueChanges.pipe(
map(value => this._filterCustomFieldSuggestions(value)),
);
private _subs = new Subscription();
constructor(
private _jiraApiService: JiraApiService,
private _snackService: SnackService,
private _projectService: ProjectService,
) {
}
private _cfg: JiraCfg;
get cfg() {
return this._cfg;
}
// NOTE: this is legit because it might be that there is no issue provider cfg yet
@Input() set cfg(cfg: JiraCfg) {
@ -48,59 +94,6 @@ export class JiraCfgComponent implements OnInit, OnDestroy {
}
}
get cfg() {
return this._cfg;
}
@Output() save: EventEmitter<{ sectionKey: GlobalConfigSectionKey | ProjectCfgFormKey, config: any }> = new EventEmitter();
T = T;
HelperClasses = HelperClasses;
issueSuggestionsCtrl: FormControl = new FormControl();
customFieldSuggestionsCtrl: FormControl = new FormControl();
customFields: any [] = [];
customFieldsPromise: Promise<any>;
isLoading$ = new BehaviorSubject(false);
fields: FormlyFieldConfig[];
form = new FormGroup({});
options: FormlyFormOptions = {};
filteredIssueSuggestions$: Observable<SearchResultItem[]> = this.issueSuggestionsCtrl.valueChanges.pipe(
debounceTime(300),
tap(() => this.isLoading$.next(true)),
switchMap((searchTerm) => {
return (searchTerm && searchTerm.length > 1)
? this._jiraApiService.issuePicker$(searchTerm)
.pipe(
catchError(() => {
return [];
})
)
// Note: the outer array signifies the observable stream the other is the value
: [[]];
}),
tap((suggestions) => {
this.isLoading$.next(false);
}),
);
filteredCustomFieldSuggestions$: Observable<any[]> = this.customFieldSuggestionsCtrl.valueChanges.pipe(
map(value => this._filterCustomFieldSuggestions(value)),
);
private _subs = new Subscription();
private _cfg: JiraCfg;
constructor(
private _jiraApiService: JiraApiService,
private _snackService: SnackService,
private _projectService: ProjectService,
) {
}
ngOnInit(): void {
this.fields = this.section.items;
}

View file

@ -93,8 +93,8 @@
{{comment.created|date:'short'}}</span>
</div>
<div *ngIf="comment.body"
class="markdown"
[innerHTML]="comment.body|jiraToMarkdown|markdown"></div>
[innerHTML]="comment.body|jiraToMarkdown|markdown"
class="markdown"></div>
</div>
</div>

View file

@ -1,4 +1,4 @@
import {JiraAttachment, JiraAuthor, JiraChangelogEntry, JiraComment, JiraIssue, } from './jira-issue.model';
import {JiraAttachment, JiraAuthor, JiraChangelogEntry, JiraComment, JiraIssue} from './jira-issue.model';
import {
JiraIssueOriginal,
JiraOriginalAttachment,

View file

@ -39,25 +39,6 @@ import {HANDLED_ERROR_PROP_STR} from '../../../../../app.constants';
@Injectable()
export class JiraIssueEffects {
@Effect({dispatch: false}) pollIssueChangesAndBacklogUpdates: any = this._actions$
.pipe(
ofType(
// while load state should be enough this just might fix the error of polling for inactive projects?
ProjectActionTypes.LoadProjectRelatedDataSuccess,
ProjectActionTypes.UpdateProjectIssueProviderCfg,
JiraIssueActionTypes.LoadState,
),
withLatestFrom(
this._projectService.isJiraEnabled$,
this._projectService.currentJiraCfg$,
),
switchMap(([a, isEnabled, jiraCfg]) => {
return (isEnabled && jiraCfg.isAutoPollTickets)
? this._pollChangesForIssues$
: EMPTY;
})
);
@Effect() pollNewIssuesToBacklog$: any = this._actions$
.pipe(
ofType(
@ -78,7 +59,6 @@ export class JiraIssueEffects {
: EMPTY;
}),
);
@Effect({dispatch: false}) syncIssueStateToLs$: any = this._actions$
.pipe(
ofType(
@ -99,7 +79,6 @@ export class JiraIssueEffects {
),
tap(this._saveToLs.bind(this))
);
@Effect({dispatch: false}) addOpenIssuesToBacklog$: any = this._actions$
.pipe(
ofType(
@ -110,8 +89,6 @@ export class JiraIssueEffects {
),
tap(this._importNewIssuesToBacklog.bind(this))
);
@Effect({dispatch: false}) addWorklog$: any = this._actions$
.pipe(
ofType(
@ -148,7 +125,6 @@ export class JiraIssueEffects {
}
})
);
@Effect({dispatch: false}) checkForReassignment: any = this._actions$
.pipe(
ofType(
@ -209,7 +185,6 @@ export class JiraIssueEffects {
}
})
);
@Effect({dispatch: false}) checkForStartTransition$: Observable<any> = this._actions$
.pipe(
ofType(
@ -229,7 +204,6 @@ export class JiraIssueEffects {
return this._handleTransitionForIssue('IN_PROGRESS', jiraCfg, issueData);
}),
);
@Effect({dispatch: false})
checkForDoneTransition$: Observable<any> = this._actions$
.pipe(
@ -253,7 +227,6 @@ export class JiraIssueEffects {
return this._handleTransitionForIssue('DONE', jiraCfg, issueData);
})
);
@Effect({dispatch: false}) loadMissingIssues$: any = this._taskService.tasksWithMissingIssueData$
.pipe(
withLatestFrom(
@ -272,7 +245,6 @@ export class JiraIssueEffects {
tasks.forEach((task) => this._jiraIssueService.loadMissingIssueData(task.issueId));
})
);
@Effect() updateTaskTitleIfChanged$: any = this._actions$
.pipe(
ofType(
@ -298,7 +270,6 @@ export class JiraIssueEffects {
})
),
);
private _pollChangesForIssues$: Observable<any> = timer(JIRA_INITIAL_POLL_DELAY, JIRA_POLL_INTERVAL).pipe(
withLatestFrom(
this._store$.pipe(select(selectJiraIssueIds)),
@ -316,6 +287,24 @@ export class JiraIssueEffects {
}
}),
);
@Effect({dispatch: false}) pollIssueChangesAndBacklogUpdates: any = this._actions$
.pipe(
ofType(
// while load state should be enough this just might fix the error of polling for inactive projects?
ProjectActionTypes.LoadProjectRelatedDataSuccess,
ProjectActionTypes.UpdateProjectIssueProviderCfg,
JiraIssueActionTypes.LoadState,
),
withLatestFrom(
this._projectService.isJiraEnabled$,
this._projectService.currentJiraCfg$,
),
switchMap(([a, isEnabled, jiraCfg]) => {
return (isEnabled && jiraCfg.isAutoPollTickets)
? this._pollChangesForIssues$
: EMPTY;
})
);
constructor(private readonly _actions$: Actions,
private readonly _store$: Store<any>,

View file

@ -1,6 +1,5 @@
// TODO use as a checklist
import {JiraCfg} from './jira';
import {FormlyFieldConfig} from '@ngx-formly/core';
import {GITHUB_INITIAL_POLL_DELAY} from '../github/github.const';
import {T} from '../../../t.const';
import {ConfigFormSection, LimitedFormlyFieldConfig} from '../../config/global-config.model';

View file

@ -13,14 +13,14 @@
<div class="row">
<mat-form-field>
<input #mood="ngModel"
[ngModel]="metricForDay.mood"
(ngModelChange)="updateMood($event)"
[ngModel]="metricForDay.mood"
[placeholder]="T.F.METRIC.EVAL_FORM.MOOD|translate"
matInput
max="10"
maxLength="2"
min="1"
name="mood"
[placeholder]="T.F.METRIC.EVAL_FORM.MOOD|translate"
required
type="number">
<mat-hint>{{T.F.METRIC.EVAL_FORM.MOOD_HINT|translate}}</mat-hint>
@ -31,14 +31,14 @@
<mat-form-field>
<input #productivity="ngModel"
[ngModel]="metricForDay.productivity"
(ngModelChange)="updateProductivity($event)"
[ngModel]="metricForDay.productivity"
[placeholder]="T.F.METRIC.EVAL_FORM.PRODUCTIVITY|translate"
matInput
max="10"
maxLength="2"
min="1"
name="productivity"
[placeholder]="T.F.METRIC.EVAL_FORM.PRODUCTIVITY|translate"
required
type="number">
<mat-hint>{{T.F.METRIC.EVAL_FORM.PRODUCTIVITY_HINT|translate}}</mat-hint>
@ -51,34 +51,34 @@
<chip-list-input (addItem)="addImprovement($event)"
(addNewItem)="addNewImprovement($event)"
(removeItem)="removeImprovement($event)"
[label]="T.F.METRIC.EVAL_FORM.IMPROVEMENTS|translate"
[model]="metricForDay.improvements"
[suggestions]="(improvementService.improvements$|async)"
[label]="T.F.METRIC.EVAL_FORM.IMPROVEMENTS|translate"></chip-list-input>
[suggestions]="(improvementService.improvements$|async)"></chip-list-input>
<chip-list-input (addItem)="addObstruction($event)"
(addNewItem)="addNewObstruction($event)"
(removeItem)="removeObstruction($event)"
[label]="T.F.METRIC.EVAL_FORM.OBSTRUCTIONS|translate"
[model]="metricForDay.obstructions"
[suggestions]="(obstructionService.obstructions$|async)"
[label]="T.F.METRIC.EVAL_FORM.OBSTRUCTIONS|translate"></chip-list-input>
[suggestions]="(obstructionService.obstructions$|async)"></chip-list-input>
<chip-list-input (addItem)="addImprovementTomorrow($event)"
(addNewItem)="addNewImprovementTomorrow($event)"
(removeItem)="removeImprovementTomorrow($event)"
(additionalAction)="toggleImprovementRepeat($event)"
additionalActionIcon="repeat"
[toggledItems]="improvementService.repeatedImprovementIds$|async"
[additionalActionTooltip]="T.F.METRIC.EVAL_FORM.ENABLE_REPEAT_EVERY_DAY|translate"
(removeItem)="removeImprovementTomorrow($event)"
[additionalActionTooltipUnToggle]="T.F.METRIC.EVAL_FORM.DISABLE_REPEAT_EVERY_DAY|translate"
[additionalActionTooltip]="T.F.METRIC.EVAL_FORM.ENABLE_REPEAT_EVERY_DAY|translate"
[label]="T.F.METRIC.EVAL_FORM.IMPROVEMENTS_TOMORROW|translate"
[model]="metricForDay.improvementsTomorrow"
[suggestions]="(improvementService.improvements$|async)"
[label]="T.F.METRIC.EVAL_FORM.IMPROVEMENTS_TOMORROW|translate"></chip-list-input>
[toggledItems]="improvementService.repeatedImprovementIds$|async"
additionalActionIcon="repeat"></chip-list-input>
</form>
</div>
<div style="text-align: center; margin-top: 8px;margin-bottom: 16px;">
<button mat-button
(click)="addNote()">
<button (click)="addNote()"
mat-button>
<mat-icon>add</mat-icon>
{{T.F.METRIC.EVAL_FORM.ADD_NOTE_FOR_TOMORROW|translate}}
{{T.F.METRIC.EVAL_FORM.ADD_NOTE_FOR_TOMORROW|translate}}
</button>
</div>

View file

@ -29,24 +29,16 @@ import {MatDialog} from '@angular/material/dialog';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EvaluationSheetComponent implements OnDestroy, OnInit {
@Input() set day(val: string) {
this.day$.next(val);
}
@Output() save = new EventEmitter<any>();
T = T;
metricForDay: MetricCopy;
day$ = new BehaviorSubject<string>(getWorklogStr());
// isForToday$: Observable<boolean> = this.day$.pipe(map(day => day === getWorklogStr()));
private _metricForDay$ = this.day$.pipe(
switchMap((day) => this._metricService.getMetricForDayOrDefaultWithCheckedImprovements$(day)),
);
// isForToday$: Observable<boolean> = this.day$.pipe(map(day => day === getWorklogStr()));
private _subs = new Subscription();
constructor(
public obstructionService: ObstructionService,
public improvementService: ImprovementService,
@ -58,6 +50,10 @@ export class EvaluationSheetComponent implements OnDestroy, OnInit {
) {
}
@Input() set day(val: string) {
this.day$.next(val);
}
ngOnInit(): void {
this._subs.add(this._metricForDay$.subscribe(metric => {
this.metricForDay = metric;

View file

@ -1,23 +1,23 @@
<div class="improvements"
[@improvementBanner]="improvements.length">
<div class="improvement"
mat-ripple
*ngFor="let improvement of improvements;">
<button mat-icon-button
disableRipple
class="dismiss"
<div [@improvementBanner]="improvements.length"
class="improvements">
<div *ngFor="let improvement of improvements;"
class="improvement"
mat-ripple>
<button (click)="dismiss(improvement)"
[matTooltip]="T.G.DISMISS|translate"
(click)="dismiss(improvement)">
class="dismiss"
disableRipple
mat-icon-button>
<mat-icon>close</mat-icon>
</button>
<div class="title">{{improvement?.title}}</div>
<button mat-icon-button
disableRipple
class="check"
<button (click)="check(improvement)"
[matTooltip]="T.F.METRIC.BANNER.CHECK|translate"
(click)="check(improvement)">
class="check"
disableRipple
mat-icon-button>
<mat-icon>check</mat-icon>
</button>
</div>

View file

@ -9,9 +9,9 @@
<!--[matDatepicker]="myDatepicker"-->
<input
[(ngModel)]="title"
[placeholder]="T.F.NOTE.D_ADD_REMINDER.L_TITLE|translate"
matInput
name="title"
[placeholder]="T.F.NOTE.D_ADD_REMINDER.L_TITLE|translate"
required
type="text">
<mat-error>{{T.F.NOTE.D_ADD_REMINDER.E_ENTER_TITLE|translate}}</mat-error>
@ -19,9 +19,9 @@
<datetime-input (modelChange)="dateTime=$event"
[model]="dateTime"
[placeholder]="T.F.NOTE.D_ADD_REMINDER.L_DATETIME|translate"
[required]="true"
name="reminderDate"
[placeholder]="T.F.NOTE.D_ADD_REMINDER.L_DATETIME|translate"></datetime-input>
name="reminderDate"></datetime-input>
</div>
</mat-dialog-content>

View file

@ -5,15 +5,15 @@
<textarea (keydown)="keydownHandler($event)"
(ngModelChange)="saveTmp()"
[(ngModel)]="noteContent"
[placeholder]="T.F.NOTE.D_ADD.NOTE_LABEL|translate"
matTextareaAutosize
name="noteContent"
[placeholder]="T.F.NOTE.D_ADD.NOTE_LABEL|translate"
rows="6"></textarea>
</div>
<datetime-input (modelChange)="reminderDate=$event"
[model]="reminderDate"
name="reminderData"
[placeholder]="T.F.NOTE.D_ADD.DATETIME_LABEL|translate"
name="reminderData"
style="width: 100%;"></datetime-input>
</div>

View file

@ -3,6 +3,7 @@
:host-context([dir=rtl]) {
direction: rtl;
}
textarea {
display: block;
width: 100%;
@ -12,7 +13,7 @@ textarea {
padding: $s;
min-height: $s*5;
@include mq (xs) {
@include mq(xs) {
min-height: 220px;
width: 500px;
}

View file

@ -20,8 +20,8 @@
<mat-dialog-actions align="end">
<div class="wrap-buttons">
<button [matMenuTriggerFor]="snoozeMenu"
(dblclick)="snooze(10)"
<button (dblclick)="snooze(10)"
[matMenuTriggerFor]="snoozeMenu"
color="primary"
mat-button
type="button">
@ -41,18 +41,18 @@
<mat-menu #snoozeMenu="matMenu">
<button mat-menu-item
(click)="snooze(10)">
<button (click)="snooze(10)"
mat-menu-item>
<mat-icon>snooze</mat-icon>
{{T.G.MINUTES|translate:{m: 10} }}
</button>
<button mat-menu-item
(click)="snooze(30)">
<button (click)="snooze(30)"
mat-menu-item>
<mat-icon>snooze</mat-icon>
{{T.G.MINUTES|translate:{m: 30} }}
</button>
<button mat-menu-item
(click)="snooze(60)">
<button (click)="snooze(60)"
mat-menu-item>
<mat-icon>snooze</mat-icon>
{{T.G.MINUTES|translate:{m: 60} }}
</button>

View file

@ -6,6 +6,7 @@ $noteFontSize: 12px;
:host {
display: block;
margin-right: $s;
:host-context([dir=rtl]) {
margin-left: $s;
margin-right: unset;
@ -25,11 +26,12 @@ $noteFontSize: 12px;
box-shadow: $whiteframe-shadow-3dp;
//outline: 2px dashed $c-accent;
}
&.isFocused {
z-index: 5;
}
&.isImg {
&.isImg {
border: 0;
}
@ -48,6 +50,7 @@ $noteFontSize: 12px;
right: unset;
left: -$s*0.75;
}
// fixes drag and drop on mobile
touch-action: none;

View file

@ -6,8 +6,8 @@
<mat-icon>add</mat-icon>
{{T.F.NOTE.NOTES_CMP.ADD_BTN|translate}}
</button>
<button mat-icon-button
(click)="onScrollToSidenavClick()">
<button (click)="onScrollToSidenavClick()"
mat-icon-button>
<mat-icon>arrow_upwards</mat-icon>
</button>
<!-- <button mat-icon-button>-->

View file

@ -66,16 +66,16 @@
flaws.</p>
<mat-form-field>
<textarea matInput
[placeholder]="T.F.PROCRASTINATION.REFRAME.TL1|translate"></textarea>
<textarea [placeholder]="T.F.PROCRASTINATION.REFRAME.TL1|translate"
matInput></textarea>
</mat-form-field>
<mat-form-field>
<textarea matInput
[placeholder]="T.F.PROCRASTINATION.REFRAME.TL2|translate"></textarea>
<textarea [placeholder]="T.F.PROCRASTINATION.REFRAME.TL2|translate"
matInput></textarea>
</mat-form-field>
<mat-form-field>
<textarea matInput
[placeholder]="T.F.PROCRASTINATION.REFRAME.TL3|translate"></textarea>
<textarea [placeholder]="T.F.PROCRASTINATION.REFRAME.TL3|translate"
matInput></textarea>
</mat-form-field>
</section>
</mat-tab>
@ -88,7 +88,8 @@
<task [task]="currentTask"></task>
<p style="margin-top: 16px;" [innerHTML]="T.F.PROCRASTINATION.SPLIT_UP.OUTRO|translate"></p>
<p [innerHTML]="T.F.PROCRASTINATION.SPLIT_UP.OUTRO|translate"
style="margin-top: 16px;"></p>
</section>
</mat-tab>
</mat-tab-group>

View file

@ -14,7 +14,7 @@ import {Subscription} from 'rxjs';
import {loadFromSessionStorage, saveToSessionStorage} from '../../../../core/persistence/local-storage';
import {GithubCfg} from '../../../issue/github/github';
import {DialogGithubInitialSetupComponent} from '../../../issue/github/dialog-github-initial-setup/dialog-github-initial-setup.component';
import {DEFAULT_ISSUE_PROVIDER_CFGS, GITHUB_TYPE, JIRA_TYPE} from '../../../issue/issue.const';
import {GITHUB_TYPE} from '../../../issue/issue.const';
import {T} from '../../../../t.const';
import {DEFAULT_JIRA_CFG} from '../../../issue/jira/jira.const';
import {DEFAULT_GITHUB_CFG} from '../../../issue/github/github.const';

View file

@ -3,6 +3,7 @@ h1, mat-dialog-actions, help-section {
direction: rtl;
}
}
.form-wrapper {
min-width: 280px;
}

View file

@ -1,6 +1,6 @@
<form (submit)="addTask()"
[class.mat-elevation-z2]="isElevated"
[class.mat-elevation-z1]="!isElevated"
[class.mat-elevation-z2]="isElevated"
class="add-task-form">
<div *ngIf="(isLoading$|async)"
class="spinner">

View file

@ -9,9 +9,9 @@
<div class="form-wrapper">
<datetime-input (modelChange)="dateTime=$event"
[model]="dateTime"
[placeholder]="T.F.TASK.D_REMINDER_ADD.DATETIME_FOR|translate"
[required]="true"
name="reminderDate"
[placeholder]="T.F.TASK.D_REMINDER_ADD.DATETIME_FOR|translate"></datetime-input>
name="reminderDate"></datetime-input>
<div *ngIf="isMoveToBacklogPossible"
style="margin: 16px 0;">

View file

@ -1,6 +1,5 @@
import {ChangeDetectionStrategy, Component, Inject} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import {Task} from '../task.model';
import {TaskService} from '../task.service';
import {ReminderCopy} from '../../reminder/reminder.model';
import {ReminderService} from '../../reminder/reminder.service';

View file

@ -6,8 +6,8 @@
<mat-dialog-content>
<help-section>
<div class="side-info"
[innerHTML]="T.F.TASK.D_TIME_FOR_DAY.HELP|translate">
<div [innerHTML]="T.F.TASK.D_TIME_FOR_DAY.HELP|translate"
class="side-info">
</div>
</help-section>
@ -16,9 +16,9 @@
<mat-form-field>
<input [(ngModel)]="newEntry.date"
[matDatepicker]="myDatepicker"
[placeholder]="T.F.TASK.D_TIME_FOR_DAY.DATE|translate"
matInput
name="date"
[placeholder]="T.F.TASK.D_TIME_FOR_DAY.DATE|translate"
required
type="text">
<mat-error>{{T.V.E_DATETIME|translate}}</mat-error>
@ -39,14 +39,14 @@
<mat-dialog-actions align="end">
<button [mat-dialog-close]="true"
color="primary"
type="button"
mat-button>
mat-button
type="button">
{{T.G.CANCEL|translate}}
</button>
<button type="submit"
color="primary"
mat-stroked-button>
<button color="primary"
mat-stroked-button
type="submit">
<mat-icon>save</mat-icon>
{{T.G.SAVE|translate}}
</button>

View file

@ -7,8 +7,8 @@
<mat-dialog-content>
<help-section>
<div class="side-info"
[innerHTML]="T.F.TASK.D_TIME_FOR_DAY.HELP|translate">
<div [innerHTML]="T.F.TASK.D_TIME_FOR_DAY.HELP|translate"
class="side-info">
</div>
</help-section>
@ -27,18 +27,18 @@
class="other-day">
<mat-form-field class="mat-icon-float mat-block">
<input [(ngModel)]="timeSpentOnDayCopy[strDate]"
[placeholder]="T.F.TASK.D_TIME.TIME_SPENT_ON|translate:{date:strDate}"
inputDuration="optional"
matInput
name="timeSpentOnDay{{strDate}}"
[placeholder]="T.F.TASK.D_TIME.TIME_SPENT_ON|translate:{date:strDate}"
type="text">
<mat-icon matPrefix>timer</mat-icon>
</mat-form-field>
<button (click)="deleteValue(strDate)"
[title]="T.F.TASK.D_TIME.DELETE_FOR|translate"
color=""
mat-icon-button
[title]="T.F.TASK.D_TIME.DELETE_FOR|translate"
type="button">
<mat-icon>delete_forever</mat-icon>
</button>
@ -59,15 +59,15 @@
<mat-dialog-actions align="end">
<button [mat-dialog-close]="true"
color="primary"
type="button"
mat-button>
mat-button
type="button">
{{T.G.CANCEL|translate}}
</button>
<button (click)="submit()"
type="submit"
color="primary"
mat-stroked-button>
mat-stroked-button
type="submit">
<mat-icon>save</mat-icon>
{{T.G.SAVE|translate}}
</button>

View file

@ -37,9 +37,9 @@
</button>
<ng-container *ngIf="!isError">
<button [matMenuTriggerFor]="snoozeMenu"
(dblclick)="snooze(10)"
<button (dblclick)="snooze(10)"
[disabled]="isDisableControls"
[matMenuTriggerFor]="snoozeMenu"
color="primary"
mat-button
type="button">
@ -64,28 +64,32 @@
type="button">
<mat-icon>play_arrow</mat-icon>
{{!isForCurrentProject
? (T.F.TASK.D_REMINDER_VIEW.SWITCH_PROJECT_START|translate)
: (T.F.TASK.D_REMINDER_VIEW.START|translate)}}
? (T.F.TASK.D_REMINDER_VIEW.SWITCH_PROJECT_START|translate)
: (T.F.TASK.D_REMINDER_VIEW.START|translate)}}
</button>
</ng-container>
</div>
</mat-dialog-actions>
<mat-menu #snoozeMenu="matMenu">
<button mat-menu-item
(click)="snooze(10)">
<mat-icon>snooze</mat-icon>{{T.G.MINUTES|translate:{m: 10} }}
<button (click)="snooze(10)"
mat-menu-item>
<mat-icon>snooze</mat-icon>
{{T.G.MINUTES|translate:{m: 10} }}
</button>
<button mat-menu-item
(click)="snooze(30)">
<mat-icon>snooze</mat-icon>{{T.G.MINUTES|translate:{m: 30} }}
<button (click)="snooze(30)"
mat-menu-item>
<mat-icon>snooze</mat-icon>
{{T.G.MINUTES|translate:{m: 30} }}
</button>
<button mat-menu-item
(click)="snooze(60)">
<mat-icon>snooze</mat-icon>{{T.G.MINUTES|translate:{m: 60} }}
<button (click)="snooze(60)"
mat-menu-item>
<mat-icon>snooze</mat-icon>
{{T.G.MINUTES|translate:{m: 60} }}
</button>
<button mat-menu-item
(click)="editReminder()">
<mat-icon>edit</mat-icon>{{T.G.EDIT|translate}}
<button (click)="editReminder()"
mat-menu-item>
<mat-icon>edit</mat-icon>
{{T.G.EDIT|translate}}
</button>
</mat-menu>

View file

@ -1,7 +1,7 @@
import {ChangeDetectionStrategy, Component, Inject, OnDestroy} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog';
import {Reminder} from '../../reminder/reminder.model';
import {Task, TaskWithReminderData} from '../task.model';
import {Task} from '../task.model';
import {TaskService} from '../task.service';
import {Observable, Subscription} from 'rxjs';
import {ReminderService} from '../../reminder/reminder.service';
@ -47,15 +47,15 @@ export class DialogViewTaskReminderComponent implements OnDestroy {
}));
}
ngOnDestroy(): void {
this._subs.unsubscribe();
}
get isError() {
// just for this dialog we make an exception about using getters
return !this.task && this.isForCurrentProject;
}
ngOnDestroy(): void {
this._subs.unsubscribe();
}
play() {
this.isDisableControls = true;
if (this.isForCurrentProject) {

View file

@ -1,8 +1,8 @@
<mat-form-field>
<input [formControl]="taskSelectCtrl"
[matAutocomplete]="auto"
matInput
[placeholder]="T.F.TASK.SELECT_OR_CREATE|translate"
matInput
required>
<mat-icon *ngIf="!isCreate"
matSuffix="">track_changes

View file

@ -1,6 +1,6 @@
<ng-container *ngIf="type==='input'">
<section class="input-item"
(click)="onInputItemClick()">
<section (click)="onInputItemClick()"
class="input-item">
<div class="input-item__title">
<ng-content select="[input-title]"></ng-content>
</div>
@ -8,9 +8,9 @@
<ng-content select="[input-value]"></ng-content>
</div>
<button mat-icon-button
<button class="input-item__edit-btn"
color="accent"
class="input-item__edit-btn">
mat-icon-button>
<mat-icon>{{inputIcon}}</mat-icon>
</button>

View file

@ -26,6 +26,10 @@ export class TaskAdditionalInfoItemComponent {
@HostBinding('tabindex') tabindex = 3;
constructor(
public elementRef: ElementRef
) {
}
@HostListener('keydown', ['$event']) onKeyDown(ev: KeyboardEvent) {
const tagName = (ev.target as HTMLElement).tagName.toLowerCase();
@ -55,11 +59,6 @@ export class TaskAdditionalInfoItemComponent {
}
}
constructor(
public elementRef: ElementRef
) {
}
focusEl() {
this.elementRef.nativeElement.focus();
}

View file

@ -1,6 +1,6 @@
<better-drawer-container [isOver]="isAlwaysOver || (layoutService.isNotesOver$|async)"
<better-drawer-container (wasClosed)="taskService.setSelectedId(null)"
[isOpen]="taskService.selectedTask$|async"
(wasClosed)="taskService.setSelectedId(null)"
[isOver]="isAlwaysOver || (layoutService.isNotesOver$|async)"
[sideWidth]="40">
<ng-container better-drawer-content>
<ng-content></ng-content>

View file

@ -1,5 +1,5 @@
import {animate, style, transition, trigger} from '@angular/animations';
import {ANI_ENTER_TIMING, ANI_LEAVE_TIMING} from '../../../ui/animations/animation.const';
import {ANI_ENTER_TIMING} from '../../../ui/animations/animation.const';
const ANI = [
style({opacity: 0, transform: 'scale(0.9)'}),

View file

@ -1,14 +1,14 @@
<div class="wrapper"
*ngIf="task.id"
[@taskAdditionalInfoTaskChange]="task.id">
<div *ngIf="task.id"
[@taskAdditionalInfoTaskChange]="task.id"
class="wrapper">
<task-additional-info-item
class="input-item --estimate"
*ngIf="task.parentId"
[inputIcon]="'arrow_forward'"
(collapseParent)="collapseParent()"
(editActionTriggered)="taskService.setSelectedId(task.parentId)"
(keyPress)="onItemKeyPress($event)"
(collapseParent)="collapseParent()">
*ngIf="task.parentId"
[inputIcon]="'arrow_forward'"
class="input-item --estimate">
<ng-container input-title>
<mat-icon>subdirectory_arrow_right</mat-icon>
<span>{{T.F.TASK.ADDITIONAL_INFO.PARENT|translate}}</span>
@ -22,12 +22,12 @@
</task-additional-info-item>
<task-additional-info-item
class="input-item --estimate"
*ngIf="!task.subTasks?.length"
[inputIcon]="'edit'"
(collapseParent)="collapseParent()"
(editActionTriggered)="estimateTime()"
(keyPress)="onItemKeyPress($event)"
(collapseParent)="collapseParent()">
*ngIf="!task.subTasks?.length"
[inputIcon]="'edit'"
class="input-item --estimate">
<ng-container input-title>
<mat-icon>timer</mat-icon>
<span>{{T.F.TASK.ADDITIONAL_INFO.TIME|translate}}</span>
@ -47,33 +47,33 @@
</task-additional-info-item>
<task-additional-info-item
class="input-item"
*ngIf="!task.repeatCfgId"
[inputIcon]="task.reminderId ? 'edit': 'add'"
(collapseParent)="collapseParent()"
(editActionTriggered)="editReminder()"
(keyPress)="onItemKeyPress($event)"
(collapseParent)="collapseParent()">
*ngIf="!task.repeatCfgId"
[inputIcon]="task.reminderId ? 'edit': 'add'"
class="input-item">
<ng-container input-title>
<mat-icon>alarm</mat-icon>
<span *ngIf="task.reminderId">{{T.F.TASK.ADDITIONAL_INFO.REMINDER|translate}}</span>
<span *ngIf="!task.reminderId">{{T.F.TASK.ADDITIONAL_INFO.SCHEDULE_TASK|translate}}</span>
</ng-container>
<ng-container input-value>
<div class="reminder-value"
matTooltipPosition="left"
*ngIf="reminderData$|async as reminderData"
[matTooltip]="reminderData.remindAt|date:'short'">
<div *ngIf="reminderData$|async as reminderData"
[matTooltip]="reminderData.remindAt|date:'short'"
class="reminder-value"
matTooltipPosition="left">
{{reminderData.remindAt|humanizeTimestamp}}
</div>
</ng-container>
</task-additional-info-item>
<task-additional-info-item
[type]="'panel'"
(collapseParent)="collapseParent()"
(keyPress)="onItemKeyPress($event)"
*ngIf="task.issueData"
[expanded]="true"
(keyPress)="onItemKeyPress($event)"
(collapseParent)="collapseParent()">
[type]="'panel'">
<ng-container panel-header>
<issue-header [task]="task"></issue-header>
</ng-container>
@ -87,11 +87,11 @@
<task-additional-info-item
#noteWrapperElRef
[type]="'panel'"
[expanded]="task.notes || (!(task.issueId) && !task.attachmentIds?.length)"
(keyPress)="onItemKeyPress($event)"
(collapseParent)="collapseParent()"
(editActionTriggered)="isFocusNotes=true">
(editActionTriggered)="isFocusNotes=true"
(keyPress)="onItemKeyPress($event)"
[expanded]="task.notes || (!(task.issueId) && !task.attachmentIds?.length)"
[type]="'panel'">
<ng-container panel-header>
<mat-icon *ngIf="task.notes">chat</mat-icon>
<mat-icon *ngIf="!task.notes">chat_bubble_outline</mat-icon>
@ -99,24 +99,24 @@
</ng-container>
<ng-container panel-content>
<inline-markdown (changed)="changeTaskNotes($event); isFocusNotes=false"
(blur)="isFocusNotes=false"
<inline-markdown (blur)="isFocusNotes=false"
(blurred)="isFocusNotes=false"
(changed)="changeTaskNotes($event); isFocusNotes=false"
(keyboardUnToggle)="focusItem(noteWrapperElRef)"
[isFocus]="isFocusNotes"
[model]="task.notes"
[isShowControls]="true"></inline-markdown>
[isShowControls]="true"
[model]="task.notes"></inline-markdown>
</ng-container>
</task-additional-info-item>
<task-additional-info-item
#attachmentPanelElRef
[type]="'panel'"
[expanded]="true"
*ngIf="issueAttachments?.length || (localAttachments$|async)?.length"
(collapseParent)="collapseParent()"
(keyPress)="onItemKeyPress($event)"
(collapseParent)="collapseParent()">
*ngIf="issueAttachments?.length || (localAttachments$|async)?.length"
[expanded]="true"
[type]="'panel'">
<ng-container panel-header>
<mat-icon>attachment</mat-icon>
<span>{{T.F.TASK.ADDITIONAL_INFO.ATTACHMENTS|translate:{nr: issueAttachments?.length + (localAttachments$|async)?.length} }}</span>
@ -128,8 +128,8 @@
<attachment-list [attachments]="issueAttachments"
[isDisableControls]="true"></attachment-list>
</ng-container>
<h3 class="mat-h3"
*ngIf="issueAttachments?.length"
<h3 *ngIf="issueAttachments?.length"
class="mat-h3"
style="margin-bottom: 0;">{{T.F.TASK.ADDITIONAL_INFO.LOCAL_ATTACHMENTS|translate}}</h3>
<attachment-list [attachments]="localAttachments$|async"></attachment-list>
</div>
@ -137,12 +137,12 @@
</task-additional-info-item>
<task-additional-info-item
class="input-item"
*ngIf="!issueAttachments?.length && !(localAttachments$|async)?.length"
[inputIcon]="'add'"
(collapseParent)="collapseParent()"
(editActionTriggered)="addAttachment()"
(keyPress)="onItemKeyPress($event)"
(collapseParent)="collapseParent()">
*ngIf="!issueAttachments?.length && !(localAttachments$|async)?.length"
[inputIcon]="'add'"
class="input-item">
<ng-container input-title>
<mat-icon>attachment</mat-icon>
<span>{{T.F.TASK.ADDITIONAL_INFO.ADD_ATTACHMENT|translate}}</span>
@ -153,12 +153,12 @@
<task-additional-info-item
class="input-item"
*ngIf="!task.parentId && !task.issueId"
[inputIcon]="task.repeatCfgId ? 'edit': 'add'"
(collapseParent)="collapseParent()"
(editActionTriggered)="editTaskRepeatCfg()"
(keyPress)="onItemKeyPress($event)"
(collapseParent)="collapseParent()">
*ngIf="!task.parentId && !task.issueId"
[inputIcon]="task.repeatCfgId ? 'edit': 'add'"
class="input-item">
<ng-container input-title>
<mat-icon
style="transform: rotate(45deg);">repeat
@ -166,9 +166,9 @@
<span>{{T.F.TASK.ADDITIONAL_INFO.REPEAT|translate}}</span>
</ng-container>
<ng-container input-value>
<div class="reminder-value"
matTooltipPosition="left"
*ngIf="repeatCfgDays$|async as repeatCfgDays">
<div *ngIf="repeatCfgDays$|async as repeatCfgDays"
class="reminder-value"
matTooltipPosition="left">
{{repeatCfgDays}}
</div>
</ng-container>

View file

@ -83,17 +83,14 @@ export class TaskAdditionalInfoComponent implements AfterViewInit, OnDestroy {
: of(null)
),
);
private _attachmentIds$ = new BehaviorSubject([]);
localAttachments$: Observable<Attachment[]> = this._attachmentIds$.pipe(
switchMap((ids) => this.attachmentService.getByIds$(ids))
);
parentId$ = new BehaviorSubject<string>(null);
parentTaskData$: Observable<TaskWithIssueData> = this.parentId$.pipe(
switchMap((id) => id ? this.taskService.getByIdWithIssueData$(id) : of(null))
);
private _attachmentIds$ = new BehaviorSubject([]);
localAttachments$: Observable<Attachment[]> = this._attachmentIds$.pipe(
switchMap((ids) => this.attachmentService.getByIds$(ids))
);
private _taskData: TaskWithSubTasks;
private _focusTimeout: number;
private _subs = new Subscription();
@ -109,6 +106,10 @@ export class TaskAdditionalInfoComponent implements AfterViewInit, OnDestroy {
) {
}
get task(): TaskWithSubTasks {
return this._taskData;
}
@Input() set task(newVal: TaskWithSubTasks) {
const prev = this._taskData;
this._taskData = newVal;
@ -123,10 +124,6 @@ export class TaskAdditionalInfoComponent implements AfterViewInit, OnDestroy {
}
}
get task(): TaskWithSubTasks {
return this._taskData;
}
get progress() {
return this._taskData && this._taskData.timeEstimate && (this._taskData.timeSpent / this._taskData.timeEstimate) * 100;
}

View file

@ -15,9 +15,9 @@
class="repeat-task-icon">repeat
</mat-icon>
<span *ngIf="task.parentId"></span>
<inline-input style="display: inline-block"
(changed)="updateTaskTitle(task, $event)"
[value]="task.title">
<inline-input (changed)="updateTaskTitle(task, $event)"
[value]="task.title"
style="display: inline-block">
</inline-input>
</div>
</td>
@ -67,10 +67,10 @@
mat-cell>
<button (click)="toggleTaskDone(task)"
[class.isDone]="task.isDone"
[title]="T.F.TASK.SUMMARY_TABLE.TOGGLE_DONE|translate"
class="check-done"
mat-icon-button
tabindex="2"
[title]="T.F.TASK.SUMMARY_TABLE.TOGGLE_DONE|translate">
tabindex="2">
<mat-icon aria-label="Mark as undone"
class="undo">undo
</mat-icon>

View file

@ -80,7 +80,8 @@ import {
selectStartableTaskIds,
selectStartableTasks,
selectTaskAdditionalInfoTargetPanel,
selectTaskById, selectTaskByIdWithIssueData,
selectTaskById,
selectTaskByIdWithIssueData,
selectTaskByIssueId,
selectTaskEntities,
selectTasksByRepeatConfigId,

View file

@ -1,22 +1,22 @@
<div class="inner-wrapper"
[class.isSelected]="isSelected">
<div [class.isSelected]="isSelected"
class="inner-wrapper">
<div style="visibility: hidden; position: fixed"
<div [matMenuTriggerFor]="menu"
[style.left]="contextMenuPosition.x"
[style.top]="contextMenuPosition.y"
[matMenuTriggerFor]="menu">
style="visibility: hidden; position: fixed">
</div>
<div class="box"></div>
<!-- TODO only bind pan etc when touch is available-->
<div (panend)="onPanEnd()"
<div (contextmenu)="openContextMenu($event)"
(panend)="onPanEnd()"
(panleft)="onPanLeft($event)"
(panright)="onPanRight($event)"
(panstart)="onPanStart($event)"
[class.isPreventPointerEventsWhilePanning]="isPreventPointerEventsWhilePanning"
class="first-line"
(contextmenu)="openContextMenu($event)">
class="first-line">
<ng-container *ngIf="isTouch">
@ -35,10 +35,10 @@
<button (click)="toggleTaskDone()"
*ngIf="task.isDone"
[title]="T.F.TASK.CMP.TOGGLE_DONE|translate"
class="check-done"
mat-icon-button
tabindex="2"
[title]="T.F.TASK.CMP.TOGGLE_DONE|translate">
tabindex="2">
<mat-icon @swirl
class="undo">undo
</mat-icon>
@ -49,9 +49,9 @@
<div class="title-and-left-btns-wrapper">
<div class="drag-handle"
[class.handle-par]="!task.parentId"
[class.handle-sub]="task.parentId">
<div [class.handle-par]="!task.parentId"
[class.handle-sub]="task.parentId"
class="drag-handle">
<mat-icon
class="drag-handle-ico"
svgIcon="drag_handle">
@ -62,20 +62,20 @@
<div class="type-ico-wrapper">
<mat-icon class="task-type-ico"
<mat-icon (click)="editTaskRepeatCfg()"
*ngIf="task.repeatCfgId"
(click)="editTaskRepeatCfg()"
[style.transform]="isCurrent ? 'scale(1.4) rotate(45deg)': 'rotate(45deg)'">repeat
[style.transform]="isCurrent ? 'scale(1.4) rotate(45deg)': 'rotate(45deg)'"
class="task-type-ico">repeat
</mat-icon>
<mat-icon class="task-type-ico"
(click)="handleUpdateBtnClick()"
<mat-icon (click)="handleUpdateBtnClick()"
*ngIf="task.issueData?.wasUpdated"
class="task-type-ico"
color="accent">update
</mat-icon>
<div class="task-type-ico"
*ngIf="!task.issueData?.wasUpdated && task.issueData">
<div *ngIf="!task.issueData?.wasUpdated && task.issueData"
class="task-type-ico">
<div *ngIf="task.issueData?.storyPoints"
class="mini-badge bgc-primary">{{task.issueData?.storyPoints}}</div>
<mat-icon [svgIcon]="task.issueType|issueIcon"></mat-icon>
@ -85,18 +85,18 @@
<div #contentEditableOnClickEl
(editFinished)="updateTaskTitleIfChanged($event.isChanged, $event.newVal)"
[value]="task.title"
[isResetAfterEdit]="true"
[value]="task.title"
class="task-title"
contenteditable="true"
contentEditableOnClick
contenteditable="true"
tabindex="2"></div>
</div>
<div class="all-controls-wrapper">
<div (click)="estimateTime()"
[class.isEditable]="!task.subTasks?.length"
[class.hasNoTimeSpentOrEstimate]="!task.timeSpent && !task.timeEstimate"
[class.isEditable]="!task.subTasks?.length"
class="time-wrapper">
<div *ngIf="!task.subTasks?.length"
class="time">
@ -122,84 +122,84 @@
<div class="hover-controls">
<button (click)="startTask()"
*ngIf="!task.isDone && !isCurrent && !task.subTasks"
[title]="T.F.TASK.CMP.TRACK_TIME|translate"
class="ico-btn start-task-btn"
color=""
mat-icon-button
tabindex="2"
[title]="T.F.TASK.CMP.TRACK_TIME|translate">
tabindex="2">
<mat-icon class="play-icon"
svgIcon="play"></mat-icon>
</button>
<button (click)="pauseTask()"
*ngIf="!task.isDone && isCurrent && !task.subTasks"
[title]="T.F.TASK.CMP.TRACK_TIME_STOP|translate"
class="ico-btn"
color="accent"
mat-icon-button
tabindex="2"
[title]="T.F.TASK.CMP.TRACK_TIME_STOP|translate">
tabindex="2">
<mat-icon>pause</mat-icon>
</button>
<button (click)="toggleTaskDone()"
[title]="T.F.TASK.CMP.TOGGLE_DONE|translate"
class="ico-btn task-done-btn"
color=""
mat-icon-button
tabindex="2"
[title]="T.F.TASK.CMP.TOGGLE_DONE|translate">
tabindex="2">
<mat-icon *ngIf="task.isDone">undo</mat-icon>
<mat-icon *ngIf="!task.isDone">check</mat-icon>
</button>
<button (click)="toggleShowAdditionalInfoOpen()"
*ngIf="!task.notes&&!task.issueData&&!isSelected"
[title]="T.F.TASK.CMP.TOGGLE_ADDITIONAL|translate"
class="ico-btn show-additional-info-btn"
color=""
mat-icon-button
tabindex="2"
[title]="T.F.TASK.CMP.TOGGLE_ADDITIONAL|translate">
tabindex="2">
<mat-icon>chat_bubble_outline</mat-icon>
</button>
</div>
<button (click)="editReminder()"
*ngIf="task.reminderId"
[title]="T.F.TASK.CMP.EDIT_REMINDER|translate"
class="ico-btn"
color=""
mat-icon-button
tabindex="2"
[title]="T.F.TASK.CMP.EDIT_REMINDER|translate">
tabindex="2">
<mat-icon>alarm</mat-icon>
</button>
<button (click)="toggleShowAttachments()"
*ngIf="task.attachmentIds?.length || (task.issueType==='JIRA' && task.issueData && task.issueData['attachments']?.length)"
[title]="T.F.TASK.CMP.TOGGLE_ATTACHMENTS|translate"
class="ico-btn attachment-btn"
color=""
mat-icon-button
tabindex="2"
[title]="T.F.TASK.CMP.TOGGLE_ATTACHMENTS|translate">
tabindex="2">
<mat-icon>attach_file</mat-icon>
</button>
<button (click)="toggleShowAdditionalInfoOpen()"
*ngIf="task.notes||task.issueData||isSelected"
[title]="T.F.TASK.CMP.TOGGLE_ADDITIONAL|translate"
class="ico-btn show-additional-info-btn"
color=""
mat-icon-button
tabindex="2"
[title]="T.F.TASK.CMP.TOGGLE_ADDITIONAL|translate">
tabindex="2">
<mat-icon *ngIf="!isSelected">chat</mat-icon>
<mat-icon *ngIf="isSelected">close</mat-icon>
</button>
<button [matMenuTriggerFor]="menu"
[style.pointer-events]="isContextMenuDisabled ? 'none' : 'all'"
<button (menuClosed)="isContextMenuDisabled = false"
(menuOpened)="isContextMenuDisabled = true"
(menuClosed)="isContextMenuDisabled = false"
[matMenuTriggerFor]="menu"
[style.pointer-events]="isContextMenuDisabled ? 'none' : 'all'"
[title]="T.F.TASK.CMP.OPEN_TASK_MENU|translate"
class="ico-btn menu-trigger show-touch-only"
color=""
mat-icon-button
[title]="T.F.TASK.CMP.OPEN_TASK_MENU|translate">
mat-icon-button>
<mat-icon>more_vert</mat-icon>
</button>
@ -285,8 +285,8 @@
<a *ngIf="task.issueData?.url"
[href]="task.issueData.url"
mat-menu-item
target="_blank"
tabindex="2">
tabindex="2"
target="_blank">
<mat-icon [svgIcon]="task.issueType|issueIcon"></mat-icon>
{{T.F.TASK.CMP.OPEN_ISSUE|translate}}
</a>
@ -325,18 +325,18 @@
{{T.F.TASK.CMP.DELETE|translate}}
</button>
<button mat-menu-item
tabindex="2"
*ngIf="!task.parentId && !task.issueId"
[matMenuTriggerFor]="advMenu">
<button *ngIf="!task.parentId && !task.issueId"
[matMenuTriggerFor]="advMenu"
mat-menu-item
tabindex="2">
{{T.F.TASK.CMP.ADVANCED|translate}}
</button>
</mat-menu>
<mat-menu #advMenu="matMenu">
<button mat-menu-item
<button *ngIf="!task.parentId && !task.issueId && !task.repeatCfgId"
[matMenuTriggerFor]="projectMenu"
*ngIf="!task.parentId && !task.issueId && !task.repeatCfgId">
mat-menu-item>
<mat-icon>forward</mat-icon>
{{T.F.TASK.CMP.MOVE_TO_OTHER_PROJECT|translate}}
</button>
@ -375,11 +375,11 @@
class="sub-tasks">
<button (click)="toggleSubTaskMode()"
*ngIf="task.subTasks && task.subTasks.length"
[title]="T.F.TASK.CMP.TOGGLE_SUB_TASK_VISIBILITY|translate"
class="toggle-sub-tasks-btn ico-btn mat-elevation-z2"
color=""
mat-mini-fab
tabindex="2"
[title]="T.F.TASK.CMP.TOGGLE_SUB_TASK_VISIBILITY|translate">
tabindex="2">
<mat-icon *ngIf="(task._showSubTasksMode===ShowSubTasksMode.HideAll)">add
</mat-icon>
<mat-icon *ngIf="(task._showSubTasksMode!==ShowSubTasksMode.HideAll)"

View file

@ -66,6 +66,26 @@ export class TaskComponent implements OnInit, OnDestroy, AfterViewInit {
@ViewChild(MatMenuTrigger, {static: true}) contextMenu: MatMenuTrigger;
@HostBinding('tabindex') tabIndex = 1;
private _dragEnterTarget: HTMLElement;
private _destroy$: Subject<boolean> = new Subject<boolean>();
private _currentPanTimeout: number;
constructor(
private readonly _taskService: TaskService,
private readonly _matDialog: MatDialog,
private readonly _configService: GlobalConfigService,
private readonly _issueService: IssueService,
private readonly _attachmentService: AttachmentService,
private readonly _elementRef: ElementRef,
private readonly _renderer: Renderer2,
private readonly _cd: ChangeDetectorRef,
public readonly projectService: ProjectService,
) {
}
public get progress() {
return this.task && this.task.timeEstimate && (this.task.timeSpent / this.task.timeEstimate) * 100;
}
// TODO do via observable
@HostBinding('class.isCurrent')
@ -89,27 +109,6 @@ export class TaskComponent implements OnInit, OnDestroy, AfterViewInit {
return 't-' + this.task.id;
}
private _dragEnterTarget: HTMLElement;
private _destroy$: Subject<boolean> = new Subject<boolean>();
private _currentPanTimeout: number;
constructor(
private readonly _taskService: TaskService,
private readonly _matDialog: MatDialog,
private readonly _configService: GlobalConfigService,
private readonly _issueService: IssueService,
private readonly _attachmentService: AttachmentService,
private readonly _elementRef: ElementRef,
private readonly _renderer: Renderer2,
private readonly _cd: ChangeDetectorRef,
public readonly projectService: ProjectService,
) {
}
public get progress() {
return this.task && this.task.timeEstimate && (this.task.timeSpent / this.task.timeEstimate) * 100;
}
// methods come last
@HostListener('keydown', ['$event']) onKeyDown(ev: KeyboardEvent) {
this._handleKeyboardShortcuts(ev);

View file

@ -27,8 +27,8 @@ import {TaskUiEffects} from './store/task-ui.effects';
import {TaskElectronEffects} from './store/task-electron.effects';
import {SubTaskTotalTimeSpentPipe} from './pipes/sub-task-total-time-spent.pipe';
import {SubTaskTotalTimeEstimatePipe} from './pipes/sub-task-total-time-estimate.pipe';
import { TaskAdditionalInfoItemComponent } from './task-additional-info/task-additional-info-item/task-additional-info-item.component';
import { TaskAdditionalInfoWrapperComponent } from './task-additional-info/task-additional-info-wrapper/task-additional-info-wrapper.component';
import {TaskAdditionalInfoItemComponent} from './task-additional-info/task-additional-info-item/task-additional-info-item.component';
import {TaskAdditionalInfoWrapperComponent} from './task-additional-info/task-additional-info-wrapper/task-additional-info-wrapper.component';
import {BetterDrawerModule} from '../../ui/better-drawer/better-drawer.module';
@NgModule({

View file

@ -11,21 +11,21 @@
<div *ngIf="!isShowAsText"
class="wrapper-wrapper"
[class.isNoCols]="!options.cols?.length"
class="wrapper-wrapper"
>
<button [matMenuTriggerFor]="addColMenu"
[matTooltip]="T.F.WORKLOG.EXPORT.ADD_COL|translate"
class="add-col"
color=""
[matTooltip]="T.F.WORKLOG.EXPORT.ADD_COL|translate"
matTooltipPosition="left"
mat-mini-fab>
mat-mini-fab
matTooltipPosition="left">
<mat-icon>add</mat-icon>
</button>
<mat-menu #addColMenu="matMenu">
<button mat-menu-item
<button (click)="addCol(colOpt.id)"
*ngFor="let colOpt of colOpts"
(click)="addCol(colOpt.id)">
mat-menu-item>
{{colOpt.title|translate}}
</button>
</mat-menu>
@ -61,9 +61,9 @@
</div>
<collapsible class="options-collapsible"
[isInline]="true"
[title]="T.F.WORKLOG.EXPORT.OPTIONS|translate">
<collapsible [isInline]="true"
[title]="T.F.WORKLOG.EXPORT.OPTIONS|translate"
class="options-collapsible">
<section class="options">
<div class="row">
<div class="col">

View file

@ -26,9 +26,9 @@
<button (click)="exportData(month.value,year.key, month.key)"
aria-label="export data"
class="mat-elevation-z1"
color="primary"
mat-mini-fab
class="mat-elevation-z1">
mat-mini-fab>
<mat-icon>call_made</mat-icon>
</button>
</h2>
@ -53,9 +53,9 @@
(click)="exportData(month.value,year.key, month.key, week.weekNr)"
[matTooltip]="week.start+'.-'+week.end+'. Days: '+ week.daysWorked+', Time: '+(week.timeSpent|msToString)"
aria-label="export data"
class="mat-elevation-z1"
color=""
mat-mini-fab
class="mat-elevation-z1">
mat-mini-fab>
<mat-icon>call_made</mat-icon>
</button>
</div>
@ -94,8 +94,8 @@
<td [class.isSubTask]="logEntry.task.parentId"
class="title">
<mat-icon *ngIf="logEntry.task.repeatCfgId"
class="repeat-task-icon"
[title]="T.F.WORKLOG.CMP.REPEATING_TASK|translate">repeat
[title]="T.F.WORKLOG.CMP.REPEATING_TASK|translate"
class="repeat-task-icon">repeat
</mat-icon>
<span class="task-title">{{logEntry.task.title}}</span>
</td>
@ -113,10 +113,10 @@
<td class="actions">
<button (click)="restoreTask(logEntry.task);"
*ngIf="!logEntry.task?.parentId && !logEntry.isNoRestore"
[title]="T.F.WORKLOG.CMP.RESTORE_TASK_FROM_ARCHIVE|translate"
aria-label="restore"
color=""
mat-icon-button
[title]="T.F.WORKLOG.CMP.RESTORE_TASK_FROM_ARCHIVE|translate">
mat-icon-button>
<mat-icon>settings_backup_restore</mat-icon>
</button>
</td>

View file

@ -5,9 +5,9 @@ import {BehaviorSubject, Observable} from 'rxjs';
providedIn: 'root'
})
export class ImexMetaService {
isDataImportInProgress = false;
private _isDataImportInProgress$ = new BehaviorSubject<boolean>(false);
isDataImportInProgress$: Observable<boolean> = this._isDataImportInProgress$.asObservable();
isDataImportInProgress = false;
constructor() {
this.isDataImportInProgress$.subscribe((val) => this.isDataImportInProgress = val);

View file

@ -7,14 +7,14 @@
<div class="dark-mode-toggle">
<mat-slide-toggle
[checked]="(configService.misc$|async)?.isDarkMode"
(change)="toggleDarkMode($event)">
(change)="toggleDarkMode($event)"
[checked]="(configService.misc$|async)?.isDarkMode">
{{T.PS.TOGGLE_DARK_MODE|translate}}
</mat-slide-toggle>
</div>
<section class="config-section "
*ngFor="let section of globalConfigFormCfg; trackBy:trackBySectionKey;">
<section *ngFor="let section of globalConfigFormCfg; trackBy:trackBySectionKey;"
class="config-section ">
<config-section (save)="saveGlobalCfg($event)"
[cfg]="globalCfg[section.key]"
[section]="section"></config-section>

View file

@ -8,8 +8,8 @@
<div *ngIf="isForToday"
style="text-align: center;">
<a class="back-btn"
mat-button
color="primary"
mat-button
routerLink="/work-view">
<mat-icon>chevron_left</mat-icon>
{{T.PDS.BACK|translate}}
@ -48,8 +48,8 @@
</div>
</div>
</div>
<div class="summary-point"
[title]="T.PDS.TIME_SPENT_ESTIMATE_TITLE|translate">
<div [title]="T.PDS.TIME_SPENT_ESTIMATE_TITLE|translate"
class="summary-point">
<mat-icon>timer</mat-icon>
<div class="summary-text">{{T.PDS.TIME_SPENT_AND_ESTIMATE_LABEL|translate}}
<div class="summary-val">{{timeWorked$|async|msToClockString}}
@ -80,13 +80,13 @@
</ng-template>
<ng-container *ngIf="(hasTasksForToday$|async); else noTasks">
<task-summary-table [day]="(dayStr$|async)"
[flatTasks]="(tasksWorkedOnOrDoneOrRepeatableFlat$|async)"
(updated)="onTaskSummaryEdit()"></task-summary-table>
<task-summary-table (updated)="onTaskSummaryEdit()"
[day]="(dayStr$|async)"
[flatTasks]="(tasksWorkedOnOrDoneOrRepeatableFlat$|async)"></task-summary-table>
<div style="text-align: center; margin-top: 8px; margin-bottom: 16px;">
<button [matMenuTriggerFor]="roundTimeActions"
mat-button
[title]="T.PDS.ROUND_TIME_SPENT_TITLE|translate">
[title]="T.PDS.ROUND_TIME_SPENT_TITLE|translate"
mat-button>
<mat-icon>restore</mat-icon>
{{T.PDS.ROUND_TIME_SPENT|translate}}
</button>
@ -133,8 +133,8 @@
</mat-tab>
<mat-tab [label]="T.PDS.EVALUATION|translate"
*ngIf="!(configService.misc$|async)?.isHideEvaluationSheet">
<mat-tab *ngIf="!(configService.misc$|async)?.isHideEvaluationSheet"
[label]="T.PDS.EVALUATION|translate">
<section class="tab-inner"
style="max-width: 600px">
<evaluation-sheet (save)="onEvaluationSave()"

View file

@ -8,7 +8,7 @@ import {RouterModule} from '@angular/router';
import {WorklogModule} from '../../features/worklog/worklog.module';
import {MetricModule} from '../../features/metric/metric.module';
import {TasksModule} from '../../features/tasks/tasks.module';
import { PlanTasksTomorrowComponent } from './plan-tasks-tomorrow/plan-tasks-tomorrow.component';
import {PlanTasksTomorrowComponent} from './plan-tasks-tomorrow/plan-tasks-tomorrow.component';
import {BetterDrawerModule} from '../../ui/better-drawer/better-drawer.module';
@NgModule({

View file

@ -1,5 +1,5 @@
<div class="task-list-wrapper">
<section class="add-task-bar-wrapper">
<section class="add-task-bar-wrapper">
<add-task-bar [isAddToBottom]="true"
[isDisableAutoFocus]="true"></add-task-bar>
</section>

View file

@ -5,7 +5,7 @@
max-width: 628px;
}
:host::ng-deep .hover-controls{
:host::ng-deep .hover-controls {
.task-done-btn,
.start-task-btn {
display: none !important;

View file

@ -9,6 +9,7 @@ import {T} from '../../t.const';
})
export class MetricPageComponent {
T = T;
constructor() {
}
}

View file

@ -21,39 +21,39 @@
<div class="issue-providers">
<mat-icon *ngIf="project.issueIntegrationCfgs?.JIRA?.isEnabled"
svgIcon="jira"
[title]="T.PP.JIRA_CONFIGURED|translate"></mat-icon>
[title]="T.PP.JIRA_CONFIGURED|translate"
svgIcon="jira"></mat-icon>
<mat-icon *ngIf="project.issueIntegrationCfgs?.GITHUB?.repo"
svgIcon="github"
[title]="T.PP.GITHUB_CONFIGURED|translate"></mat-icon>
[title]="T.PP.GITHUB_CONFIGURED|translate"
svgIcon="github"></mat-icon>
</div>
<div class="controls">
<button (click)="edit(project)"
[title]="T.PP.EDIT_PROJECT|translate"
color=""
mat-icon-button
[title]="T.PP.EDIT_PROJECT|translate">
mat-icon-button>
<mat-icon>edit</mat-icon>
</button>
<button (click)="archive(project.id)"
[disabled]="project.id === (projectService.currentId$|async)"
[title]="T.PP.ARCHIVE_PROJECT|translate"
color=""
mat-icon-button
[title]="T.PP.ARCHIVE_PROJECT|translate">
mat-icon-button>
<mat-icon>archive</mat-icon>
</button>
<button (click)="export(project.id, project.title)"
[title]="T.PP.EXPORT_PROJECT|translate"
class="hide-xs"
color=""
mat-icon-button
[title]="T.PP.EXPORT_PROJECT|translate">
mat-icon-button>
<mat-icon>flight</mat-icon>
</button>
<button (click)="remove(project.id)"
[disabled]="project.id === (projectService.currentId$|async)"
[title]="T.PP.DELETE_PROJECT|translate"
color="warn"
mat-icon-button
[title]="T.PP.DELETE_PROJECT|translate">
mat-icon-button>
<mat-icon>delete</mat-icon>
</button>
</div>
@ -97,25 +97,25 @@
<div class="issue-providers">
<mat-icon *ngIf="project.issueIntegrationCfgs?.JIRA?.isEnabled"
svgIcon="jira"
[title]="T.PP.JIRA_CONFIGURED|translate"></mat-icon>
[title]="T.PP.JIRA_CONFIGURED|translate"
svgIcon="jira"></mat-icon>
<mat-icon *ngIf="project.issueIntegrationCfgs?.GITHUB?.repo"
svgIcon="github"
[title]="T.PP.GITHUB_CONFIGURED|translate"></mat-icon>
[title]="T.PP.GITHUB_CONFIGURED|translate"
svgIcon="github"></mat-icon>
</div>
<div class="controls">
<button (click)="unarchive(project.id)"
[title]="T.PP.UN_ARCHIVE_PROJECT|translate"
color=""
mat-icon-button
[title]="T.PP.UN_ARCHIVE_PROJECT|translate">
mat-icon-button>
<mat-icon>unarchive</mat-icon>
</button>
<button (click)="remove(project.id)"
*ngIf="project.id !== (projectService.currentId$|async)"
[title]="T.PP.DELETE_PROJECT|translate"
color="warn"
mat-icon-button
[title]="T.PP.DELETE_PROJECT|translate">
mat-icon-button>
<mat-icon>delete</mat-icon>
</button>
</div>

View file

@ -3,7 +3,6 @@ import {CommonModule} from '@angular/common';
import {ProjectSettingsComponent} from './project-settings.component';
import {UiModule} from '../../ui/ui.module';
import {ConfigModule} from '../../features/config/config.module';
import {GoogleModule} from '../../features/google/google.module';
import {JiraModule} from '../../features/issue/jira/jira.module';

View file

@ -18,20 +18,20 @@
<mat-card-content>
<div class="content">
<button (click)="startTask(task)"
color=""
class="mat-elevation-z1 start-task-btn"
matTooltipPosition="right"
[matTooltip]="T.SCHEDULE.START_TASK|translate"
mat-mini-fab>
class="mat-elevation-z1 start-task-btn"
color=""
mat-mini-fab
matTooltipPosition="right">
<mat-icon>play_arrow</mat-icon>
</button>
<div class="task-info">
<div class="title">
<div class="task-title"
(editFinished)="updateTaskTitleIfChanged($event.isChanged, $event.newVal, task)"
contenteditable="true"
contentEditableOnClick>{{task.title}}</div>
<div (editFinished)="updateTaskTitleIfChanged($event.isChanged, $event.newVal, task)"
class="task-title"
contentEditableOnClick
contenteditable="true">{{task.title}}</div>
<div *ngIf="(projectService.getById$(task.reminderData.projectId)|async) as project"
class="project">
<div [ngStyle]="getThemeColor(project.theme?.primary || project.themeColor)"
@ -39,11 +39,11 @@
<div class="project-title">{{project.title}}</div>
</div>
</div>
<div class="due-date"
<div (click)="editReminder(task)"
[matTooltip]="task.reminderData.remindAt|date:'short'"
class="due-date"
mat-ripple
(click)="editReminder(task)"
matTooltipPosition="left"
[matTooltip]="task.reminderData.remindAt|date:'short'">
matTooltipPosition="left">
<div class="date">
{{task.reminderData.remindAt|humanizeTimestamp}}
</div>

View file

@ -1,8 +1,8 @@
<div class="wrapper">
<div class="task-list-wrapper">
<task-list [noTasksMsg]="T.BL.NO_TASKS|translate"
<task-list [isBacklog]="true"
[noTasksMsg]="T.BL.NO_TASKS|translate"
[tasks]="backlogTasks$|async"
[isBacklog]="true"
class="isHidePlayBtn"
listId="PARENT"
listModelId="BACKLOG"></task-list>

View file

@ -89,8 +89,8 @@
@expandFade
class="planning-mode-content">
<add-task-bar (done)="startWork()"
[isDoubleEnterMode]="true"
[isAddToBottom]="true"></add-task-bar>
[isAddToBottom]="true"
[isDoubleEnterMode]="true"></add-task-bar>
<button (click)="startWork()"
class="read-to-work-btn"
color="primary"

View file

@ -53,23 +53,13 @@ export class WorkViewPageComponent implements OnInit, OnDestroy, AfterContentIni
),
map(v => v[0]),
);
splitTopEl$ = new ReplaySubject<HTMLElement>(1);
upperContainerScroll$ = this.projectService.isProjectChanging$.pipe(
filter(isChanging => !isChanging),
delay(50),
switchMap(() => this.splitTopEl$),
switchMap((el) => fromEvent(el, 'scroll')),
);
@ViewChild('splitTopEl', {static: false, read: ElementRef}) set splitTopElRef(ref: ElementRef) {
if (ref) {
this.splitTopEl$.next(ref.nativeElement);
}
}
splitTopEl$ = new ReplaySubject<HTMLElement>(1);
private _subs = new Subscription();
private _switchListAnimationTimeout: number;
@ -86,6 +76,11 @@ export class WorkViewPageComponent implements OnInit, OnDestroy, AfterContentIni
) {
}
@ViewChild('splitTopEl', {static: false, read: ElementRef}) set splitTopElRef(ref: ElementRef) {
if (ref) {
this.splitTopEl$.next(ref.nativeElement);
}
}
ngOnInit() {
const sub = this._dragulaService.find(SUB);

View file

@ -1,18 +1,18 @@
<div class="content"
#contentElRef>
<div #contentElRef
class="content">
<ng-content select="[better-drawer-content]"></ng-content>
</div>
<div class="backdrop"
(click)="close()"
<div (click)="close()"
*ngIf="isOpenGet && isOverGet"
@fade></div>
@fade
class="backdrop"></div>
<div class="side"
[style]="sideStyle">
<button class="close-btn"
(click)="close()">
<div [style]="sideStyle"
class="side">
<button (click)="close()"
class="close-btn">
&times;
</button>
<div class="side-inner">

View file

@ -1,6 +1,6 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import { BetterDrawerContainerComponent } from './better-drawer-container.component';
import {BetterDrawerContainerComponent} from './better-drawer-container.component';
describe('BetterDrawerContainerComponent', () => {
let component: BetterDrawerContainerComponent;
@ -8,9 +8,9 @@ describe('BetterDrawerContainerComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BetterDrawerContainerComponent ]
declarations: [BetterDrawerContainerComponent]
})
.compileComponents();
.compileComponents();
}));
beforeEach(() => {

View file

@ -14,7 +14,7 @@ import {
import {fadeAnimation} from '../../animations/fade.ani';
import {DomSanitizer, SafeStyle} from '@angular/platform-browser';
import {Observable, ReplaySubject, Subscription} from 'rxjs';
import {distinctUntilChanged, filter, map, share, switchMap, tap} from 'rxjs/operators';
import {distinctUntilChanged, filter, map, share, switchMap} from 'rxjs/operators';
import {observeWidth} from '../../../util/resize-observer-obs';
import {MainContainerClass} from '../../../app.constants';
@ -31,35 +31,8 @@ const VERY_SMALL_CONTAINER_WIDTH = 450;
})
export class BetterDrawerContainerComponent implements OnInit, AfterContentInit, OnDestroy {
@Input() sideWidth: number;
@Input() set isOpen(v: boolean) {
this._isOpen = v;
this._updateStyle();
}
@HostBinding('class.isOpen') get isOpenGet() {
return this._isOpen;
}
@Input() set isOver(v: boolean) {
this._isOver = v;
this._updateStyle();
}
@HostBinding('class.isOver') get isOverGet() {
return this._isOver;
}
@Output() wasClosed = new EventEmitter<void>();
@ViewChild('contentElRef', {static: false, read: ElementRef}) set setContentElRef(ref: ElementRef) {
if (ref) {
this.contentEl$.next(ref.nativeElement);
}
}
contentEl$ = new ReplaySubject<HTMLElement>(1);
containerWidth$: Observable<number> = this.contentEl$.pipe(
filter(el => !!el),
switchMap((el) => observeWidth(el)),
@ -74,20 +47,43 @@ export class BetterDrawerContainerComponent implements OnInit, AfterContentInit,
map(v => v < VERY_SMALL_CONTAINER_WIDTH),
distinctUntilChanged(),
);
sideStyle: SafeStyle;
private _isOpen: boolean;
private _isOver: boolean;
private _subs = new Subscription();
constructor(
private _elementRef: ElementRef,
private _domSanitizer: DomSanitizer,
) {
}
@HostBinding('class.isOpen') get isOpenGet() {
return this._isOpen;
}
@HostBinding('class.isOver') get isOverGet() {
return this._isOver;
}
@ViewChild('contentElRef', {static: false, read: ElementRef}) set setContentElRef(ref: ElementRef) {
if (ref) {
this.contentEl$.next(ref.nativeElement);
}
}
private _isOpen: boolean;
@Input() set isOpen(v: boolean) {
this._isOpen = v;
this._updateStyle();
}
private _isOver: boolean;
@Input() set isOver(v: boolean) {
this._isOver = v;
this._updateStyle();
}
ngOnInit(): void {
this._updateStyle();
}

View file

@ -1,7 +1,6 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BetterDrawerContainerComponent } from './better-drawer-container/better-drawer-container.component';
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {BetterDrawerContainerComponent} from './better-drawer-container/better-drawer-container.component';
@NgModule({
@ -15,4 +14,5 @@ import { BetterDrawerContainerComponent } from './better-drawer-container/better
CommonModule
],
})
export class BetterDrawerModule { }
export class BetterDrawerModule {
}

View file

@ -7,16 +7,16 @@
{{ modelItem.title}}
<mat-icon matChipRemove
[matTooltip]="T.G.REMOVE|translate">cancel
<mat-icon [matTooltip]="T.G.REMOVE|translate"
matChipRemove>cancel
</mat-icon>
<button mat-icon-button
<button (click)="additionalAction.emit(modelItem.id)"
*ngIf="additionalActionIcon"
class="additional"
[class.isToggled]="isToggled(modelItem.id)"
(click)="additionalAction.emit(modelItem.id)"
[matTooltip]="isToggled(modelItem.id) ? additionalActionTooltipUnToggle: additionalActionTooltip">
[matTooltip]="isToggled(modelItem.id) ? additionalActionTooltipUnToggle: additionalActionTooltip"
class="additional"
mat-icon-button>
<mat-icon style="transform: rotate(45deg)">{{additionalActionIcon}}
</mat-icon>
</button>

View file

@ -30,29 +30,17 @@ export class ChipListInputComponent {
@Input() additionalActionTooltip: string;
@Input() additionalActionTooltipUnToggle: string;
@Input() toggledItems: string[];
@Input() set suggestions(val) {
this.suggestionsIn = val.sort((a, b) => a.title.localeCompare(b.title));
this._updateModelItems(this._modelIds);
}
suggestionsIn: Suggestion[];
@Input() set model(v: string[]) {
this._modelIds = v;
this._updateModelItems(v);
}
@Output() addItem = new EventEmitter<string>();
@Output() addNewItem = new EventEmitter<string>();
@Output() removeItem = new EventEmitter<string>();
@Output() additionalAction = new EventEmitter<string>();
modelItems: Suggestion[];
inputCtrl = new FormControl();
separatorKeysCodes: number[] = [ENTER, COMMA];
@ViewChild('inputElRef', {static: true}) inputEl: ElementRef<HTMLInputElement>;
@ViewChild('autoElRef', {static: true}) matAutocomplete: MatAutocomplete;
private _modelIds: string[] = [];
filteredSuggestions: Observable<Suggestion[]> = this.inputCtrl.valueChanges.pipe(
startWith(''),
map((val: string | null) => val
@ -60,14 +48,19 @@ export class ChipListInputComponent {
: this.suggestionsIn.filter(suggestion => !this._modelIds || !this._modelIds.includes(suggestion.id)))
);
@ViewChild('inputElRef', {static: true}) inputEl: ElementRef<HTMLInputElement>;
@ViewChild('autoElRef', {static: true}) matAutocomplete: MatAutocomplete;
private _modelIds: string[] = [];
constructor() {
}
@Input() set suggestions(val) {
this.suggestionsIn = val.sort((a, b) => a.title.localeCompare(b.title));
this._updateModelItems(this._modelIds);
}
@Input() set model(v: string[]) {
this._modelIds = v;
this._updateModelItems(v);
}
add(event: MatChipInputEvent): void {
if (!this.matAutocomplete.isOpen) {
const input = event.input;

View file

@ -26,7 +26,7 @@
<mat-chip (click)="setCommonVal('2H')">{{T.DATETIME_INPUT.IN|translate:{time: '2h'} }}</mat-chip>
<mat-chip (click)="setCommonVal('5H')">{{T.DATETIME_INPUT.IN|translate:{time: '5h'} }}</mat-chip>
<mat-chip (click)="setCommonVal('TOMORROW_11')">{{T.DATETIME_INPUT.TOMORROW|translate:{time: '11:00'} }}</mat-chip>
<mat-chip *ngIf="lastVal"
(click)="setLastVal()">{{lastVal|date:'short'}}</mat-chip>
<mat-chip (click)="setLastVal()"
*ngIf="lastVal">{{lastVal|date:'short'}}</mat-chip>
</mat-chip-list>
</div>

View file

@ -26,15 +26,15 @@ export class DatetimeInputComponent {
}
}
get model() {
return this.nrValue;
}
@Input()
set model(v: number) {
this._updateValues(v);
}
get model() {
return this.nrValue;
}
updateFromInput(v: number) {
this._updateValues(v, true);
}

View file

@ -16,9 +16,9 @@
<input (ngModelChange)="onInputChange($event)"
[id]="uid"
[ngModel]="_model"
[placeholder]="T.G.CLICK_TO_EDIT|translate"
class="value"
inputDuration="optional"
[placeholder]="T.G.CLICK_TO_EDIT|translate"
spellcheck="false"
type="text">
</div>

View file

@ -5,8 +5,8 @@
(blur)="untoggleShowEdit(); setBlur($event)"
(focus)="setFocus($event)"
(input)="resizeTextareaToFit()"
(keypress)="keypressHandler($event)"
(keydown)="keypressHandler($event)"
(keypress)="keypressHandler($event)"
*ngIf="isShowEdit || (isTurnOffMarkdownParsing$|async)"
[@fade]
[ngModel]="modelCopy"
@ -17,18 +17,18 @@
<div #previewEl
(click)="toggleShowEdit($event)"
(focus)="toggleShowEdit($event)"
*ngIf="!(isTurnOffMarkdownParsing$|async)"
[data]="model"
[hidden]="isShowEdit"
*ngIf="!(isTurnOffMarkdownParsing$|async)"
class="mat-body-1 markdown-parsed"
markdown
tabindex="1"></div>
</div>
<div class="controls"
*ngIf="isShowControls">
<button mat-icon-button
(click)="openFullScreen()">
<div *ngIf="isShowControls"
class="controls">
<button (click)="openFullScreen()"
mat-icon-button>
<mat-icon>fullscreen</mat-icon>
</button>
</div>

View file

@ -50,14 +50,27 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
map(cfg => cfg && cfg.isTurnOffMarkdown),
startWith(false),
);
private _hideOverFlowTimeout: number;
constructor(
private _electronService: ElectronService,
private _cd: ChangeDetectorRef,
private _globalConfigService: GlobalConfigService,
private _matDialog: MatDialog,
) {
this.resizeParsedToFit();
}
@HostBinding('class.isFocused') get isFocused() {
return this.isShowEdit;
}
private _hideOverFlowTimeout: number;
private _model: string;
get model() {
return this._model;
}
@Input() set model(v: string) {
this._model = v;
this.modelCopy = v;
@ -69,20 +82,6 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
}
}
get model() {
return this._model;
}
constructor(
private _electronService: ElectronService,
private _cd: ChangeDetectorRef,
private _globalConfigService: GlobalConfigService,
private _matDialog: MatDialog,
) {
this.resizeParsedToFit();
}
@Input() set isFocus(val: boolean) {
if (!this.isShowEdit && val) {
this.toggleShowEdit();

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 287 KiB

After

Width:  |  Height:  |  Size: 301 KiB

Before After
Before After

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#2b5797</TileColor>
</tile>
</msapplication>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#2b5797</TileColor>
</tile>
</msapplication>
</browserconfig>

View file

@ -1,9 +1,30 @@
<svg version="1.1" viewBox="0 0 30 30" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg"
focusable="false">
<circle cx="12" cy="9" r="1.5" class="clr-i-outline clr-i-outline-path-1"></circle>
<circle cx="12" cy="21" r="1.5" class="clr-i-outline clr-i-outline-path-2"></circle>
<circle cx="18" cy="9" r="1.5" class="clr-i-outline clr-i-outline-path-3"></circle>
<circle cx="18" cy="21" r="1.5" class="clr-i-outline clr-i-outline-path-4"></circle>
<circle cx="18" cy="15" r="1.5" class="clr-i-outline clr-i-outline-path-5"></circle>
<circle cx="12" cy="15" r="1.5" class="clr-i-outline clr-i-outline-path-6"></circle>
<svg focusable="false"
preserveAspectRatio="xMidYMid meet"
version="1.1"
viewBox="0 0 30 30"
xmlns="http://www.w3.org/2000/svg">
<circle class="clr-i-outline clr-i-outline-path-1"
cx="12"
cy="9"
r="1.5"></circle>
<circle class="clr-i-outline clr-i-outline-path-2"
cx="12"
cy="21"
r="1.5"></circle>
<circle class="clr-i-outline clr-i-outline-path-3"
cx="18"
cy="9"
r="1.5"></circle>
<circle class="clr-i-outline clr-i-outline-path-4"
cx="18"
cy="21"
r="1.5"></circle>
<circle class="clr-i-outline clr-i-outline-path-5"
cx="18"
cy="15"
r="1.5"></circle>
<circle class="clr-i-outline clr-i-outline-path-6"
cx="12"
cy="15"
r="1.5"></circle>
</svg>

Before

Width:  |  Height:  |  Size: 661 B

After

Width:  |  Height:  |  Size: 856 B

Before After
Before After

View file

@ -1,5 +1,11 @@
<svg width="1024" height="1000" viewBox="0 0 1024 1000" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd"
<svg fill="none"
height="1000"
viewBox="0 0 1024 1000"
width="1024"
xmlns="http://www.w3.org/2000/svg">
<path clip-rule="evenodd"
d="M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z"
transform="scale(64)" fill="currentColor"/>
fill="currentColor"
fill-rule="evenodd"
transform="scale(64)" />
</svg>

Before

Width:  |  Height:  |  Size: 991 B

After

Width:  |  Height:  |  Size: 1 KiB

Before After
Before After

View file

@ -1,20 +1,27 @@
<svg xmlns="http://www.w3.org/2000/svg" id="JIRA_-_Blue" viewBox="61 -48.7 256 256">
<style id="style3">.st0{fill:currentColor}</style>
<g id="g3051" transform="translate(-25.053 -71.833) scale(1.54217)">
<svg id="JIRA_-_Blue"
viewBox="61 -48.7 256 256"
xmlns="http://www.w3.org/2000/svg">
<style id="style3">.st0 {
fill: currentColor
}</style>
<g id="g3051"
transform="translate(-25.053 -71.833) scale(1.54217)">
<g id="g17">
<g id="g19">
<g id="g21">
<g id="g23">
<path class="st0"
d="M103.1 24.9c-6 0-10.9 4.9-10.9 10.9s4.9 10.9 10.9 10.9S114 41.8 114 35.8c-.1-6-4.9-10.9-10.9-10.9z"
id="path25" fill="currentColor"/>
fill="currentColor"
id="path25" />
</g>
</g>
<g id="g27">
<g id="g29">
<path class="st0"
d="M174.5 24.9c-6 0-10.9 4.9-10.9 10.9s4.9 10.9 10.9 10.9 10.9-4.9 10.9-10.9-4.9-10.9-10.9-10.9z"
id="path31" fill="currentColor"/>
fill="currentColor"
id="path31" />
</g>
</g>
</g>
@ -22,22 +29,26 @@
<g id="g35">
<path class="st0"
d="M138.8 15c-6 0-10.9 4.9-10.9 10.9s4.9 10.9 10.9 10.9 10.9-4.9 10.9-10.9c0-6.1-4.9-10.9-10.9-10.9z"
id="path37" fill="currentColor"/>
fill="currentColor"
id="path37" />
</g>
</g>
</g>
<g id="g39">
<path class="st0"
d="M200.3 55.3c-.6-.5-1.3-.7-2.1-.7-.4 0-.8.1-1.2.2-7.4 2.8-14.8 5-21.7 6.5-1.4.3-2.5 1.4-3 2.6-5 13.6-17.7 26.6-31 40.2-.5.5-1.3 1.2-2.5 1.2s-2-.6-2.5-1.2c-13.3-13.6-26-26.5-31-40.2-.5-1.2-1.6-2.3-3-2.6-6.8-1.6-14.3-3.8-21.7-6.6-.4-.2-.8-.2-1.2-.2-.7 0-1.5.2-2.1.7-.9.7-1.4 1.9-1.3 3 1.1 11.3 5.6 22.4 13.7 34 7.6 10.9 17.5 21 27.1 30.8 17.6 18 34.3 35 35.8 54.7a3.4 3.4 0 0 0 3.4 3.2h20.7c.9 0 1.8-.4 2.5-1.1.6-.7 1-1.6.9-2.5-.7-13.2-5.6-26.4-15.2-40.4-2-2.9-4.1-5.8-6.4-8.6-.9-1.1-.5-2.5.2-3.3l2.1-2.1c9.6-9.8 19.5-19.9 27.1-30.8 8.1-11.6 12.6-22.6 13.7-34 .1-.9-.4-2.1-1.3-2.8z"
id="path41" fill="currentColor"/>
fill="currentColor"
id="path41" />
<g id="g43">
<path class="st0"
d="M116.5 138.4c-.5-.5-1.2-1-2.4-1-1.5 0-2.5 1.1-2.8 1.6-8.7 13.3-13.2 25.8-13.8 38.4 0 .9.3 1.9.9 2.5.6.7 1.5 1.1 2.5 1.1h20.7c1.8 0 3.3-1.4 3.4-3.2.5-6.1 2.3-12.1 5.8-18.5 1.2-2.2.3-4.3-.4-5.2-3.5-4.5-7.6-9.2-13.9-15.7z"
id="path45" fill="currentColor"/>
fill="currentColor"
id="path45" />
</g>
<path class="st0"
d="M138.8 65.4c6.5 0 10.3-.4 11.6-.4 1.6 0 3.1 1.3 3.1 3.2 0 .5-.1.9-.3 1.3-.9 2.3-4.8 10.6-12.1 17.7-.8.8-1.8.9-2.4.9-.6 0-1.6-.1-2.4-.9-7.3-7.1-11.2-15.4-12.1-17.7-.1-.3-.3-.7-.3-1.3 0-1.8 1.5-3.2 3.1-3.2 1.5 0 5.3.4 11.8.4z"
id="path47" fill="currentColor"/>
fill="currentColor"
id="path47" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

View file

@ -1,8 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg"
<svg fill="currentColor"
id="svg3360"
version="1.1"
fill="currentColor"
viewBox="0 0 24 24">
<polygon points="3,3 21,12 3,21" style="stroke:currentColor;stroke-width:1.5;stroke-opacity:1" fill-opacity="0"
stroke-opacity="1" stroke-linejoin="round"/>
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<polygon fill-opacity="0"
points="3,3 21,12 3,21"
stroke-linejoin="round"
stroke-opacity="1"
style="stroke:currentColor;stroke-width:1.5;stroke-opacity:1" />
</svg>

Before

Width:  |  Height:  |  Size: 305 B

After

Width:  |  Height:  |  Size: 339 B

Before After
Before After

View file

@ -1,21 +1,25 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="1024.000000pt" height="1024.000000pt" viewBox="0 0 1024.000000 1024.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.11, written by Peter Selinger 2001-2013
</metadata>
<g transform="translate(0.000000,1024.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M4785 10230 c-1318 -97 -2500 -656 -3398 -1608 -1037 -1099 -1534
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg height="1024.000000pt"
preserveAspectRatio="xMidYMid meet"
version="1.0"
viewBox="0 0 1024.000000 1024.000000"
width="1024.000000pt"
xmlns="http://www.w3.org/2000/svg">
<metadata>
Created by potrace 1.11, written by Peter Selinger 2001-2013
</metadata>
<g fill="#000000"
stroke="none"
transform="translate(0.000000,1024.000000) scale(0.100000,-0.100000)">
<path d="M4785 10230 c-1318 -97 -2500 -656 -3398 -1608 -1037 -1099 -1534
-2623 -1347 -4133 231 -1861 1460 -3445 3208 -4133 436 -172 866 -275 1382
-333 218 -24 761 -24 985 0 787 86 1486 317 2134 705 1352 809 2259 2203 2451
3766 159 1297 -183 2606 -956 3659 l-72 98 -174 -318 c-95 -175 -914 -1672
-1818 -3326 -905 -1654 -1649 -3006 -1655 -3005 -13 4 -4136 3461 -4131 3465
1 1 864 -346 1917 -772 1053 -427 1919 -774 1926 -773 8 2 2540 3210 3805
4820 l29 37 -73 83 c-559 642 -1236 1121 -2008 1423 -442 173 -882 279 -1370
330 -172 19 -666 27 -835 15z"/>
</g>
330 -172 19 -666 27 -835 15z" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before After
Before After

View file

@ -1,7 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 64 64">
<svg viewBox="0 0 64 64"
xmlns="http://www.w3.org/2000/svg">
<path id="path3395"
style="fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.46761858;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:13.80000019;stroke-dasharray:none;stroke-opacity:1"
d="M 0.65537046,34.582787 32.452267,63.855301 63.791548,0.94356422 30.222644,47.722023 Z"/>
<path d="M 0.65537046,34.582787 32.452267,63.855301 63.791548,0.94356422 30.222644,47.722023 Z"
id="path3395"
style="fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.46761858;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:13.80000019;stroke-dasharray:none;stroke-opacity:1" />
</svg>

Before

Width:  |  Height:  |  Size: 392 B

After

Width:  |  Height:  |  Size: 393 B

Before After
Before After

Some files were not shown because too many files have changed in this diff Show more