refactor: make prettier work for angular

This commit is contained in:
Johannes Millan 2025-02-21 14:31:22 +01:00
parent 292e66615d
commit d34ab71f16
152 changed files with 6731 additions and 6044 deletions

View file

@ -9,11 +9,11 @@ updates:
directory: '/' # Location of package manifests directory: '/' # Location of package manifests
schedule: schedule:
interval: 'monthly' interval: 'monthly'
# - package-ecosystem: "npm" # See documentation for possible values # - package-ecosystem: "npm" # See documentation for possible values
# directory: "/tools/schematics/" # Location of package manifests # directory: "/tools/schematics/" # Location of package manifests
# schedule: # schedule:
# interval: "monthly" # interval: "monthly"
- package-ecosystem: "github-actions" - package-ecosystem: 'github-actions'
directory: "/" directory: '/'
schedule: schedule:
interval: monthly interval: monthly

View file

@ -1,17 +1,17 @@
vscode: vscode:
extensions: extensions:
- coenraads.bracket-pair-colorizer-2 - coenraads.bracket-pair-colorizer-2
- pustelto.bracketeer - pustelto.bracketeer
- formulahendry.auto-close-tag - formulahendry.auto-close-tag
- dbaeumer.vscode-eslint - dbaeumer.vscode-eslint
- mhutchie.git-graph - mhutchie.git-graph
tasks: tasks:
- name: config, build, dev - name: config, build, dev
before: | before: |
export ANY_CONST_ENVS="can be defined here" && export ANY_CONST_ENVS="can be defined here" &&
export LIKE_THIS=* export LIKE_THIS=*
init: yarn init: yarn
command: yarn ng serve command: yarn ng serve
# Ports to expose on workspace startup # Ports to expose on workspace startup

View file

@ -11,16 +11,10 @@
"endOfLine": "auto", "endOfLine": "auto",
"printWidth": 90, "printWidth": 90,
"overrides": [ "overrides": [
{
"files": "*.component.html",
"options": {
"parser": "angular"
}
},
{ {
"files": "*.html", "files": "*.html",
"options": { "options": {
"parser": "html" "parser": "angular"
} }
} }
] ]

8
package-lock.json generated
View file

@ -121,7 +121,7 @@
"nightwatch": "^3.6.3", "nightwatch": "^3.6.3",
"object-path": "^0.11.8", "object-path": "^0.11.8",
"p-throttle": "^3.1.0", "p-throttle": "^3.1.0",
"prettier": "^3.4.2", "prettier": "^3.5.1",
"pretty-quick": "^4.0.0", "pretty-quick": "^4.0.0",
"query-string": "^7.1.1", "query-string": "^7.1.1",
"rxjs": "^6.6.7", "rxjs": "^6.6.7",
@ -21014,9 +21014,9 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "3.4.2", "version": "3.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz",
"integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", "integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==",
"dev": true, "dev": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"

View file

@ -207,7 +207,7 @@
"nightwatch": "^3.6.3", "nightwatch": "^3.6.3",
"object-path": "^0.11.8", "object-path": "^0.11.8",
"p-throttle": "^3.1.0", "p-throttle": "^3.1.0",
"prettier": "^3.4.2", "prettier": "^3.5.1",
"pretty-quick": "^4.0.0", "pretty-quick": "^4.0.0",
"query-string": "^7.1.1", "query-string": "^7.1.1",
"rxjs": "^6.6.7", "rxjs": "^6.6.7",

View file

@ -1,104 +1,111 @@
@if (isShowUi$|async) { @if ((globalThemeService.backgroundImg$|async); as bgImage) { @if (isShowUi$ | async) {
<div @if (globalThemeService.backgroundImg$ | async; as bgImage) {
[style.background]="'url(' + bgImage + ')'"
class="bg-image"
></div>
}
<!--TODO move inside page container somehow -->
@if (layoutService.isShowAddTaskBar$|async) {
<add-task-bar
(blurred)="layoutService.hideAddTaskBar()"
[isElevated]="true"
class="global"
></add-task-bar>
} @if ((layoutService.isShowAddTaskBar$|async)) {
<div
(click)="layoutService.hideAddTaskBar()"
@fade
class="backdrop"
></div>
} @if (layoutService.isShowSearchBar$|async) {
<search-bar (blurred)="layoutService.hideSearchBar()"></search-bar>
} @if ((layoutService.isShowSearchBar$|async)) {
<div
(click)="layoutService.hideSearchBar()"
@fade
class="backdrop"
></div>
}
<!-- -->
@if (isShowFocusOverlay$|async) {
<focus-mode-overlay @warp></focus-mode-overlay>
} @else {
<mat-sidenav-container [dir]="isRTL ? 'rtl' : 'ltr'">
<mat-sidenav
(closedStart)="layoutService.hideSideNav()"
[mode]="(layoutService.isNavOver$|async) ? 'over' : 'side'"
[opened]="(layoutService.isShowSideNav$|async)"
position="start"
>
<side-nav></side-nav>
@if (workContextService.isActiveWorkContextProject$|async) { }
</mat-sidenav>
<mat-sidenav-content>
<header
[class.isNotScrolled]="!(layoutService.isScrolled$|async)"
class="header-wrapper"
>
<main-header></main-header>
@if ((workContextService.isActiveWorkContextProject$|async)) {
<bookmark-bar></bookmark-bar>
}
<banner></banner>
</header>
<div <div
#routeWrapper [style.background]="'url(' + bgImage + ')'"
[@warpRoute]="getPage(o)" class="bg-image"
class="route-wrapper" ></div>
> }
<router-outlet #o="outlet"></router-outlet> <!--TODO move inside page container somehow -->
</div> @if (layoutService.isShowAddTaskBar$ | async) {
<global-progress-bar></global-progress-bar> <add-task-bar
</mat-sidenav-content> (blurred)="layoutService.hideAddTaskBar()"
</mat-sidenav-container> [isElevated]="true"
class="global"
></add-task-bar>
}
@if (layoutService.isShowAddTaskBar$ | async) {
<div
(click)="layoutService.hideAddTaskBar()"
@fade
class="backdrop"
></div>
}
@if (layoutService.isShowSearchBar$ | async) {
<search-bar (blurred)="layoutService.hideSearchBar()"></search-bar>
}
@if (layoutService.isShowSearchBar$ | async) {
<div
(click)="layoutService.hideSearchBar()"
@fade
class="backdrop"
></div>
}
<!-- -->
@if (isShowFocusOverlay$ | async) {
<focus-mode-overlay @warp></focus-mode-overlay>
} @else {
<mat-sidenav-container [dir]="isRTL ? 'rtl' : 'ltr'">
<mat-sidenav
(closedStart)="layoutService.hideSideNav()"
[mode]="(layoutService.isNavOver$ | async) ? 'over' : 'side'"
[opened]="layoutService.isShowSideNav$ | async"
position="start"
>
<side-nav></side-nav>
@if (workContextService.isActiveWorkContextProject$ | async) {}
</mat-sidenav>
<mat-sidenav-content>
<header
[class.isNotScrolled]="!(layoutService.isScrolled$ | async)"
class="header-wrapper"
>
<main-header></main-header>
@if (workContextService.isActiveWorkContextProject$ | async) {
<bookmark-bar></bookmark-bar>
}
<banner></banner>
</header>
<div
#routeWrapper
[@warpRoute]="getPage(o)"
class="route-wrapper"
>
<router-outlet #o="outlet"></router-outlet>
</div>
<global-progress-bar></global-progress-bar>
</mat-sidenav-content>
</mat-sidenav-container>
}
<!-- -->
} }
<!-- --> @if (
} @if (!(syncTriggerService.afterInitialSyncDoneAndDataLoadedInitially$|async) || !(syncTriggerService.afterInitialSyncDoneAndDataLoadedInitially$ | async) ||
(imexMetaService.isDataImportInProgress$|async)) { (imexMetaService.isDataImportInProgress$ | async)
<div class="loading-full-page-wrapper"> ) {
<global-progress-bar></global-progress-bar> <div class="loading-full-page-wrapper">
<div class="app-loading"> <global-progress-bar></global-progress-bar>
<div class="productivity-tip"> <div class="app-loading">
<h2 id="heading">{{ productivityTipTitle }}</h2> <div class="productivity-tip">
<p id="text">{{ productivityTipText }}</p> <h2 id="heading">{{ productivityTipTitle }}</h2>
<p id="text">{{ productivityTipText }}</p>
</div>
<div class="spinner">
<div class="double-bounce1"></div>
<div class="double-bounce2"></div>
</div>
<svg
class="logo"
viewBox="0 0 64 64"
>
<path
d="M 0.65537046,34.582787 32.452267,63.855301 63.791548,0.94356422 30.222644,47.722023 Z"
id="path3395"
style="
fill: #000000;
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>
</div> </div>
<div class="spinner">
<div class="double-bounce1"></div>
<div class="double-bounce2"></div>
</div>
<svg
class="logo"
viewBox="0 0 64 64"
>
<path
d="M 0.65537046,34.582787 32.452267,63.855301 63.791548,0.94356422 30.222644,47.722023 Z"
id="path3395"
style="
fill: #000000;
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>
</div> </div>
</div>
} }
<!-- --> <!-- -->

View file

@ -1,14 +1,15 @@
@if ((globalProgressBarService.label$|async); as label) { @if (globalProgressBarService.label$ | async; as label) {
<div <div
[@fadeOut] [@fadeOut]
class="badge" class="badge"
> >
{{label|translate}} {{ label | translate }}
</div> </div>
} @if ((globalProgressBarService.isShowGlobalProgressBar$|async)) { }
<div [@fadeInOutBottom]> @if (globalProgressBarService.isShowGlobalProgressBar$ | async) {
<mat-progress-bar mode="indeterminate"></mat-progress-bar> <div [@fadeInOutBottom]>
</div> <mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>
} }
<!--<div class="badge">Some test text</div>--> <!--<div class="badge">Some test text</div>-->

View file

@ -1,48 +1,50 @@
@let activeWorkContextTypeAndId = workContextService.activeWorkContextTypeAndId$|async; @let activeWorkContextTypeAndId = workContextService.activeWorkContextTypeAndId$ | async;
<!--<div class="wrapper ">--> <!--<div class="wrapper ">-->
<div class="wrapper"> <div class="wrapper">
@if (!(layoutService.isNavAlwaysVisible$|async)) { @if (!(layoutService.isNavAlwaysVisible$ | async)) {
<button <button
(click)="layoutService.toggleSideNav()" (click)="layoutService.toggleSideNav()"
class="burger-trigger tour-burgerTrigger" class="burger-trigger tour-burgerTrigger"
mat-icon-button mat-icon-button
> >
<mat-icon>menu</mat-icon> <mat-icon>menu</mat-icon>
</button> </button>
} }
<!----> <!---->
@if (activeWorkContextTypeAndId) { @if (activeWorkContextTypeAndId) {
<div <div
[matTooltip]="T.MH.GO_TO_TASK_LIST|translate" [matTooltip]="T.MH.GO_TO_TASK_LIST | translate"
class="current-work-context-title" class="current-work-context-title"
mat-ripple mat-ripple
routerLink="/active/tasks" routerLink="/active/tasks"
> >
{{ workContextService.activeWorkContextTitle$|async }} {{ workContextService.activeWorkContextTitle$ | async }}
</div> </div>
<button <button
[mat-menu-trigger-for]="activeWorkContextMenu" [mat-menu-trigger-for]="activeWorkContextMenu"
[matTooltip]="T.MH.PROJECT_MENU|translate" [matTooltip]="T.MH.PROJECT_MENU | translate"
class="project-settings-btn hide-xxxs" class="project-settings-btn hide-xxxs"
mat-icon-button mat-icon-button
> >
<mat-icon>more_vert</mat-icon> <mat-icon>more_vert</mat-icon>
</button> </button>
<mat-menu #activeWorkContextMenu="matMenu"> <mat-menu #activeWorkContextMenu="matMenu">
<ng-template matMenuContent> <ng-template matMenuContent>
<work-context-menu <work-context-menu
[contextId]="activeWorkContextTypeAndId.activeId" [contextId]="activeWorkContextTypeAndId.activeId"
[contextType]="activeWorkContextTypeAndId.activeType" [contextType]="activeWorkContextTypeAndId.activeType"
></work-context-menu> ></work-context-menu>
</ng-template> </ng-template>
</mat-menu> </mat-menu>
} }
<nav class="action-nav"> <nav class="action-nav">
<button <button
(click)="layoutService.showAddTaskBar()" (click)="layoutService.showAddTaskBar()"
matTooltip="{{T.MH.ADD_NEW_TASK|translate}} {{kb.addNewTask?'['+kb.addNewTask+']':''}}" matTooltip="{{ T.MH.ADD_NEW_TASK | translate }} {{
kb.addNewTask ? '[' + kb.addNewTask + ']' : ''
}}"
class="hide-xs tour-addBtn" class="hide-xs tour-addBtn"
mat-icon-button mat-icon-button
> >
@ -51,40 +53,42 @@
<button <button
(click)="layoutService.showSearchBar()" (click)="layoutService.showSearchBar()"
matTooltip="{{T.MH.SHOW_SEARCH_BAR|translate}} {{kb.showSearchBar?'['+kb.showSearchBar+']':''}}" matTooltip="{{ T.MH.SHOW_SEARCH_BAR | translate }} {{
kb.showSearchBar ? '[' + kb.showSearchBar + ']' : ''
}}"
mat-icon-button mat-icon-button
> >
<mat-icon>search</mat-icon> <mat-icon>search</mat-icon>
</button> </button>
@let isOnline = isOnline$|async; @let isOnline = isOnline$ | async;
<!-- --> <!-- -->
@let isSyncEnabled = syncProviderService.isEnabled$|async; @let isSyncEnabled = syncProviderService.isEnabled$ | async;
<button <button
class="sync-btn" class="sync-btn"
matTooltip="{{T.MH.TRIGGER_SYNC|translate}}" matTooltip="{{ T.MH.TRIGGER_SYNC | translate }}"
(click)="isSyncEnabled ? sync() : setupSync()" (click)="isSyncEnabled ? sync() : setupSync()"
(longPress)="setupSync()" (longPress)="setupSync()"
mat-icon-button mat-icon-button
> >
@if (isSyncEnabled) { @if (isSyncEnabled) {
<!-- --> <!-- -->
@if(isOnline) { @if (isOnline) {
<!-- --> <!-- -->
<mat-icon [class.spin]="(syncProviderService.isSyncing$|async)">sync</mat-icon> <mat-icon [class.spin]="syncProviderService.isSyncing$ | async">sync</mat-icon>
@let isInSync = syncProviderService.isCurrentProviderInSync$|async; @let isInSync = syncProviderService.isCurrentProviderInSync$ | async;
<!-- --> <!-- -->
@if (isInSync) { @if (isInSync) {
<mat-icon class="sync-success-check-ico">check</mat-icon> <mat-icon class="sync-success-check-ico">check</mat-icon>
} }
<!-- --> <!-- -->
} @else {
<mat-icon>wifi_off</mat-icon>
}
<!-- -->
} @else { } @else {
<mat-icon>wifi_off</mat-icon> <mat-icon>sync_disabled</mat-icon>
}
<!-- -->
} @else {
<mat-icon>sync_disabled</mat-icon>
} }
</button> </button>
@ -109,58 +113,68 @@
<!-- </mat-icon>--> <!-- </mat-icon>-->
<!-- </button>--> <!-- </button>-->
@if (!(globalConfigService.cfg$|async)?.focusMode?.isAlwaysUseFocusMode) { @if (!(globalConfigService.cfg$ | async)?.focusMode?.isAlwaysUseFocusMode) {
<button <button
mat-icon-button mat-icon-button
matTooltip="Enter focus mode {{kb.goToFocusMode?'['+kb.goToFocusMode+']':''}}" matTooltip="Enter focus mode {{
class="hide-xxs" kb.goToFocusMode ? '[' + kb.goToFocusMode + ']' : ''
(click)="enableFocusMode()" }}"
> class="hide-xxs"
<mat-icon>center_focus_strong</mat-icon> (click)="enableFocusMode()"
</button> >
<mat-icon>center_focus_strong</mat-icon>
</button>
} }
<div class="play-btn-wrapper"> <div class="play-btn-wrapper">
@if ((taskService.currentTask$|async); as currentTask) { @if (taskService.currentTask$ | async; as currentTask) {
<div <div
@fade @fade
class="current-task-title" class="current-task-title"
> >
<div class="title">{{ currentTask.title }}</div> <div class="title">{{ currentTask.title }}</div>
@if ((currentTaskContext$|async); as currentTaskContext) { @if (currentTaskContext$ | async; as currentTaskContext) {
<tag <tag
@expandFadeHorizontal @expandFadeHorizontal
[tag]="currentTaskContext" [tag]="currentTaskContext"
class="project" class="project"
></tag> ></tag>
} }
</div> </div>
} @if ((taskService.currentTaskId$|async)) { }
<div class="pulse-circle"></div> @if (taskService.currentTaskId$ | async) {
<div class="pulse-circle"></div>
} }
<button <button
(click)="taskService.toggleStartTask()" (click)="taskService.toggleStartTask()"
[color]="(taskService.currentTaskId$|async)? 'accent': 'primary'" [color]="(taskService.currentTaskId$ | async) ? 'accent' : 'primary'"
matTooltip="{{T.MH.TOGGLE_TRACK_TIME|translate}}" matTooltip="{{ T.MH.TOGGLE_TRACK_TIME | translate }}"
[matTooltipPosition]="(pomodoroService.isEnabled$|async)? 'left': 'below'" [matTooltipPosition]="(pomodoroService.isEnabled$ | async) ? 'left' : 'below'"
class="play-btn tour-playBtn mat-elevation-z3" class="play-btn tour-playBtn mat-elevation-z3"
mat-mini-fab mat-mini-fab
> >
@if ((pomodoroService.isEnabled$|async)) { @if ((pomodoroService.isBreak$|async)) @if (pomodoroService.isEnabled$ | async) {
{ @if (pomodoroService.isBreak$ | async) {
<mat-icon>free_breakfast</mat-icon> <mat-icon>free_breakfast</mat-icon>
} @if (!(pomodoroService.isBreak$|async)) { @if }
(!(taskService.currentTaskId$|async)) { @if (!(pomodoroService.isBreak$ | async)) {
<mat-icon>play_arrow</mat-icon> @if (!(taskService.currentTaskId$ | async)) {
} @if ((taskService.currentTaskId$|async)) { <mat-icon>play_arrow</mat-icon>
<mat-icon>pause</mat-icon> }
} } } @if (!(pomodoroService.isEnabled$|async)) { @if @if (taskService.currentTaskId$ | async) {
(!(taskService.currentTaskId$|async)) { <mat-icon>pause</mat-icon>
<mat-icon>play_arrow</mat-icon> }
} @if ((taskService.currentTaskId$|async)) { }
<mat-icon>pause</mat-icon> }
} } @if (!(pomodoroService.isEnabled$ | async)) {
@if (!(taskService.currentTaskId$ | async)) {
<mat-icon>play_arrow</mat-icon>
}
@if (taskService.currentTaskId$ | async) {
<mat-icon>pause</mat-icon>
}
}
<svg <svg
class="circle-svg" class="circle-svg"
@ -182,86 +196,96 @@
</svg> </svg>
</button> </button>
@if ((pomodoroService.cfg$|async)?.isEnabled) { @if ((pomodoroService.cfg$ | async)?.isEnabled) {
<div class="pomodoro-label"> <div class="pomodoro-label">
{{ (pomodoroService.currentSessionTime$|async|msToMinuteClockString) }} {{ pomodoroService.currentSessionTime$ | async | msToMinuteClockString }}
</div> </div>
<div class="pomodoro-controls"> <div class="pomodoro-controls">
<button <button
(click)="pomodoroService.finishPomodoroSession()" (click)="pomodoroService.finishPomodoroSession()"
[matTooltip]="T.F.POMODORO.S.SESSION_SKIP|translate" [matTooltip]="T.F.POMODORO.S.SESSION_SKIP | translate"
matTooltipPosition="left" matTooltipPosition="left"
class="pomodoro-btn" class="pomodoro-btn"
color="" color=""
mat-mini-fab mat-mini-fab
> >
<mat-icon>skip_next</mat-icon> <mat-icon>skip_next</mat-icon>
</button> </button>
<button <button
(click)="pomodoroService.stop()" (click)="pomodoroService.stop()"
[matTooltip]="T.F.POMODORO.S.RESET|translate" [matTooltip]="T.F.POMODORO.S.RESET | translate"
matTooltipPosition="left" matTooltipPosition="left"
class="pomodoro-btn" class="pomodoro-btn"
color="" color=""
mat-mini-fab mat-mini-fab
> >
<mat-icon>restart_alt</mat-icon> <mat-icon>restart_alt</mat-icon>
</button> </button>
</div> </div>
} }
</div> </div>
@if ((simpleCounterService.enabledSimpleCounters$|async); as enabledSimpleCounters) { @if (simpleCounterService.enabledSimpleCounters$ | async; as enabledSimpleCounters) {
@if (enabledSimpleCounters.length) { @if (enabledSimpleCounters.length) {
<div class="simple-counter-buttons-outer-wrapper"> <div class="simple-counter-buttons-outer-wrapper">
<button <button
(click)="isShowSimpleCounterBtnsMobile=!isShowSimpleCounterBtnsMobile" (click)="isShowSimpleCounterBtnsMobile = !isShowSimpleCounterBtnsMobile"
class="simple-counter-mobile-trigger show-xs-only" class="simple-counter-mobile-trigger show-xs-only"
[color]="isCounterRunning(enabledSimpleCounters) ? 'accent':''" [color]="isCounterRunning(enabledSimpleCounters) ? 'accent' : ''"
mat-mini-fab mat-mini-fab
> >
@if (!isShowSimpleCounterBtnsMobile) { @if (!isShowSimpleCounterBtnsMobile) {
<mat-icon>timer</mat-icon> <mat-icon>timer</mat-icon>
} @if (isShowSimpleCounterBtnsMobile) { }
<mat-icon>close</mat-icon> @if (isShowSimpleCounterBtnsMobile) {
} <mat-icon>close</mat-icon>
</button> }
<div </button>
class="simple-counter-buttons" <div
[class.isVisibleMobile]="isShowSimpleCounterBtnsMobile" class="simple-counter-buttons"
> [class.isVisibleMobile]="isShowSimpleCounterBtnsMobile"
@for (simpleCounter of enabledSimpleCounters; track trackById($index, >
simpleCounter)) { @for (
<simple-counter-button simpleCounter of enabledSimpleCounters;
[matTooltip]="simpleCounter.title" track trackById($index, simpleCounter)
[simpleCounter]="simpleCounter" ) {
></simple-counter-button> <simple-counter-button
} [matTooltip]="simpleCounter.title"
</div> [simpleCounter]="simpleCounter"
</div> ></simple-counter-button>
} } }
</div>
</div>
}
}
<button <button
class="toggle-notes-btn tour-issuePanelTrigger e2e-toggle-issue-provider-panel" class="toggle-notes-btn tour-issuePanelTrigger e2e-toggle-issue-provider-panel"
[disabled]="!(isRouteWithSidePanel$|async)" [disabled]="!(isRouteWithSidePanel$ | async)"
[class.isActive]="(layoutService.isShowIssuePanel$|async)" [class.isActive]="layoutService.isShowIssuePanel$ | async"
[class.isRouteWithRightPanel]="(isRouteWithRightPanel$|async)" [class.isRouteWithRightPanel]="isRouteWithRightPanel$ | async"
(click)="layoutService.toggleAddTaskPanel()" (click)="layoutService.toggleAddTaskPanel()"
mat-icon-button mat-icon-button
matTooltip="{{T.MH.TOGGLE_SHOW_ISSUE_PANEL|translate}} {{kb.toggleIssuePanel?'['+kb.toggleIssuePanel+']':''}}" matTooltip="{{ T.MH.TOGGLE_SHOW_ISSUE_PANEL | translate }} {{
kb.toggleIssuePanel ? '[' + kb.toggleIssuePanel + ']' : ''
}}"
> >
<mat-icon class="note-ico">playlist_add</mat-icon> <mat-icon class="note-ico">playlist_add</mat-icon>
</button> </button>
<button <button
class="toggle-notes-btn e2e-toggle-notes-btn" class="toggle-notes-btn e2e-toggle-notes-btn"
[title]="!(isRouteWithSidePanel$|async) ? (T.MH.NOTES_PANEL_INFO|translate) : ''" [title]="
[disabled]="!(isRouteWithSidePanel$|async)" !(isRouteWithSidePanel$ | async) ? (T.MH.NOTES_PANEL_INFO | translate) : ''
[class.isActive]="(layoutService.isShowNotes$|async)" "
[class.isRouteWithRightPanel]="(isRouteWithRightPanel$|async)" [disabled]="!(isRouteWithSidePanel$ | async)"
[class.isActive]="layoutService.isShowNotes$ | async"
[class.isRouteWithRightPanel]="isRouteWithRightPanel$ | async"
(click)="layoutService.toggleNotes()" (click)="layoutService.toggleNotes()"
mat-icon-button mat-icon-button
matTooltip="{{T.MH.TOGGLE_SHOW_NOTES|translate}} {{kb.openProjectNotes?'['+kb.openProjectNotes+']':''}}" matTooltip="{{ T.MH.TOGGLE_SHOW_NOTES | translate }} {{
kb.openProjectNotes ? '[' + kb.openProjectNotes + ']' : ''
}}"
> >
<mat-icon class="note-ico">comment</mat-icon> <mat-icon class="note-ico">comment</mat-icon>
</button> </button>

View file

@ -10,7 +10,7 @@
<button <button
#routeBtn #routeBtn
[routerLink]="[type() ==='TAG' ? 'tag' :'project', workContext().id, 'tasks']" [routerLink]="[type() === 'TAG' ? 'tag' : 'project', workContext().id, 'tasks']"
routerLinkActive="isActiveRoute" routerLinkActive="isActiveRoute"
mat-menu-item mat-menu-item
> >

View file

@ -1,12 +1,12 @@
<section class="main"> <section class="main">
@if ((workContextService.mainWorkContext$|async); as mainContext) { @if (workContextService.mainWorkContext$ | async; as mainContext) {
<side-nav-item <side-nav-item
#menuEntry #menuEntry
[type]="WorkContextType.TAG" [type]="WorkContextType.TAG"
[defaultIcon]="mainContext.icon" [defaultIcon]="mainContext.icon"
[workContext]="mainContext" [workContext]="mainContext"
[activeWorkContextId]="activeWorkContextId" [activeWorkContextId]="activeWorkContextId"
></side-nav-item> ></side-nav-item>
} }
<button <button
@ -17,7 +17,7 @@
routerLinkActive="isActiveRoute" routerLinkActive="isActiveRoute"
> >
<mat-icon svgIcon="early_on"></mat-icon> <mat-icon svgIcon="early_on"></mat-icon>
<span class="text">{{ T.MH.SCHEDULE|translate }}</span> <span class="text">{{ T.MH.SCHEDULE | translate }}</span>
</button> </button>
<button <button
@ -28,132 +28,135 @@
routerLinkActive="isActiveRoute" routerLinkActive="isActiveRoute"
> >
<mat-icon>edit_calendar</mat-icon> <mat-icon>edit_calendar</mat-icon>
<span class="text">{{ T.MH.PLANNER|translate }}</span> <span class="text">{{ T.MH.PLANNER | translate }}</span>
</button> </button>
</section> </section>
@if (nonHiddenProjects$|async; as projectList) { @if (nonHiddenProjects$ | async; as projectList) {
<section class="projects tour-projects"> <section class="projects tour-projects">
<div class="g-multi-btn-wrapper"> <div class="g-multi-btn-wrapper">
<button
#menuEntry
#projectExpandBtn
(click)="toggleExpandProjects()"
(keydown)="toggleExpandProjectsLeftRight($event)"
[class.isExpanded]="isProjectsExpanded"
class="expand-btn"
mat-menu-item
>
<mat-icon>expand_more</mat-icon>
<span class="title">{{ T.MH.PROJECTS | translate }}</span>
</button>
<!-- <button-->
<!-- #projectVisibilityBtn-->
<!-- mat-icon-button-->
<!-- class="additional-btn"-->
<!-- >-->
<!-- <mat-icon>visibility</mat-icon>-->
<!-- </button>-->
<button
[style.display]="projectList.length ? '' : 'none'"
class="additional-btn"
#projectExpandBtn2
mat-icon-button
>
<mat-icon>more_vert</mat-icon>
</button>
<button
(click)="addProject()"
class="additional-btn"
mat-icon-button
[matTooltip]="T.MH.CREATE_PROJECT | translate"
>
<mat-icon>add</mat-icon>
</button>
</div>
<!-- [leftClickTriggerEl]="projectVisibilityBtn"-->
<context-menu
[contextMenu]="contextMenu"
[leftClickTriggerEl]="projectExpandBtn2"
[rightClickTriggerEl]="projectExpandBtn"
></context-menu>
<ng-template #contextMenu>
@for (project of allProjects$ | async; track project.id) {
<button
mat-menu-item
(click)="toggleProjectVisibility(project)"
>
@if (!project.isHiddenFromMenu) {
<mat-icon>visibility</mat-icon>
}
@if (project.isHiddenFromMenu) {
<mat-icon>visibility_off</mat-icon>
}
{{ project.title }}
</button>
}
</ng-template>
<div
[@standardList]="projectList?.length"
cdkDropList
(cdkDropListDropped)="dropOnProjectList(projectList, $event)"
>
@for (project of projectList; track project.id) {
<side-nav-item
#menuEntry
cdkDrag
[cdkDragData]="project"
[cdkDragStartDelay]="IS_TOUCH_PRIMARY ? DRAG_DELAY_FOR_TOUCH_LONGER : 0"
(keydown)="checkFocusProject($event)"
[workContext]="project"
[type]="WorkContextType.PROJECT"
[defaultIcon]="'folder_special'"
[activeWorkContextId]="activeWorkContextId"
></side-nav-item>
}
</div>
</section>
}
@if (tagList$ | async; as tagList) {
<section class="tags">
<button <button
#menuEntry #menuEntry
#projectExpandBtn #tagExpandBtn
(click)="toggleExpandProjects()" (click)="toggleExpandTags()"
(keydown)="toggleExpandProjectsLeftRight($event)" (keydown)="toggleExpandTagsLeftRight($event)"
[class.isExpanded]="isProjectsExpanded" [class.isExpanded]="isTagsExpanded"
class="expand-btn" class="expand-btn"
mat-menu-item mat-menu-item
> >
<span class="title">{{ T.MH.TAGS | translate }}</span>
<mat-icon>expand_more</mat-icon> <mat-icon>expand_more</mat-icon>
<span class="title">{{ T.MH.PROJECTS|translate }}</span>
</button> </button>
<!-- <button--> <div
<!-- #projectVisibilityBtn--> [@standardList]="tagList?.length"
<!-- mat-icon-button--> cdkDropList
<!-- class="additional-btn"--> (cdkDropListDropped)="dropOnTagList(tagList, $event)"
<!-- >-->
<!-- <mat-icon>visibility</mat-icon>-->
<!-- </button>-->
<button
[style.display]="projectList.length ? '' : 'none'"
class="additional-btn"
#projectExpandBtn2
mat-icon-button
> >
<mat-icon>more_vert</mat-icon> @for (tag of tagList; track tag.id) {
</button> <side-nav-item
<button #menuEntry
(click)="addProject()" cdkDrag
class="additional-btn" [cdkDragData]="tag"
mat-icon-button [cdkDragStartDelay]="IS_TOUCH_PRIMARY ? DRAG_DELAY_FOR_TOUCH_LONGER : 0"
[matTooltip]="T.MH.CREATE_PROJECT|translate" (keydown)="checkFocusTag($event)"
> [workContext]="tag"
<mat-icon>add</mat-icon> [type]="WorkContextType.TAG"
</button> [defaultIcon]="'style'"
</div> [activeWorkContextId]="activeWorkContextId"
<!-- [leftClickTriggerEl]="projectVisibilityBtn"--> ></side-nav-item>
<context-menu }
[contextMenu]="contextMenu" </div>
[leftClickTriggerEl]="projectExpandBtn2" @if (!tagList.length && isTagsExpanded) {
[rightClickTriggerEl]="projectExpandBtn" <div class="no-tags-info">{{ T.MH.NO_TAG_INFO | translate }}</div>
></context-menu>
<ng-template #contextMenu>
@for (project of (allProjects$|async); track project.id) {
<button
mat-menu-item
(click)="toggleProjectVisibility(project)"
>
@if (!project.isHiddenFromMenu) {
<mat-icon>visibility</mat-icon>
} @if (project.isHiddenFromMenu) {
<mat-icon>visibility_off</mat-icon>
} {{ project.title }}
</button>
} }
</ng-template> <!-- <button (click)="addTag()"-->
<div <!-- *ngIf="isTagsExpanded"-->
[@standardList]="projectList?.length" <!-- #menuEntry mat-menu-item>-->
cdkDropList <!-- <mat-icon>add</mat-icon>-->
(cdkDropListDropped)="dropOnProjectList(projectList, $event)" <!-- {{T.MH.CREATE_TAG|translate}}-->
> <!-- </button>-->
@for (project of projectList; track project.id) { </section>
<side-nav-item
#menuEntry
cdkDrag
[cdkDragData]="project"
[cdkDragStartDelay]="IS_TOUCH_PRIMARY ? DRAG_DELAY_FOR_TOUCH_LONGER : 0"
(keydown)="checkFocusProject($event)"
[workContext]="project"
[type]="WorkContextType.PROJECT"
[defaultIcon]="'folder_special'"
[activeWorkContextId]="activeWorkContextId"
></side-nav-item>
}
</div>
</section>
} @if ((tagList$|async); as tagList) {
<section class="tags">
<button
#menuEntry
#tagExpandBtn
(click)="toggleExpandTags()"
(keydown)="toggleExpandTagsLeftRight($event)"
[class.isExpanded]="isTagsExpanded"
class="expand-btn"
mat-menu-item
>
<span class="title">{{ T.MH.TAGS|translate }}</span>
<mat-icon>expand_more</mat-icon>
</button>
<div
[@standardList]="tagList?.length"
cdkDropList
(cdkDropListDropped)="dropOnTagList(tagList, $event)"
>
@for (tag of tagList; track tag.id) {
<side-nav-item
#menuEntry
cdkDrag
[cdkDragData]="tag"
[cdkDragStartDelay]="IS_TOUCH_PRIMARY ? DRAG_DELAY_FOR_TOUCH_LONGER : 0"
(keydown)="checkFocusTag($event)"
[workContext]="tag"
[type]="WorkContextType.TAG"
[defaultIcon]="'style'"
[activeWorkContextId]="activeWorkContextId"
></side-nav-item>
}
</div>
@if (!tagList.length && isTagsExpanded) {
<div class="no-tags-info">{{ T.MH.NO_TAG_INFO|translate }}</div>
}
<!-- <button (click)="addTag()"-->
<!-- *ngIf="isTagsExpanded"-->
<!-- #menuEntry mat-menu-item>-->
<!-- <mat-icon>add</mat-icon>-->
<!-- {{T.MH.CREATE_TAG|translate}}-->
<!-- </button>-->
</section>
} }
<!--<section class="other-task-level-section">--> <!--<section class="other-task-level-section">-->
@ -168,7 +171,7 @@
routerLinkActive="isActiveRoute" routerLinkActive="isActiveRoute"
> >
<mat-icon svgIcon="repeat"></mat-icon> <mat-icon svgIcon="repeat"></mat-icon>
<span class="text">{{ T.MH.REPEAT_SCHEDULED|translate }}</span> <span class="text">{{ T.MH.REPEAT_SCHEDULED | translate }}</span>
</button> </button>
<button <button
#menuEntry #menuEntry
@ -177,7 +180,7 @@
mat-menu-item mat-menu-item
> >
<mat-icon>help_center</mat-icon> <mat-icon>help_center</mat-icon>
<span class="text">{{ T.MH.HELP|translate }}</span> <span class="text">{{ T.MH.HELP | translate }}</span>
</button> </button>
<mat-menu #helpMenu="matMenu"> <mat-menu #helpMenu="matMenu">
@ -188,7 +191,7 @@
target="_blank" target="_blank"
> >
<mat-icon>help_center</mat-icon> <mat-icon>help_center</mat-icon>
<span class="text">{{ T.MH.HM.GET_HELP_ONLINE|translate }}</span> <span class="text">{{ T.MH.HM.GET_HELP_ONLINE | translate }}</span>
</a> </a>
<a <a
@ -198,7 +201,7 @@
target="_blank" target="_blank"
> >
<mat-icon>bug_report</mat-icon> <mat-icon>bug_report</mat-icon>
<span class="text">{{ T.MH.HM.REPORT_A_PROBLEM|translate }}</span> <span class="text">{{ T.MH.HM.REPORT_A_PROBLEM | translate }}</span>
</a> </a>
<a <a
@ -207,7 +210,7 @@
target="_blank" target="_blank"
> >
<mat-icon>volunteer_activism</mat-icon> <mat-icon>volunteer_activism</mat-icon>
<span class="text">{{ T.MH.HM.CONTRIBUTE|translate }}</span> <span class="text">{{ T.MH.HM.CONTRIBUTE | translate }}</span>
</a> </a>
<a <a
@ -216,7 +219,7 @@
target="_blank" target="_blank"
> >
<mat-icon>forum</mat-icon> <mat-icon>forum</mat-icon>
<span class="text">{{ T.MH.HM.REDDIT_COMMUNITY|translate }}</span> <span class="text">{{ T.MH.HM.REDDIT_COMMUNITY | translate }}</span>
</a> </a>
<button <button
@ -224,30 +227,30 @@
mat-menu-item mat-menu-item
> >
<mat-icon>directions</mat-icon> <mat-icon>directions</mat-icon>
<span class="text">{{ T.MH.HM.START_WELCOME|translate }}</span> <span class="text">{{ T.MH.HM.START_WELCOME | translate }}</span>
</button> </button>
@if (IS_MOUSE_PRIMARY) { @if (IS_MOUSE_PRIMARY) {
<button <button
(click)="startTour(TourId.KeyboardNav)" (click)="startTour(TourId.KeyboardNav)"
mat-menu-item mat-menu-item
> >
<mat-icon>directions</mat-icon> <mat-icon>directions</mat-icon>
<span class="text">{{ T.MH.HM.KEYBOARD|translate }}</span> <span class="text">{{ T.MH.HM.KEYBOARD | translate }}</span>
</button> </button>
} }
<button <button
(click)="startTour(TourId.Sync)" (click)="startTour(TourId.Sync)"
mat-menu-item mat-menu-item
> >
<mat-icon>directions</mat-icon> <mat-icon>directions</mat-icon>
<span class="text">{{ T.MH.HM.SYNC|translate }}</span> <span class="text">{{ T.MH.HM.SYNC | translate }}</span>
</button> </button>
<button <button
(click)="startTour(TourId.IssueProviders)" (click)="startTour(TourId.IssueProviders)"
mat-menu-item mat-menu-item
> >
<mat-icon>directions</mat-icon> <mat-icon>directions</mat-icon>
<span class="text">{{ T.MH.HM.CALENDARS|translate }}</span> <span class="text">{{ T.MH.HM.CALENDARS | translate }}</span>
</button> </button>
</ng-template> </ng-template>
</mat-menu> </mat-menu>
@ -260,7 +263,7 @@
routerLinkActive="isActiveRoute" routerLinkActive="isActiveRoute"
> >
<mat-icon>settings</mat-icon> <mat-icon>settings</mat-icon>
<span class="text">{{ T.MH.SETTINGS|translate }}</span> <span class="text">{{ T.MH.SETTINGS | translate }}</span>
</button> </button>
</section> </section>

View file

@ -1,51 +1,52 @@
<button <button
[routerLink]="[base,contextId,'quick-history']" [routerLink]="[base, contextId, 'quick-history']"
mat-menu-item mat-menu-item
> >
<mat-icon>history</mat-icon> <mat-icon>history</mat-icon>
<span class="text">{{T.MH.QUICK_HISTORY|translate}}</span> <span class="text">{{ T.MH.QUICK_HISTORY | translate }}</span>
</button> </button>
<button <button
[routerLink]="[base,contextId,'worklog']" [routerLink]="[base, contextId, 'worklog']"
mat-menu-item mat-menu-item
> >
<mat-icon>date_range</mat-icon> <mat-icon>date_range</mat-icon>
<span class="text">{{T.MH.WORKLOG|translate}}</span> <span class="text">{{ T.MH.WORKLOG | translate }}</span>
</button> </button>
@if (isForProject || contextId ===TODAY_TAG_ID) { @if (isForProject || contextId === TODAY_TAG_ID) {
<button <button
[routerLink]="[base,contextId,'metrics']" [routerLink]="[base, contextId, 'metrics']"
mat-menu-item mat-menu-item
> >
<mat-icon>donut_large</mat-icon> <mat-icon>donut_large</mat-icon>
<span class="text">{{T.MH.METRICS|translate}}</span> <span class="text">{{ T.MH.METRICS | translate }}</span>
</button> </button>
} }
<button <button
[routerLink]="[base,contextId,'settings']" [routerLink]="[base, contextId, 'settings']"
mat-menu-item mat-menu-item
> >
<mat-icon>settings</mat-icon> <mat-icon>settings</mat-icon>
<span class="text">{{T.MH.SETTINGS|translate}}</span> <span class="text">{{ T.MH.SETTINGS | translate }}</span>
</button> </button>
@if (!isForProject && contextId !== TODAY_TAG_ID) { @if (!isForProject && contextId !== TODAY_TAG_ID) {
<button <button
(click)="deleteTag()" (click)="deleteTag()"
mat-menu-item mat-menu-item
> >
<mat-icon class="color-warn-i">delete_forever</mat-icon> <mat-icon class="color-warn-i">delete_forever</mat-icon>
<span class="text">{{T.MH.DELETE_TAG|translate}}</span> <span class="text">{{ T.MH.DELETE_TAG | translate }}</span>
</button> </button>
} @if (isForProject) { }
<button @if (isForProject) {
(click)="deleteProject()" <button
mat-menu-item (click)="deleteProject()"
> mat-menu-item
<mat-icon class="color-warn-i">delete_forever</mat-icon> >
<span class="text">{{ T.MH.DELETE_PROJECT|translate }}</span> <mat-icon class="color-warn-i">delete_forever</mat-icon>
</button> <span class="text">{{ T.MH.DELETE_PROJECT | translate }}</span>
</button>
} }

View file

@ -1,79 +1,85 @@
@if ((activeBanner$|async); as banner) { @if (activeBanner$ | async; as banner) {
<div <div
[@banner] [@banner]
[class.isError]="banner.type==='ERROR'" [class.isError]="banner.type === 'ERROR'"
class="content-wrapper" class="content-wrapper"
> >
@if (banner.progress$ && (banner.progress$|async); as progress) { @if (progress>0) { @if (banner.progress$ && (banner.progress$ | async); as progress) {
<mat-progress-bar @if (progress > 0) {
mode="determinate" <mat-progress-bar
[value]="progress" mode="determinate"
></mat-progress-bar> [value]="progress"
} } ></mat-progress-bar>
<div class="inner-content-wrapper"> }
@if (banner.img) {
<div class="motivational-img-wrapper">
<img [src]="banner.img" />
</div>
} }
<div class="message-wrapper"> <div class="inner-content-wrapper">
@if (banner.ico) { @if (banner.img) {
<mat-icon>{{banner.ico}}</mat-icon> <div class="motivational-img-wrapper">
} @if (banner.svgIco) { <img [src]="banner.img" />
<mat-icon [svgIcon]="banner.svgIco"></mat-icon> </div>
} }
<!-- --> <div class="message-wrapper">
@if(banner.timer$) { @if (banner.ico) {
<div class="message"> <mat-icon>{{ banner.ico }}</mat-icon>
<strong>{{banner.timer$|async|msToMinuteClockString}}</strong> }
{{banner.msg|translate:banner.translateParams}} @if (banner.svgIco) {
<mat-icon [svgIcon]="banner.svgIco"></mat-icon>
}
<!-- -->
@if (banner.timer$) {
<div class="message">
<strong>{{ banner.timer$ | async | msToMinuteClockString }}</strong>
{{ banner.msg | translate: banner.translateParams }}
</div>
} @else {
<div
[innerHTML]="banner.msg | translate: banner.translateParams"
class="message"
></div>
}
</div>
<div class="buttons">
@if (!banner.action2 && !banner.isHideDismissBtn) {
<button
(click)="dismiss(banner.id)"
color="primary"
mat-button
tabindex="1"
>
{{ T.G.DISMISS | translate }}
</button>
}
@if (banner.action) {
<button
(click)="action(banner.id, banner.action)"
color="primary"
mat-button
tabindex="1"
>
{{ banner.action.label | translate: banner.translateParams }}
</button>
}
@if (banner.action2) {
<button
(click)="action(banner.id, banner.action2)"
color="primary"
mat-button
tabindex="1"
>
{{ banner.action2.label | translate: banner.translateParams }}
</button>
}
@if (banner.action3) {
<button
(click)="action(banner.id, banner.action3)"
color="primary"
mat-button
tabindex="1"
>
{{ banner.action3.label | translate: banner.translateParams }}
</button>
}
</div> </div>
} @else {
<div
[innerHTML]="banner.msg|translate:banner.translateParams"
class="message"
></div>
}
</div>
<div class="buttons">
@if (!banner.action2 && !banner.isHideDismissBtn) {
<button
(click)="dismiss(banner.id)"
color="primary"
mat-button
tabindex="1"
>
{{T.G.DISMISS|translate}}
</button>
} @if (banner.action) {
<button
(click)="action(banner.id, banner.action)"
color="primary"
mat-button
tabindex="1"
>
{{banner.action.label|translate:banner.translateParams}}
</button>
} @if (banner.action2) {
<button
(click)="action(banner.id, banner.action2)"
color="primary"
mat-button
tabindex="1"
>
{{banner.action2.label|translate:banner.translateParams}}
</button>
} @if (banner.action3) {
<button
(click)="action(banner.id, banner.action3)"
color="primary"
mat-button
tabindex="1"
>
{{banner.action3.label|translate:banner.translateParams}}
</button>
}
</div> </div>
</div> </div>
</div>
} }

View file

@ -1,20 +1,25 @@
<div <div
(click)="!data.actionStr && close()" (click)="!data.actionStr && close()"
[class.error]="data.type==='ERROR'" [class.error]="data.type === 'ERROR'"
[class.success]="data.type==='SUCCESS'" [class.success]="data.type === 'SUCCESS'"
class="wrapper" class="wrapper"
> >
@if (!data.ico) { @if (data.type==='SUCCESS') { @if (!data.ico) {
<mat-icon class="snack-icon">check_circle </mat-icon> @if (data.type === 'SUCCESS') {
} @if (data.type==='ERROR') { <mat-icon class="snack-icon">check_circle </mat-icon>
<mat-icon class="snack-icon">error </mat-icon> }
} } @if (data.ico) { @if (data.type === 'ERROR') {
<mat-icon class="snack-icon">{{data.ico}}</mat-icon> <mat-icon class="snack-icon">error </mat-icon>
} @if (data.svgIco) { }
<mat-icon }
[svgIcon]="data.svgIco" @if (data.ico) {
class="snack-icon" <mat-icon class="snack-icon">{{ data.ico }}</mat-icon>
></mat-icon> }
@if (data.svgIco) {
<mat-icon
[svgIcon]="data.svgIco"
class="snack-icon"
></mat-icon>
} }
<span <span
@ -24,25 +29,26 @@
<div class="button-wrapper"> <div class="button-wrapper">
@if (data.actionStr) { @if (data.actionStr) {
<button <button
(click)="actionClick()" (click)="actionClick()"
class="action" class="action"
color="accent" color="accent"
mat-button mat-button
> >
{{data.actionStr|translate}} {{ data.actionStr | translate }}
</button> </button>
} }
</div> </div>
@if (!data.actionStr) { @if (!data.actionStr) {
<button <button
class="close-btn" class="close-btn"
mat-icon-button mat-icon-button
> >
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
</button> </button>
} @if (data.promise||data.showWhile$||data.isSpinner) { }
<mat-progress-bar mode="indeterminate"></mat-progress-bar> @if (data.promise || data.showWhile$ || data.isSpinner) {
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
} }
</div> </div>

View file

@ -1,38 +1,46 @@
@let nrOfPlannerItemsForTomorrow = @let nrOfPlannerItemsForTomorrow =
(addTasksForTomorrowService.nrOfPlannerItemsForTomorrow$|async); addTasksForTomorrowService.nrOfPlannerItemsForTomorrow$ | async;
<!----> <!---->
@let plannedForToday = (addTasksForTomorrowService.allPlannedForTodayNotOnToday$|async); @let plannedForToday = addTasksForTomorrowService.allPlannedForTodayNotOnToday$ | async;
<!----> <!---->
@if (workContextService.isToday &&(isAlwaysShowIfAny() || @if (
(workContextService.activeWorkContext$|async)?.taskIds.length ===0) && plannedForToday) { workContextService.isToday &&
<div class="wrap-add-planned"> (isAlwaysShowIfAny() ||
@if (plannedForToday?.length) { (workContextService.activeWorkContext$ | async)?.taskIds.length === 0) &&
<button plannedForToday
(click)="addTasksForTomorrowService.movePlannedTasksToToday(plannedForToday)" ) {
class="add-scheduled" <div class="wrap-add-planned">
color="" @if (plannedForToday?.length) {
mat-stroked-button <button
tabindex="1" (click)="addTasksForTomorrowService.movePlannedTasksToToday(plannedForToday)"
> class="add-scheduled"
<mat-icon>playlist_add</mat-icon> color=""
{{ T.WW.ADD_SCHEDULED_FOR_TODAY|translate:{ nr: plannedForToday.length } }} mat-stroked-button
</button> tabindex="1"
} >
<!----> <mat-icon>playlist_add</mat-icon>
@if (plannedForToday.length === 0 && nrOfPlannerItemsForTomorrow) { {{ T.WW.ADD_SCHEDULED_FOR_TODAY | translate: { nr: plannedForToday.length } }}
<!----> </button>
@if (nrOfPlannerItemsForTomorrow) { }
<button <!---->
class="add-scheduled" @if (plannedForToday.length === 0 && nrOfPlannerItemsForTomorrow) {
(click)="addTasksForTomorrowService.addAllPlannedToDayAndCreateRepeatable()" <!---->
color="" @if (nrOfPlannerItemsForTomorrow) {
mat-stroked-button <button
tabindex="1" class="add-scheduled"
> (click)="addTasksForTomorrowService.addAllPlannedToDayAndCreateRepeatable()"
<mat-icon>playlist_add</mat-icon> color=""
{{ T.WW.ADD_SCHEDULED_FOR_TOMORROW|translate:{ nr: nrOfPlannerItemsForTomorrow } }} mat-stroked-button
</button> tabindex="1"
} } >
</div> <mat-icon>playlist_add</mat-icon>
{{
T.WW.ADD_SCHEDULED_FOR_TOMORROW
| translate: { nr: nrOfPlannerItemsForTomorrow }
}}
</button>
}
}
</div>
} }

View file

@ -1,125 +1,130 @@
@if (bookmarkService.isShowBookmarks$|async) { @if (bookmarkService.isShowBookmarks$ | async) {
<div
#bookmarkBar
[@slide]="{value:'*',params:{elHeight:(bookmarkBarHeight)}}"
class="global-bookmark-list-outer"
>
@if (isDragOver) {
<div <div
@fade #bookmarkBar
class="bgc-accent drag-over-msg" [@slide]="{ value: '*', params: { elHeight: bookmarkBarHeight } }"
class="global-bookmark-list-outer"
> >
<mat-icon>add</mat-icon> @if (isDragOver) {
{{T.F.BOOKMARK.BAR.DROP|translate}}
</div>
}
<div class="controls-and-list-wrapper">
<div class="list-controls">
@if (!isEditMode) {
<button
(menuClosed)="isContextMenuDisabled = false"
(menuOpened)="isContextMenuDisabled = true"
[matMenuTriggerFor]="menu"
[style.pointer-events]="isContextMenuDisabled ? 'none' : 'all'"
mat-stroked-button
>
<mat-icon>more_vert</mat-icon>
</button>
} @if (isEditMode) {
<button
(click)="isEditMode=false; isContextMenuDisabled=false"
mat-stroked-button
>
<mat-icon>check</mat-icon>
</button>
}
<mat-menu #menu="matMenu">
<ng-template matMenuContent>
<button
(click)="openEditDialog()"
color=""
mat-menu-item
>
<mat-icon>add</mat-icon>
{{T.F.BOOKMARK.BAR.ADD|translate}}
</button>
<button
(click)="isEditMode=!isEditMode"
color=""
mat-menu-item
>
<mat-icon>edit</mat-icon>
{{T.F.BOOKMARK.BAR.EDIT|translate}}
</button>
</ng-template>
</mat-menu>
</div>
@let bookmarks = (bookmarkService.bookmarks$|async);
<div
[class.isEditMode]="isEditMode"
cdkDropList
cdkDropListOrientation="horizontal"
[cdkDropListData]="bookmarks"
(cdkDropListDropped)="drop($event)"
class="global-bookmark-list-inner"
>
@if (!bookmarks?.length) {
<div class="msg">{{T.F.BOOKMARK.BAR.NO_BOOKMARKS|translate}}</div>
} @for (bookmark of bookmarks; track trackByFn($index, bookmark)) {
<div <div
class="global-bookmark" @fade
cdkDrag class="bgc-accent drag-over-msg"
draggable="false"
> >
<a <mat-icon>add</mat-icon>
[enlargeImg]="bookmark.type==='IMG'&& bookmark.path" {{ T.F.BOOKMARK.BAR.DROP | translate }}
[href]="bookmark.path" </div>
[style.background-image]="bookmark.type==='IMG'&& 'url('+bookmark.path+')'" }
[title]="bookmark.path" <div class="controls-and-list-wrapper">
aria-label="open global bookmark" <div class="list-controls">
bookmarkLink @if (!isEditMode) {
color="" <button
draggable="false" (menuClosed)="isContextMenuDisabled = false"
mat-stroked-button (menuOpened)="isContextMenuDisabled = true"
target="_blank" [matMenuTriggerFor]="menu"
type="{{bookmark.type}}" [style.pointer-events]="isContextMenuDisabled ? 'none' : 'all'"
> mat-stroked-button
@if (bookmark.icon) { >
<mat-icon>{{bookmark.icon}} </mat-icon> <mat-icon>more_vert</mat-icon>
} {{bookmark.title}} </button>
</a> }
@if (isEditMode) { @if (isEditMode) {
<div class="controls">
@if (isEditMode) {
<mat-icon
@fade
class="drag-handle bgc-400"
svgIcon="drag_handle"
></mat-icon>
}
<button <button
(click)="openEditDialog(bookmark)" (click)="isEditMode = false; isContextMenuDisabled = false"
aria-label="open edit dialog" mat-stroked-button
class="edit-btn"
color="primary"
mat-raised-button
> >
<mat-icon>edit</mat-icon> <mat-icon>check</mat-icon>
</button> </button>
<button }
(click)="remove(bookmark.id)" <mat-menu #menu="matMenu">
aria-label="remove bookmark" <ng-template matMenuContent>
class="trash-btn" <button
color="warn" (click)="openEditDialog()"
mat-raised-button color=""
mat-menu-item
>
<mat-icon>add</mat-icon>
{{ T.F.BOOKMARK.BAR.ADD | translate }}
</button>
<button
(click)="isEditMode = !isEditMode"
color=""
mat-menu-item
>
<mat-icon>edit</mat-icon>
{{ T.F.BOOKMARK.BAR.EDIT | translate }}
</button>
</ng-template>
</mat-menu>
</div>
@let bookmarks = bookmarkService.bookmarks$ | async;
<div
[class.isEditMode]="isEditMode"
cdkDropList
cdkDropListOrientation="horizontal"
[cdkDropListData]="bookmarks"
(cdkDropListDropped)="drop($event)"
class="global-bookmark-list-inner"
>
@if (!bookmarks?.length) {
<div class="msg">{{ T.F.BOOKMARK.BAR.NO_BOOKMARKS | translate }}</div>
}
@for (bookmark of bookmarks; track trackByFn($index, bookmark)) {
<div
class="global-bookmark"
cdkDrag
draggable="false"
> >
<mat-icon>delete_forever</mat-icon> <a
</button> [enlargeImg]="bookmark.type === 'IMG' && bookmark.path"
</div> [href]="bookmark.path"
[style.background-image]="
bookmark.type === 'IMG' && 'url(' + bookmark.path + ')'
"
[title]="bookmark.path"
aria-label="open global bookmark"
bookmarkLink
color=""
draggable="false"
mat-stroked-button
target="_blank"
type="{{ bookmark.type }}"
>
@if (bookmark.icon) {
<mat-icon>{{ bookmark.icon }} </mat-icon>
}
{{ bookmark.title }}
</a>
@if (isEditMode) {
<div class="controls">
@if (isEditMode) {
<mat-icon
@fade
class="drag-handle bgc-400"
svgIcon="drag_handle"
></mat-icon>
}
<button
(click)="openEditDialog(bookmark)"
aria-label="open edit dialog"
class="edit-btn"
color="primary"
mat-raised-button
>
<mat-icon>edit</mat-icon>
</button>
<button
(click)="remove(bookmark.id)"
aria-label="remove bookmark"
class="trash-btn"
color="warn"
mat-raised-button
>
<mat-icon>delete_forever</mat-icon>
</button>
</div>
}
</div>
} }
</div> </div>
}
</div> </div>
</div> </div>
</div>
} }

View file

@ -1,90 +1,94 @@
@if (bookmarkCopy) { @if (bookmarkCopy) {
<form <form
#form="ngForm" #form="ngForm"
(submit)="$event.preventDefault();submit()" (submit)="$event.preventDefault(); submit()"
> >
<h1 mat-dialog-title> <h1 mat-dialog-title>
{{ (bookmarkCopy.id ? (T.F.BOOKMARK.DIALOG_EDIT.EDIT_BOOKMARK) : {{
(T.F.BOOKMARK.DIALOG_EDIT.ADD_BOOKMARK)) |translate }} (bookmarkCopy.id
</h1> ? T.F.BOOKMARK.DIALOG_EDIT.EDIT_BOOKMARK
<mat-dialog-content> : T.F.BOOKMARK.DIALOG_EDIT.ADD_BOOKMARK
<div class="form-wrapper"> ) | translate
<mat-form-field> }}
<mat-label>{{(T.G.TITLE|translate)}}</mat-label> </h1>
<input <mat-dialog-content>
[(ngModel)]="bookmarkCopy.title" <div class="form-wrapper">
autofocus="autofocus"
matInput
name="title"
type="text"
/>
</mat-form-field>
<mat-form-field>
<mat-label>{{mapTypeToLabel(bookmarkCopy.type)|translate}}</mat-label>
<input
[(ngModel)]="bookmarkCopy.path"
matInput
name="path"
required
type="text"
/>
</mat-form-field>
<mat-form-field>
<mat-label>{{(T.F.BOOKMARK.DIALOG_EDIT.SELECT_TYPE|translate)}}</mat-label>
<mat-select
[(ngModel)]="bookmarkCopy.type"
name="type"
required="true"
>
@for (type of types; track trackByIndex($index, type)) {
<mat-option [value]="type.type">{{ (type.title|translate) }} </mat-option>
}
</mat-select>
</mat-form-field>
<div class="custom-icon-wrapper">
<mat-form-field> <mat-form-field>
<mat-label>{{(T.F.BOOKMARK.DIALOG_EDIT.SELECT_ICON|translate)}}</mat-label> <mat-label>{{ T.G.TITLE | translate }}</mat-label>
<input <input
[(ngModel)]="bookmarkCopy.icon" [(ngModel)]="bookmarkCopy.title"
[formControl]="iconControl" autofocus="autofocus"
[matAutocomplete]="auto"
matInput matInput
name="title"
type="text" type="text"
/> />
<mat-icon matPrefix="">{{bookmarkCopy.icon}}</mat-icon>
<mat-autocomplete
#auto="matAutocomplete"
[autoActiveFirstOption]="true"
>
@for (icon of (filteredIcons$|async); track trackByIndex($index, icon)) {
<mat-option [value]="icon">
<mat-icon>{{icon}}</mat-icon>
<span>{{icon}}</span>
</mat-option>
}
</mat-autocomplete>
</mat-form-field> </mat-form-field>
<mat-form-field>
<mat-label>{{ mapTypeToLabel(bookmarkCopy.type) | translate }}</mat-label>
<input
[(ngModel)]="bookmarkCopy.path"
matInput
name="path"
required
type="text"
/>
</mat-form-field>
<mat-form-field>
<mat-label>{{ T.F.BOOKMARK.DIALOG_EDIT.SELECT_TYPE | translate }}</mat-label>
<mat-select
[(ngModel)]="bookmarkCopy.type"
name="type"
required="true"
>
@for (type of types; track trackByIndex($index, type)) {
<mat-option [value]="type.type">{{ type.title | translate }} </mat-option>
}
</mat-select>
</mat-form-field>
<div class="custom-icon-wrapper">
<mat-form-field>
<mat-label>{{ T.F.BOOKMARK.DIALOG_EDIT.SELECT_ICON | translate }}</mat-label>
<input
[(ngModel)]="bookmarkCopy.icon"
[formControl]="iconControl"
[matAutocomplete]="auto"
matInput
type="text"
/>
<mat-icon matPrefix="">{{ bookmarkCopy.icon }}</mat-icon>
<mat-autocomplete
#auto="matAutocomplete"
[autoActiveFirstOption]="true"
>
@for (icon of filteredIcons$ | async; track trackByIndex($index, icon)) {
<mat-option [value]="icon">
<mat-icon>{{ icon }}</mat-icon>
<span>{{ icon }}</span>
</mat-option>
}
</mat-autocomplete>
</mat-form-field>
</div>
</div> </div>
</div> </mat-dialog-content>
</mat-dialog-content> <mat-dialog-actions align="end">
<mat-dialog-actions align="end"> <button
<button (click)="close()"
(click)="close()" color="primary"
color="primary" mat-button
mat-button type="button"
type="button" >
> {{ T.G.CANCEL | translate }}
{{T.G.CANCEL|translate}} </button>
</button> <button
<button [disabled]="!form.valid"
[disabled]="!form.valid" color="primary"
color="primary" mat-stroked-button
mat-stroked-button type="submit"
type="submit" >
> <mat-icon>save</mat-icon>
<mat-icon>save</mat-icon> {{ T.G.SAVE | translate }}
{{T.G.SAVE|translate}} </button>
</button> </mat-dialog-actions>
</mat-dialog-actions> </form>
</form>
} }

View file

@ -1,36 +1,44 @@
<collapsible <collapsible
[isExpanded]="isExpanded" [isExpanded]="isExpanded"
[isIconBefore]="true" [isIconBefore]="true"
[title]="(section?.title|translate)" [title]="section?.title | translate"
> >
<!--[icon]="section?.icon"--> <!--[icon]="section?.icon"-->
@if (section?.help||section?.helpArr) { @if (section?.help || section?.helpArr) {
<help-section> <help-section>
@if (section?.help) { @if (section?.help) {
<div [innerHtml]="section?.help|translate"></div> <div [innerHtml]="section?.help | translate"></div>
} @if (section?.helpArr) { @for (helpSection of section?.helpArr; track }
trackByIndex($index, helpSection)) { @if (helpSection.h) { @if (section?.helpArr) {
<div class="mat-caption">{{helpSection.h|translate}}</div> @for (helpSection of section?.helpArr; track trackByIndex($index, helpSection)) {
} @if (helpSection.p) { @if (helpSection.h) {
<p [innerHTML]="helpSection.p|translate"></p> <div class="mat-caption">{{ helpSection.h | translate }}</div>
} @if (helpSection.p2) { }
<p [innerHTML]="helpSection.p2|translate"></p> @if (helpSection.p) {
} @if (helpSection.p3) { <p [innerHTML]="helpSection.p | translate"></p>
<p [innerHTML]="helpSection.p3|translate"></p> }
} @if (helpSection.p4) { @if (helpSection.p2) {
<p [innerHTML]="helpSection.p4|translate"></p> <p [innerHTML]="helpSection.p2 | translate"></p>
} } } }
</help-section> @if (helpSection.p3) {
<p [innerHTML]="helpSection.p3 | translate"></p>
}
@if (helpSection.p4) {
<p [innerHTML]="helpSection.p4 | translate"></p>
}
}
}
</help-section>
} }
<div class="form-wrapper {{section?.key}}"> <div class="form-wrapper {{ section?.key }}">
@if (section?.items && !section?.customSection) { @if (section?.items && !section?.customSection) {
<config-form <config-form
(save)="onSave($event)" (save)="onSave($event)"
[cfg]="cfg" [cfg]="cfg"
[formCfg]="section?.items" [formCfg]="section?.items"
[sectionKey]="section?.key" [sectionKey]="section?.key"
></config-form> ></config-form>
} }
<ng-template <ng-template

View file

@ -9,7 +9,7 @@
class="width100" class="width100"
[hideRequiredMarker]="true" [hideRequiredMarker]="true"
> >
<mat-label>{{ 'GCF.SOUND.VOLUME' | translate}}</mat-label> <mat-label>{{ 'GCF.SOUND.VOLUME' | translate }}</mat-label>
<mat-slider <mat-slider
class="width100" class="width100"
[min]="0" [min]="0"
@ -26,10 +26,10 @@
</mat-slider> </mat-slider>
</mat-form-field> </mat-form-field>
<mat-form-field class="width100"> <mat-form-field class="width100">
<mat-label>{{ 'GCF.SOUND.DONE_SOUND' | translate}}</mat-label> <mat-label>{{ 'GCF.SOUND.DONE_SOUND' | translate }}</mat-label>
<mat-select formControlName="doneSound"> <mat-select formControlName="doneSound">
@for (sound of soundOpts; track sound) { @for (sound of soundOpts; track sound) {
<mat-option [value]="sound.value">{{sound.label}}</mat-option> <mat-option [value]="sound.value">{{ sound.label }}</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@ -42,14 +42,14 @@
matInput matInput
[checked]="this.config?.isIncreaseDoneSoundPitch" [checked]="this.config?.isIncreaseDoneSoundPitch"
formControlName="isIncreaseDoneSoundPitch" formControlName="isIncreaseDoneSoundPitch"
>{{'GCF.SOUND.IS_INCREASE_DONE_PITCH' | translate}}</mat-slide-toggle >{{ 'GCF.SOUND.IS_INCREASE_DONE_PITCH' | translate }}</mat-slide-toggle
> >
</mat-form-field> </mat-form-field>
<mat-form-field class="width100"> <mat-form-field class="width100">
<mat-label>{{'GCF.SOUND.BREAK_REMINDER_SOUND' | translate }}</mat-label> <mat-label>{{ 'GCF.SOUND.BREAK_REMINDER_SOUND' | translate }}</mat-label>
<mat-select formControlName="breakReminderSound"> <mat-select formControlName="breakReminderSound">
@for (sound of soundOpts; track sound) { @for (sound of soundOpts; track sound) {
<mat-option [value]="sound.value">{{sound.label}}</mat-option> <mat-option [value]="sound.value">{{ sound.label }}</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>

View file

@ -1,10 +1,10 @@
import { GlobalConfigState } from './global-config.model'; import { GlobalConfigState } from './global-config.model';
import { DEFAULT_PROJECT_ID } from '../project/project.const'; import { DEFAULT_PROJECT_ID } from '../project/project.const';
import { TRACKING_INTERVAL } from 'src/app/app.constants'; import { TRACKING_INTERVAL } from 'src/app/app.constants';
import {getDefaultVoice} from 'src/app/features/domina-mode/getAvailableVoices' import { getDefaultVoice } from 'src/app/features/domina-mode/getAvailableVoices';
const minute = 60 * 1000; const minute = 60 * 1000;
const defaultVoice = getDefaultVoice(); const defaultVoice = getDefaultVoice();
console.log("Setting default voice as"+ defaultVoice); console.log('Setting default voice as' + defaultVoice);
export const DEFAULT_DAY_START = '9:00'; export const DEFAULT_DAY_START = '9:00';
export const DEFAULT_GLOBAL_CONFIG: GlobalConfigState = { export const DEFAULT_GLOBAL_CONFIG: GlobalConfigState = {
@ -63,8 +63,7 @@ export const DEFAULT_GLOBAL_CONFIG: GlobalConfigState = {
interval: 5 * minute, interval: 5 * minute,
volume: 75, volume: 75,
text: 'Your current task is: ${currentTaskTitle}', text: 'Your current task is: ${currentTaskTitle}',
voice:defaultVoice , voice: defaultVoice,
}, },
focusMode: { focusMode: {
isAlwaysUseFocusMode: false, isAlwaysUseFocusMode: false,

View file

@ -2,8 +2,7 @@
import { ConfigFormSection, DominaModeConfig } from '../global-config.model'; import { ConfigFormSection, DominaModeConfig } from '../global-config.model';
import { T } from '../../../t.const'; import { T } from '../../../t.const';
import { speak } from '../../../util/speak'; import { speak } from '../../../util/speak';
import {getAvailableVoices} from '../../domina-mode/getAvailableVoices' import { getAvailableVoices } from '../../domina-mode/getAvailableVoices';
export const DOMINA_MODE_FORM: ConfigFormSection<DominaModeConfig> = { export const DOMINA_MODE_FORM: ConfigFormSection<DominaModeConfig> = {
title: T.F.DOMINA_MODE.FORM.TITLE, title: T.F.DOMINA_MODE.FORM.TITLE,
@ -53,17 +52,17 @@ export const DOMINA_MODE_FORM: ConfigFormSection<DominaModeConfig> = {
if (txt.length <= 1) { if (txt.length <= 1) {
txt = 'No text configured for domina mode'; txt = 'No text configured for domina mode';
} }
speak(txt, model.volume,model.voice); speak(txt, model.volume, model.voice);
}, },
}, },
}, },
{ {
key:'voice', key: 'voice',
type:'select', type: 'select',
templateOptions:{ templateOptions: {
label:"Select a Voice", label: 'Select a Voice',
description:"Choose a voice", description: 'Choose a voice',
required:false, required: false,
}, },
hooks: { hooks: {
onInit: (field) => { onInit: (field) => {
@ -71,17 +70,14 @@ export const DOMINA_MODE_FORM: ConfigFormSection<DominaModeConfig> = {
voices = getAvailableVoices(); voices = getAvailableVoices();
//console.log(voices); //console.log(voices);
if(field.templateOptions){ if (field.templateOptions) {
field.templateOptions.options = voices.map(voiceName=>({ field.templateOptions.options = voices.map((voiceName) => ({
label:voiceName.name, label: voiceName.name,
value: voiceName.voiceURI, value: voiceName.voiceURI,
}));
}))
} }
},
} },
} },
}
], ],
}; };

View file

@ -157,7 +157,6 @@ export type DominaModeConfig = Readonly<{
interval: number; interval: number;
volume: number; volume: number;
voice: string; voice: string;
}>; }>;
export type FocusModeConfig = Readonly<{ export type FocusModeConfig = Readonly<{

View file

@ -18,20 +18,20 @@
(optionSelected)="onIconSelect($event.option.value)" (optionSelected)="onIconSelect($event.option.value)"
[autoActiveFirstOption]="false" [autoActiveFirstOption]="false"
> >
@for (icon of (filteredIcons); track trackByIndex($index, icon)) { @for (icon of filteredIcons; track trackByIndex($index, icon)) {
<mat-option [value]="icon"> <mat-option [value]="icon">
<mat-icon>{{icon}}</mat-icon> <mat-icon>{{ icon }}</mat-icon>
<span>{{icon}}</span> <span>{{ icon }}</span>
</mat-option> </mat-option>
} }
</mat-autocomplete> </mat-autocomplete>
@if(IS_ELECTRON && !isLinux){ @if (IS_ELECTRON && !isLinux) {
<mat-icon <mat-icon
matSuffix matSuffix
type="button" type="button"
[matTooltip]="'Open system emoji picker if any'" [matTooltip]="'Open system emoji picker if any'"
(click)="openEmojiPicker()" (click)="openEmojiPicker()"
>add_reaction</mat-icon >add_reaction</mat-icon
> >
} }

View file

@ -3,21 +3,21 @@
class="list-wrapper" class="list-wrapper"
> >
@for (innerField of field.fieldGroup; track trackByFn(i, innerField); let i = $index) { @for (innerField of field.fieldGroup; track trackByFn(i, innerField); let i = $index) {
<div class="row"> <div class="row">
<formly-field <formly-field
[field]="innerField" [field]="innerField"
class="field" class="field"
></formly-field> ></formly-field>
<button <button
(click)="removeItem(i)" (click)="removeItem(i)"
color="warn" color="warn"
mat-mini-fab mat-mini-fab
type="button" type="button"
class="remove-btn" class="remove-btn"
> >
<mat-icon>delete_forever</mat-icon> <mat-icon>delete_forever</mat-icon>
</button> </button>
</div> </div>
} }
</div> </div>
@ -28,6 +28,6 @@
type="button" type="button"
> >
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
{{ to.addText | translate}} {{ to.addText | translate }}
</button> </button>
</div> </div>

View file

@ -6,8 +6,8 @@
[readonly]="to.readonly" [readonly]="to.readonly"
matNativeControl matNativeControl
> >
<option [ngValue]="false">{{T.G.NONE | translate}}</option> <option [ngValue]="false">{{ T.G.NONE | translate }}</option>
@for (opt of projectService.list$|async; track trackById($index, opt)) { @for (opt of projectService.list$ | async; track trackById($index, opt)) {
<option [ngValue]="opt.id">{{ opt.title }}</option> <option [ngValue]="opt.id">{{ opt.title }}</option>
} }
</select> </select>

View file

@ -1,16 +1,14 @@
export const getAvailableVoices = (): SpeechSynthesisVoice[] => { export const getAvailableVoices = (): SpeechSynthesisVoice[] => {
const synth = window.speechSynthesis; const synth = window.speechSynthesis;
return synth.getVoices() return synth.getVoices();
}; };
export const getDefaultVoice = (): string => { export const getDefaultVoice = (): string => {
const voices = window.speechSynthesis.getVoices(); const voices = window.speechSynthesis.getVoices();
if (voices.length === 0) { if (voices.length === 0) {
return "null"; return 'null';
} }
//"null" should theoretically use the default voice //"null" should theoretically use the default voice
const defaultVoice = voices.find(voice => voice.default); const defaultVoice = voices.find((voice) => voice.default);
return defaultVoice ? defaultVoice.voiceURI : voices[0].voiceURI; return defaultVoice ? defaultVoice.voiceURI : voices[0].voiceURI;
} };

View file

@ -26,7 +26,7 @@ export class DominaModeEffects {
if (txt.length <= 1) { if (txt.length <= 1) {
txt = currentTask.title; txt = currentTask.title;
} }
speak(txt, cfg.volume,cfg.voice); speak(txt, cfg.volume, cfg.voice);
} }
}), }),
) )

View file

@ -1,30 +1,34 @@
<form <form
(submit)="$event.preventDefault();onSubmit($event)" (submit)="$event.preventDefault(); onSubmit($event)"
novalidate novalidate
> >
@if(selectedMode() !== FocusModeMode.Flowtime) { @if (selectedMode() !== FocusModeMode.Flowtime) {
<h1>{{T.F.FOCUS_MODE.SET_FOCUS_SESSION_DURATION|translate}}</h1> <h1>{{ T.F.FOCUS_MODE.SET_FOCUS_SESSION_DURATION | translate }}</h1>
} @if (task$|async; as task) { }
<div class="for-task"> @if (task$ | async; as task) {
<div class="label">for task</div> <div class="for-task">
<div>"<em>{{task?.title}}</em>"</div> <div class="label">for task</div>
</div> <div>
<div style="text-align: center; margin-bottom: 8px"> "<em>{{ task?.title }}</em
<button >"
mat-stroked-button </div>
type="button" </div>
(click)="selectDifferentTask()" <div style="text-align: center; margin-bottom: 8px">
> <button
<!-- <mat-icon>arrow_back_ios</mat-icon>--> mat-stroked-button
{{T.F.FOCUS_MODE.SELECT_ANOTHER_TASK|translate}} type="button"
</button> (click)="selectDifferentTask()"
</div> >
} @if(selectedMode() !== FocusModeMode.Flowtime) { <!-- <mat-icon>arrow_back_ios</mat-icon>-->
{{ T.F.FOCUS_MODE.SELECT_ANOTHER_TASK | translate }}
<input-duration-slider </button>
[model]="sessionDuration$|async" </div>
(modelChange)="onFocusModeDurationChanged($event)" }
></input-duration-slider> @if (selectedMode() !== FocusModeMode.Flowtime) {
<input-duration-slider
[model]="sessionDuration$ | async"
(modelChange)="onFocusModeDurationChanged($event)"
></input-duration-slider>
} }
<button <button
style="margin-top: 16px" style="margin-top: 16px"
@ -32,6 +36,6 @@
color="primary" color="primary"
mat-raised-button mat-raised-button
> >
{{T.F.FOCUS_MODE.START_FOCUS_SESSION|translate}} {{ T.F.FOCUS_MODE.START_FOCUS_SESSION | translate }}
</button> </button>
</form> </form>

View file

@ -1,128 +1,137 @@
@let isCountTimeDown = isCountTimeDown$|async; <!--@let isCountTimeDown = isCountTimeDown$|async;-->
<!-- --> <!--&lt;!&ndash; &ndash;&gt;-->
@if (taskService.currentTask$|async; as task) { <!--@if (taskService.currentTask$|async; as task) {-->
<task-title <!-- <task-title-->
(valueEdited)="updateTaskTitleIfChanged($event.wasChanged, $event.newVal)" <!-- (valueEdited)="updateTaskTitleIfChanged($event.wasChanged, $event.newVal)"-->
[value]="task.title" <!-- [value]="task.title"-->
class="task-title" <!-- class="task-title"-->
></task-title> <!-- ></task-title>-->
<div class="progress-wrapper"> <!-- <div class="progress-wrapper">-->
@if (isCountTimeDown) { <!-- @if (isCountTimeDown) {-->
<progress-circle [progress]="sessionProgress$|async"></progress-circle> <!-- <progress-circle [progress]="sessionProgress$|async"></progress-circle>-->
} @else { <!-- } @else {-->
<progress-circle [autoRotationDuration]="60000"></progress-circle> <!-- <progress-circle [autoRotationDuration]="60000"></progress-circle>-->
} <!-- }-->
<div class="progress-label-wrapper"> <!-- <div class="progress-label-wrapper">-->
<div <!-- <div-->
class="focus-time" <!-- class="focus-time"-->
title="Focus time" <!-- title="Focus time"-->
> <!-- >-->
<!-- {{focusModeTimeToGo / 60000}}min--> <!-- &lt;!&ndash; {{focusModeTimeToGo / 60000}}min&ndash;&gt;-->
@if(isCountTimeDown) { {{ (timeToGo$|async|msToMinuteClockString) }} } @else { {{ <!-- @if (isCountTimeDown) {-->
(timeElapsed$|async|msToMinuteClockString) }} } <!-- {{ (timeToGo$|async|msToMinuteClockString) }}-->
</div> <!-- } @else {-->
<!-- <div class="task-times">--> <!-- {{ (timeElapsed$|async|msToMinuteClockString) }}-->
<!-- {{task.timeSpent|msToString}}/{{task.timeEstimate|msToString}}--> <!-- }-->
<!-- </div>--> <!-- </div>-->
</div> <!-- &lt;!&ndash; <div class="task-times">&ndash;&gt;-->
</div> <!-- &lt;!&ndash; {{task.timeSpent|msToString}}/{{task.timeEstimate|msToString}}&ndash;&gt;-->
@if ((simpleCounterService.enabledSimpleCounters$|async); as enabledSimpleCounters) { @if <!-- &lt;!&ndash; </div>&ndash;&gt;-->
(enabledSimpleCounters.length) { <!-- </div>-->
<section class="simple-counter-buttons"> <!-- </div>-->
@for (simpleCounter of enabledSimpleCounters; track trackById($index, simpleCounter)) { <!-- @if ((simpleCounterService.enabledSimpleCounters$|async); as enabledSimpleCounters) {-->
<simple-counter-button <!-- @if () {-->
[class.isHiddenWithoutFocus]="!simpleCounter.isOn" <!-- } (enabledSimpleCounters.length) {-->
[simpleCounter]="simpleCounter" <!-- <section class="simple-counter-buttons">-->
></simple-counter-button> <!-- @for (simpleCounter of enabledSimpleCounters; track trackById($index, simpleCounter))-->
} <!-- {-->
</section> <!-- <simple-counter-button-->
} } <!-- [class.isHiddenWithoutFocus]="!simpleCounter.isOn"-->
<section class="controls"> <!-- [simpleCounter]="simpleCounter"-->
<button <!-- ></simple-counter-button>-->
mat-icon-button <!-- }-->
[matTooltip]="T.F.FOCUS_MODE.FINISH_TASK_AND_SELECT_NEXT|translate" <!-- </section>-->
(click)="finishCurrentTask();" <!-- }-->
> <!-- }-->
<mat-icon>done</mat-icon> <!-- <section class="controls">-->
</button> <!-- <button-->
<button <!-- mat-icon-button-->
mat-icon-button <!-- [matTooltip]="T.F.FOCUS_MODE.FINISH_TASK_AND_SELECT_NEXT|translate"-->
[matTooltip]="T.F.FOCUS_MODE.GO_TO_PROCRASTINATION|translate" <!-- (click)="finishCurrentTask();"-->
(click)="getProcrastinationHelp()" <!-- >-->
> <!-- <mat-icon>done</mat-icon>-->
<mat-icon>flash_on</mat-icon> <!-- </button>-->
</button> <!-- <button-->
@if (task.issueId && task.issueType !== ICAL_TYPE) { <!-- mat-icon-button-->
<a <!-- [matTooltip]="T.F.FOCUS_MODE.GO_TO_PROCRASTINATION|translate"-->
mat-icon-button <!-- (click)="getProcrastinationHelp()"-->
[matTooltip]="T.F.FOCUS_MODE.OPEN_ISSUE_IN_BROWSER|translate" <!-- >-->
target="_blank" <!-- <mat-icon>flash_on</mat-icon>-->
[href]="issueUrl$|async" <!-- </button>-->
> <!-- @if (task.issueId && task.issueType !== ICAL_TYPE) {-->
@if (task.issuePoints) { <!-- <a-->
<div class="mini-badge bgc-primary">{{ task.issuePoints }}</div> <!-- mat-icon-button-->
} <!-- [matTooltip]="T.F.FOCUS_MODE.OPEN_ISSUE_IN_BROWSER|translate"-->
<mat-icon [svgIcon]="task.issueType|issueIcon"></mat-icon> <!-- target="_blank"-->
</a> <!-- [href]="issueUrl$|async"-->
} <!-- >-->
<button <!-- @if (task.issuePoints) {-->
(click)="isShowNotes=!isShowNotes" <!-- <div class="mini-badge bgc-primary">{{ task.issuePoints }}</div>-->
[matTooltip]="T.F.FOCUS_MODE.SHOW_HIDE_NOTES_AND_ATTACHMENTS|translate" <!-- }-->
class="ico-btn show-additional-info-btn" <!-- <mat-icon [svgIcon]="task.issueType|issueIcon"></mat-icon>-->
color="" <!-- </a>-->
mat-icon-button <!-- }-->
> <!-- <button-->
@if (!isShowNotes) { <!-- (click)="isShowNotes=!isShowNotes"-->
<mat-icon>chat</mat-icon> <!-- [matTooltip]="T.F.FOCUS_MODE.SHOW_HIDE_NOTES_AND_ATTACHMENTS|translate"-->
} @if (isShowNotes) { <!-- class="ico-btn show-additional-info-btn"-->
<mat-icon>expand_less</mat-icon> <!-- color=""-->
} <!-- mat-icon-button-->
</button> <!-- >-->
</section> <!-- @if (!isShowNotes) {-->
@if (isShowNotes) { <!-- <mat-icon>chat</mat-icon>-->
<div <!-- }-->
style="height: 100px" <!-- @if (isShowNotes) {-->
@expand <!-- <mat-icon>expand_less</mat-icon>-->
></div> <!-- }-->
<!-- </button>-->
<!-- </section>-->
<!-- @if (isShowNotes) {-->
<!-- <div-->
<!-- style="height: 100px"-->
<!-- @expand-->
<!-- ></div>-->
<div <!-- <div-->
class="notes-and-attachments" <!-- class="notes-and-attachments"-->
@slideInOutFromBottom <!-- @slideInOutFromBottom-->
> <!-- >-->
<button <!-- <button-->
(click)="isShowNotes=false" <!-- (click)="isShowNotes=false"-->
class="hide-notes-btn" <!-- class="hide-notes-btn"-->
color="" <!-- color=""-->
mat-mini-fab <!-- mat-mini-fab-->
> <!-- >-->
<mat-icon>expand_less</mat-icon> <!-- <mat-icon>expand_less</mat-icon>-->
</button> <!-- </button>-->
<div class="notes-panel"> <!-- <div class="notes-panel">-->
<inline-markdown <!-- <inline-markdown-->
(blur)="isFocusNotes=false" <!-- (blur)="isFocusNotes=false"-->
(blurred)="isFocusNotes=false" <!-- (blurred)="isFocusNotes=false"-->
(changed)="changeTaskNotes($event); isFocusNotes=false" <!-- (changed)="changeTaskNotes($event); isFocusNotes=false"-->
[isFocus]="isFocusNotes" <!-- [isFocus]="isFocusNotes"-->
[isShowControls]="true" <!-- [isShowControls]="true"-->
[model]="task.notes|| defaultTaskNotes" <!-- [model]="task.notes|| defaultTaskNotes"-->
></inline-markdown> <!-- ></inline-markdown>-->
</div> <!-- </div>-->
@if (task.attachments.length) { <!-- @if (task.attachments.length) {-->
<div <!-- <div-->
class="attachment-list-wrapper" <!-- class="attachment-list-wrapper"-->
@fade <!-- @fade-->
> <!-- >-->
<task-attachment-list <!-- <task-attachment-list-->
[taskId]="task.id" <!-- [taskId]="task.id"-->
[attachments]="task.attachments" <!-- [attachments]="task.attachments"-->
></task-attachment-list> <!-- ></task-attachment-list>-->
</div> <!-- </div>-->
} <!-- }-->
</div> <!-- </div>-->
} @if (isDragOver) { <!-- }-->
<div class="bgc-accent drag-over-msg"> <!-- @if (isDragOver) {-->
<mat-icon>add</mat-icon> <!-- <div class="bgc-accent drag-over-msg">-->
{{ T.F.TASK.CMP.DROP_ATTACHMENT|translate:{ title: task.title } }} <!-- <mat-icon>add</mat-icon>-->
</div> <!-- {{ T.F.TASK.CMP.DROP_ATTACHMENT|translate:{ title: task.title } }}-->
} } <!-- </div>-->
<!-- }-->
<!--}-->

View file

@ -1,20 +1,82 @@
<div class="mac-os-drag-bar"></div> <div class="mac-os-drag-bar"></div>
@if (!(isPomodoroEnabled$|async)) { @if (!(isPomodoroEnabled$ | async)) {
<header> <header>
<banner></banner> <banner></banner>
</header> </header>
@if (activePage()) { @if (activePage()) {
<main> <main>
@if (activePage() === FocusModePage.ProcrastinationHelp) { @if (activePage() === FocusModePage.ProcrastinationHelp) {
<button <button
class="close-btn" class="close-btn"
mat-icon-button mat-icon-button
(click)="leaveProcrastinationHelp()" (click)="leaveProcrastinationHelp()"
> >
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
</button> </button>
} @if (activePage() !== FocusModePage.ProcrastinationHelp) { }
@if (activePage() !== FocusModePage.ProcrastinationHelp) {
<button
class="close-btn"
mat-icon-button
(click)="closeOverlay()"
>
<mat-icon>close</mat-icon>
</button>
}
<ng-template #selectModeTpl>
<mat-button-toggle-group
class="focus-mode-select-mode"
[value]="selectedMode()"
(change)="selectMode($event.value)"
>
<mat-button-toggle [value]="FocusModeMode.Flowtime">Flowtime</mat-button-toggle>
<!-- <mat-button-toggle [value]="FocusModeMode.Pomodoro">Pomodoro</mat-button-toggle>-->
<mat-button-toggle [value]="FocusModeMode.Countdown"
>Countdown</mat-button-toggle
>
</mat-button-toggle-group>
</ng-template>
<!-- -->
@switch (activePage()) {
<!-- -->
@case (FocusModePage.ProcrastinationHelp) {
<div
class="scroll-container"
@warpIn
>
<procrastination></procrastination>
</div>
}
@case (FocusModePage.TaskSelection) {
<ng-container *ngTemplateOutlet="selectModeTpl"></ng-container>
<focus-mode-task-selection
style="margin-bottom: auto; margin-top: -32px"
@warpIn
></focus-mode-task-selection>
}
@case (FocusModePage.DurationSelection) {
<ng-container *ngTemplateOutlet="selectModeTpl"></ng-container>
<focus-mode-duration-selection
style="margin-bottom: auto; margin-top: -32px"
@warpIn
></focus-mode-duration-selection>
}
@case (FocusModePage.Preparation) {
<focus-mode-preparation @warpIn></focus-mode-preparation>
}
@case (FocusModePage.Main) {
<focus-mode-main @warpIn></focus-mode-main>
}
@case (FocusModePage.SessionDone) {
<focus-mode-task-done @warpIn></focus-mode-task-done>
}
}
</main>
}
} @else {
<button <button
class="close-btn" class="close-btn"
mat-icon-button mat-icon-button
@ -22,76 +84,24 @@
> >
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
</button> </button>
} <div class="pomodoro-info-wrapper">
<div class="pomodoro-info-msg">{{ T.F.FOCUS_MODE.POMODORO_INFO | translate }}</div>
<ng-template #selectModeTpl> <div style="text-align: center">
<mat-button-toggle-group <button
class="focus-mode-select-mode" mat-stroked-button
[value]="selectedMode()" color="primary"
(change)="selectMode($event.value)" (click)="deactivatePomodoro()"
> >
<mat-button-toggle [value]="FocusModeMode.Flowtime">Flowtime</mat-button-toggle> <mat-icon>alarm_off</mat-icon>
<!-- <mat-button-toggle [value]="FocusModeMode.Pomodoro">Pomodoro</mat-button-toggle>--> {{ T.F.FOCUS_MODE.POMODORO_DISABLE | translate }}
<mat-button-toggle [value]="FocusModeMode.Countdown">Countdown</mat-button-toggle> </button>
</mat-button-toggle-group> <button
</ng-template> mat-stroked-button
(click)="cancelFocusSession()"
<!-- --> >
@switch (activePage()) { <mat-icon>arrow_back</mat-icon>
<!-- --> {{ T.F.FOCUS_MODE.BACK_TO_PLANNING | translate }}
@case (FocusModePage.ProcrastinationHelp) { </button>
<div </div>
class="scroll-container"
@warpIn
>
<procrastination></procrastination>
</div> </div>
} @case (FocusModePage.TaskSelection) {
<ng-container *ngTemplateOutlet="selectModeTpl"></ng-container>
<focus-mode-task-selection
style="margin-bottom: auto; margin-top: -32px"
@warpIn
></focus-mode-task-selection>
} @case (FocusModePage.DurationSelection) {
<ng-container *ngTemplateOutlet="selectModeTpl"></ng-container>
<focus-mode-duration-selection
style="margin-bottom: auto; margin-top: -32px"
@warpIn
></focus-mode-duration-selection>
} @case (FocusModePage.Preparation) {
<focus-mode-preparation @warpIn></focus-mode-preparation>
} @case (FocusModePage.Main) {
<focus-mode-main @warpIn></focus-mode-main>
} @case (FocusModePage.SessionDone) {
<focus-mode-task-done @warpIn></focus-mode-task-done>
} }
</main>
} } @else {
<button
class="close-btn"
mat-icon-button
(click)="closeOverlay()"
>
<mat-icon>close</mat-icon>
</button>
<div class="pomodoro-info-wrapper">
<div class="pomodoro-info-msg">{{ T.F.FOCUS_MODE.POMODORO_INFO|translate }}</div>
<div style="text-align: center">
<button
mat-stroked-button
color="primary"
(click)="deactivatePomodoro()"
>
<mat-icon>alarm_off</mat-icon>
{{ T.F.FOCUS_MODE.POMODORO_DISABLE|translate }}
</button>
<button
mat-stroked-button
(click)="cancelFocusSession()"
>
<mat-icon>arrow_back</mat-icon>
{{ T.F.FOCUS_MODE.BACK_TO_PLANNING|translate }}
</button>
</div>
</div>
} }

View file

@ -1,25 +1,27 @@
@if (countdown$|async; as countdown) { @if (countdown > 0) { @if (countdown$ | async; as countdown) {
<section> @if (countdown > 0) {
<div class="action-msg">{{T.F.FOCUS_MODE.GET_READY|translate}}</div> <section>
<ol> <div class="action-msg">{{ T.F.FOCUS_MODE.GET_READY | translate }}</div>
<li>{{T.F.FOCUS_MODE.PREP_STRETCH|translate}}</li> <ol>
<li>{{T.F.FOCUS_MODE.PREP_SIT_UPRIGHT|translate}}</li> <li>{{ T.F.FOCUS_MODE.PREP_STRETCH | translate }}</li>
<li>{{T.F.FOCUS_MODE.PREP_GET_MENTALLY_READY|translate}}</li> <li>{{ T.F.FOCUS_MODE.PREP_SIT_UPRIGHT | translate }}</li>
</ol> <li>{{ T.F.FOCUS_MODE.PREP_GET_MENTALLY_READY | translate }}</li>
<div class="countdown-timer">{{countdown}}</div> </ol>
<!-- <div style="text-align: center">--> <div class="countdown-timer">{{ countdown }}</div>
<!-- <button--> <!-- <div style="text-align: center">-->
<!-- type="submit"--> <!-- <button-->
<!-- color="primary"--> <!-- type="submit"-->
<!-- mat-raised-button--> <!-- color="primary"-->
<!-- (click)="startSession()"--> <!-- mat-raised-button-->
<!-- >--> <!-- (click)="startSession()"-->
<!-- Start Focus Session--> <!-- >-->
<!-- </button>--> <!-- Start Focus Session-->
<!-- </div>--> <!-- </button>-->
</section> <!-- </div>-->
} } @else { </section>
<section @fade> }
<div class="action-msg">{{T.F.FOCUS_MODE.GOGOGO|translate}}</div> } @else {
</section> <section @fade>
<div class="action-msg">{{ T.F.FOCUS_MODE.GOGOGO | translate }}</div>
</section>
} }

View file

@ -7,12 +7,12 @@
<h1>Focus Session Completed!</h1> <h1>Focus Session Completed!</h1>
<div class="msg"> <div class="msg">
<div class="worked-for-label">{{T.F.FOCUS_MODE.WORKED_FOR|translate}}</div> <div class="worked-for-label">{{ T.F.FOCUS_MODE.WORKED_FOR | translate }}</div>
<div class="worked-for-value">{{6213000|msToString:true}}</div> <div class="worked-for-value">{{ 6213000 | msToString: true }}</div>
<!-- <div class="worked-for-value">{{timeElapsed$|async|msToString:true}}</div>--> <!-- <div class="worked-for-value">{{timeElapsed$|async|msToString:true}}</div>-->
<div class="task-title-label">{{T.F.FOCUS_MODE.ON|translate}}</div> <div class="task-title-label">{{ T.F.FOCUS_MODE.ON | translate }}</div>
<div class="task-title">{{taskTitle$|async}}</div> <div class="task-title">{{ taskTitle$ | async }}</div>
</div> </div>
<div class="btn-wrapper"> <div class="btn-wrapper">
@ -21,24 +21,25 @@
color="primary" color="primary"
(click)="closeFocusOverlay()" (click)="closeFocusOverlay()"
> >
{{T.F.FOCUS_MODE.BACK_TO_PLANNING|translate}} {{ T.F.FOCUS_MODE.BACK_TO_PLANNING | translate }}
</button> </button>
@if (!(currentTask$|async)) { @if (!(currentTask$ | async)) {
<button <button
mat-raised-button mat-raised-button
color="primary" color="primary"
(click)="startNextFocusSession()" (click)="startNextFocusSession()"
> >
{{T.F.FOCUS_MODE.START_NEXT_FOCUS_SESSION|translate}} {{ T.F.FOCUS_MODE.START_NEXT_FOCUS_SESSION | translate }}
</button> </button>
} @if ((currentTask$|async)) { }
<button @if (currentTask$ | async) {
mat-raised-button <button
color="primary" mat-raised-button
(click)="continueWithFocusSession()" color="primary"
> (click)="continueWithFocusSession()"
{{T.F.FOCUS_MODE.CONTINUE_FOCUS_SESSION|translate}} >
</button> {{ T.F.FOCUS_MODE.CONTINUE_FOCUS_SESSION | translate }}
</button>
} }
</div> </div>

View file

@ -1,12 +1,12 @@
<form <form
(submit)="$event.preventDefault();onSubmit($event)" (submit)="$event.preventDefault(); onSubmit($event)"
novalidate novalidate
> >
<h1>{{T.F.FOCUS_MODE.SELECT_TASK|translate}}</h1> <h1>{{ T.F.FOCUS_MODE.SELECT_TASK | translate }}</h1>
<select-task <select-task
(taskChange)="onTaskChange($event)" (taskChange)="onTaskChange($event)"
[initialTask]="initialTask$|async" [initialTask]="initialTask$ | async"
[isIncludeDoneTasks]="false" [isIncludeDoneTasks]="false"
> >
</select-task> </select-task>
@ -17,6 +17,6 @@
color="primary" color="primary"
mat-raised-button mat-raised-button
> >
{{T.F.FOCUS_MODE.NEXT|translate}} {{ T.F.FOCUS_MODE.NEXT | translate }}
</button> </button>
</form> </form>

View file

@ -2,65 +2,72 @@
class="dialog-content" class="dialog-content"
mat-dialog-content mat-dialog-content
> >
<p>{{T.F.TIME_TRACKING.D_IDLE.IDLE_FOR|translate}}</p> <p>{{ T.F.TIME_TRACKING.D_IDLE.IDLE_FOR | translate }}</p>
<div class="time">{{idleTime$|async|msToString:true}}</div> <div class="time">{{ idleTime$ | async | msToString: true }}</div>
<div class="track-to-items"> <div class="track-to-items">
@for (item of trackItems; track item) { @for (item of trackItems; track item) {
<div class="track-to-item"> <div class="track-to-item">
<div class="first-block"> <div class="first-block">
<mat-button-toggle-group [(ngModel)]="item.type"> <mat-button-toggle-group [(ngModel)]="item.type">
<mat-button-toggle value="BREAK"> <mat-button-toggle value="BREAK">
<mat-icon>free_breakfast</mat-icon> <mat-icon>free_breakfast</mat-icon>
</mat-button-toggle> </mat-button-toggle>
<!-- <mat-button-toggle value="TASK_AND_BREAK">--> <!-- <mat-button-toggle value="TASK_AND_BREAK">-->
<!-- <mat-icon>track_changes</mat-icon>--> <!-- <mat-icon>track_changes</mat-icon>-->
<!-- +--> <!-- +-->
<!-- <mat-icon>free_breakfast</mat-icon>--> <!-- <mat-icon>free_breakfast</mat-icon>-->
<!-- </mat-button-toggle>--> <!-- </mat-button-toggle>-->
<mat-button-toggle value="TASK"> <mat-button-toggle value="TASK">
<mat-icon>track_changes</mat-icon> <mat-icon>track_changes</mat-icon>
</mat-button-toggle> </mat-button-toggle>
</mat-button-toggle-group> </mat-button-toggle-group>
<select-task <select-task
[isIncludeDoneTasks]="true" [isIncludeDoneTasks]="true"
[initialTask]="item.task" [initialTask]="item.task"
(taskChange)="onTaskChange(item, $event)" (taskChange)="onTaskChange(item, $event)"
[class.isDisabled]="item.type==='BREAK'" [class.isDisabled]="item.type === 'BREAK'"
>
</select-task>
<section class="simple-counter-section">
@for (simpleCounterBtn of item.simpleCounterToggleBtns; track simpleCounterBtn)
{
<button
mat-mini-fab
class="simple-counter"
type="button"
(click)="simpleCounterBtn.isTrackTo=!simpleCounterBtn.isTrackTo"
[matTooltip]="(simpleCounterBtn.isTrackTo ? T.F.TIME_TRACKING.D_IDLE.SIMPLE_COUNTER_TOOLTIP_DISABLE : T.F.TIME_TRACKING.D_IDLE.SIMPLE_COUNTER_TOOLTIP)|translate:{ title: simpleCounterBtn.title }"
[color]="simpleCounterBtn.isTrackTo ? 'primary' : ''"
> >
<mat-icon>{{simpleCounterBtn.icon}}</mat-icon> </select-task>
</button> <section class="simple-counter-section">
} @for (
</section> simpleCounterBtn of item.simpleCounterToggleBtns;
</div> track simpleCounterBtn
<input-duration-slider ) {
[(model)]="item.time" <button
[label]="T.F.TASK.D_TIME.TIME_SPENT|translate" mat-mini-fab
> class="simple-counter"
</input-duration-slider> type="button"
<div> (click)="simpleCounterBtn.isTrackTo = !simpleCounterBtn.isTrackTo"
<button [matTooltip]="
mat-icon-button (simpleCounterBtn.isTrackTo
[color]="'warn'" ? T.F.TIME_TRACKING.D_IDLE.SIMPLE_COUNTER_TOOLTIP_DISABLE
(click)="removeTrackItem(item)" : T.F.TIME_TRACKING.D_IDLE.SIMPLE_COUNTER_TOOLTIP
[disabled]="trackItems.length <= 1" ) | translate: { title: simpleCounterBtn.title }
"
[color]="simpleCounterBtn.isTrackTo ? 'primary' : ''"
>
<mat-icon>{{ simpleCounterBtn.icon }}</mat-icon>
</button>
}
</section>
</div>
<input-duration-slider
[(model)]="item.time"
[label]="T.F.TASK.D_TIME.TIME_SPENT | translate"
> >
<mat-icon>delete_forever</mat-icon> </input-duration-slider>
</button> <div>
<button
mat-icon-button
[color]="'warn'"
(click)="removeTrackItem(item)"
[disabled]="trackItems.length <= 1"
>
<mat-icon>delete_forever</mat-icon>
</button>
</div>
</div> </div>
</div>
} }
<div style="text-align: center; margin-top: 8px"> <div style="text-align: center; margin-top: 8px">
@ -69,7 +76,7 @@
(click)="addTrackItem()" (click)="addTrackItem()"
> >
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
{{T.F.TIME_TRACKING.D_IDLE.ADD_ENTRY|translate}} {{ T.F.TIME_TRACKING.D_IDLE.ADD_ENTRY | translate }}
</button> </button>
</div> </div>
</div> </div>
@ -85,7 +92,7 @@
mat-button mat-button
type="button" type="button"
> >
{{T.G.CANCEL|translate}} {{ T.G.CANCEL | translate }}
</button> </button>
<button <button
@ -95,6 +102,6 @@
type="submit" type="submit"
> >
<mat-icon>save</mat-icon> <mat-icon>save</mat-icon>
{{T.G.SAVE|translate}} {{ T.G.SAVE | translate }}
</button> </button>
</div> </div>

View file

@ -1,103 +1,112 @@
@if (isTaskDataLoadedIfNeeded) { @if (isTaskDataLoadedIfNeeded) {
<form (submit)="$event.preventDefault();track()"> <form (submit)="$event.preventDefault(); track()">
<div
class="dialog-content"
mat-dialog-content
>
<p>{{T.F.TIME_TRACKING.D_IDLE.IDLE_FOR|translate}}</p>
<div class="time">{{idleTime$|async|msToString:true}}</div>
<div <div
class="split-btn" class="dialog-content"
style="text-align: center" mat-dialog-content
> >
<button <p>{{ T.F.TIME_TRACKING.D_IDLE.IDLE_FOR | translate }}</p>
mat-icon-button <div class="time">{{ idleTime$ | async | msToString: true }}</div>
[matTooltip]="T.F.TIME_TRACKING.D_IDLE.SPLIT_TIME|translate" <div
(click)="showSplit()" class="split-btn"
type="button" style="text-align: center"
> >
<mat-icon>call_split</mat-icon> <button
</button> mat-icon-button
</div> [matTooltip]="T.F.TIME_TRACKING.D_IDLE.SPLIT_TIME | translate"
<div class="track-to-label"> (click)="showSplit()"
@if (!isCreate) { type="button"
<span>{{T.F.TIME_TRACKING.D_IDLE.TRACK_TO|translate}}</span> >
} @if (isCreate) { <mat-icon>call_split</mat-icon>
<span [innerHTML]="T.F.TIME_TRACKING.D_IDLE.CREATE_AND_TRACK|translate"></span> </button>
</div>
<div class="track-to-label">
@if (!isCreate) {
<span>{{ T.F.TIME_TRACKING.D_IDLE.TRACK_TO | translate }}</span>
}
@if (isCreate) {
<span
[innerHTML]="T.F.TIME_TRACKING.D_IDLE.CREATE_AND_TRACK | translate"
></span>
}
</div>
<select-task
(taskChange)="onTaskChange($event)"
[isIncludeDoneTasks]="true"
[initialTask]="selectedTask"
></select-task>
<section class="simple-counter-section">
@for (simpleCounterBtn of simpleCounterToggleBtns; track simpleCounterBtn) {
<button
mat-mini-fab
class="simple-counter"
type="button"
(click)="simpleCounterBtn.isTrackTo = !simpleCounterBtn.isTrackTo"
[matTooltip]="
(simpleCounterBtn.isTrackTo
? T.F.TIME_TRACKING.D_IDLE.SIMPLE_COUNTER_TOOLTIP_DISABLE
: T.F.TIME_TRACKING.D_IDLE.SIMPLE_COUNTER_TOOLTIP
) | translate: { title: simpleCounterBtn.title }
"
[color]="simpleCounterBtn.isTrackTo ? 'primary' : ''"
>
<mat-icon>{{ simpleCounterBtn.icon }}</mat-icon>
</button>
}
</section>
@if ((configService.takeABreak$ | async)?.isTakeABreakEnabled) {
<div
style="
display: flex;
justify-content: center;
margin-top: 16px;
margin-bottom: -8px;
"
>
<mat-checkbox
[(ngModel)]="isResetBreakTimer"
[ngModelOptions]="{ standalone: true }"
>
{{ T.F.TIME_TRACKING.D_IDLE.RESET_BREAK_REMINDER_TIMER | translate }}
</mat-checkbox>
</div>
} }
</div> </div>
<select-task
(taskChange)="onTaskChange($event)"
[isIncludeDoneTasks]="true"
[initialTask]="selectedTask"
></select-task>
<section class="simple-counter-section">
@for (simpleCounterBtn of simpleCounterToggleBtns; track simpleCounterBtn) {
<button
mat-mini-fab
class="simple-counter"
type="button"
(click)="simpleCounterBtn.isTrackTo=!simpleCounterBtn.isTrackTo"
[matTooltip]="(simpleCounterBtn.isTrackTo ? T.F.TIME_TRACKING.D_IDLE.SIMPLE_COUNTER_TOOLTIP_DISABLE : T.F.TIME_TRACKING.D_IDLE.SIMPLE_COUNTER_TOOLTIP)|translate:{ title: simpleCounterBtn.title }"
[color]="simpleCounterBtn.isTrackTo ? 'primary' : ''"
>
<mat-icon>{{simpleCounterBtn.icon}}</mat-icon>
</button>
}
</section>
@if ((configService.takeABreak$|async)?.isTakeABreakEnabled) {
<div <div
style=" align="center"
display: flex; mat-dialog-actions
justify-content: center;
margin-top: 16px;
margin-bottom: -8px;
"
> >
<mat-checkbox <button
[(ngModel)]="isResetBreakTimer" (click)="skipTrack()"
[ngModelOptions]=" color=""
{standalone: true}" mat-button
type="button"
> >
{{ T.F.TIME_TRACKING.D_IDLE.RESET_BREAK_REMINDER_TIMER|translate }} <mat-icon>skip_next</mat-icon>
</mat-checkbox> {{ T.F.TIME_TRACKING.D_IDLE.SKIP | translate }}
</button>
<button
(click)="trackAsBreak()"
color="primary"
mat-stroked-button
type="button"
>
<mat-icon>free_breakfast</mat-icon>
{{ T.F.TIME_TRACKING.D_IDLE.BREAK | translate }}
</button>
<button
[disabled]="!(selectedTask || newTaskTitle)"
color="primary"
mat-stroked-button
type="submit"
>
@if (!isCreate) {
<mat-icon>track_changes</mat-icon>
}
@if (isCreate) {
<mat-icon>add</mat-icon>
}
{{ T.F.TIME_TRACKING.D_IDLE.TASK | translate }}
</button>
</div> </div>
} </form>
</div>
<div
align="center"
mat-dialog-actions
>
<button
(click)="skipTrack()"
color=""
mat-button
type="button"
>
<mat-icon>skip_next</mat-icon>
{{T.F.TIME_TRACKING.D_IDLE.SKIP|translate}}
</button>
<button
(click)="trackAsBreak()"
color="primary"
mat-stroked-button
type="button"
>
<mat-icon>free_breakfast</mat-icon>
{{T.F.TIME_TRACKING.D_IDLE.BREAK|translate}}
</button>
<button
[disabled]="!(selectedTask||newTaskTitle)"
color="primary"
mat-stroked-button
type="submit"
>
@if (!isCreate) {
<mat-icon>track_changes</mat-icon>
} @if (isCreate) {
<mat-icon>add</mat-icon>
} {{T.F.TIME_TRACKING.D_IDLE.TASK|translate}}
</button>
</div>
</form>
} }

View file

@ -1,33 +1,37 @@
@if (isLoading()) { @if (isLoading()) {
<div class="spinner"> <div class="spinner">
<mat-spinner diameter="50"></mat-spinner> <mat-spinner diameter="50"></mat-spinner>
</div> </div>
} @else if (error()) { } @else if (error()) {
<error-card <error-card
[errorTxt]="error()" [errorTxt]="error()"
[actionAdvice]="'Check your config!'" [actionAdvice]="'Check your config!'"
></error-card> ></error-card>
} @else if (!agendaItems()?.length) { } @else if (!agendaItems()?.length) {
<div class="empty">No items found (already added are not shown)</div> <div class="empty">No items found (already added are not shown)</div>
} @else { } @else {
<div class="agenda"> <div class="agenda">
@for (day of agendaItems(); track day.dayStr) { @for (day of agendaItems(); track day.dayStr) {
<div class="agenda-day"> <div class="agenda-day">
<h4>{{ day.dayStr|date:'shortDate' }}</h4> <h4>{{ day.dayStr | date: 'shortDate' }}</h4>
<div <div
class="item-list" class="item-list"
[@standardList]="day.itemsForDay.length" [@standardList]="day.itemsForDay.length"
> >
@for (item of day.itemsForDay; track item.issueData.id) { @for (item of day.itemsForDay; track item.issueData.id) {
<issue-preview-item <issue-preview-item
[issueProviderId]="issueProvider().id" [issueProviderId]="issueProvider().id"
[itemData]="item" [itemData]="item"
[customTitleStr]="(item.issueData?.start|date:'shortTime') + ' ' + item.issueData?.title" [customTitleStr]="
(addIssue)="addIssue($event)" (item.issueData?.start | date: 'shortTime') +
></issue-preview-item> ' ' +
} item.issueData?.title
</div> "
(addIssue)="addIssue($event)"
></issue-preview-item>
}
</div>
</div>
}
</div> </div>
}
</div>
} }

View file

@ -1,5 +1,5 @@
@if (isShowIntro()) { @if (isShowIntro()) {
<issue-panel-intro></issue-panel-intro> <issue-panel-intro></issue-panel-intro>
} }
<mat-tab-group <mat-tab-group
@ -15,29 +15,29 @@
[selectedIndex]="selectedTabIndex()" [selectedIndex]="selectedTabIndex()"
> >
@for (entry of issueProvidersMapped(); track entry.issueProvider.id) { @for (entry of issueProvidersMapped(); track entry.issueProvider.id) {
<mat-tab> <mat-tab>
<ng-template mat-tab-label> <ng-template mat-tab-label>
<div <div
cdkDrag cdkDrag
cdkDragRootElement=".mat-mdc-tab" cdkDragRootElement=".mat-mdc-tab"
cdkDragPreviewClass="issue-provider-drag-preview" cdkDragPreviewClass="issue-provider-drag-preview"
class="tab-header-item" class="tab-header-item"
[class.disabled]="!entry.issueProvider.isEnabled" [class.disabled]="!entry.issueProvider.isEnabled"
(longPressIOS)="openEditIssueProvider(entry.issueProvider)" (longPressIOS)="openEditIssueProvider(entry.issueProvider)"
(longPress)="openEditIssueProvider(entry.issueProvider)" (longPress)="openEditIssueProvider(entry.issueProvider)"
> >
<mat-icon <mat-icon
[svgIcon]="entry.issueProvider.issueProviderKey|issueIcon" [svgIcon]="entry.issueProvider.issueProviderKey | issueIcon"
[matTooltip]="entry.tooltip" [matTooltip]="entry.tooltip"
matTooltipPosition="above" matTooltipPosition="above"
></mat-icon> ></mat-icon>
<div class="initials">{{ entry.initials }}</div> <div class="initials">{{ entry.initials }}</div>
</div> </div>
</ng-template> </ng-template>
<ng-template matTabContent> <ng-template matTabContent>
<issue-provider-tab [issueProvider]="entry.issueProvider"></issue-provider-tab> <issue-provider-tab [issueProvider]="entry.issueProvider"></issue-provider-tab>
</ng-template> </ng-template>
</mat-tab> </mat-tab>
} }
<mat-tab> <mat-tab>

View file

@ -8,12 +8,12 @@
<div class="title">{{ customTitleStr() || itemData().title }}</div> <div class="title">{{ customTitleStr() || itemData().title }}</div>
@if(itemData().issueType !== ICAL_TYPE) { @if (itemData().issueType !== ICAL_TYPE) {
<button <button
class="open-issue" class="open-issue"
mat-icon-button mat-icon-button
(click)="openIssue()" (click)="openIssue()"
> >
<mat-icon>open_in_new</mat-icon> <mat-icon>open_in_new</mat-icon>
</button> </button>
} }

View file

@ -8,125 +8,128 @@
<mat-icon>settings</mat-icon> <mat-icon>settings</mat-icon>
</button> </button>
<div class="title">{{ issueProviderTooltip() }}</div> <div class="title">{{ issueProviderTooltip() }}</div>
@let defaultP = defaultProject(); @if (defaultP) { @let defaultP = defaultProject();
<mat-icon class="arrow">arrow_forward</mat-icon> @if (defaultP) {
<div class="default-project">{{ defaultP.title }}</div> <mat-icon class="arrow">arrow_forward</mat-icon>
<div class="default-project">{{ defaultP.title }}</div>
} }
</header> </header>
@let ip = issueProvider(); @let ip = issueProvider();
<!----> <!---->
@if (ip.isEnabled) { @if (ip.isEnabled) {
<!----> <!---->
@if (ip.issueProviderKey === 'JIRA') { @if (ip.issueProviderKey === 'JIRA') {
<div [ngClass]="HelperClasses.isHideForAdvancedFeatures"> <div [ngClass]="HelperClasses.isHideForAdvancedFeatures">
<p [innerHTML]="T.G.EXTENSION_INFO|translate"></p> <p [innerHTML]="T.G.EXTENSION_INFO | translate"></p>
</div> </div>
}
<!---->
@if(ip.issueProviderKey === 'ICAL') {
<issue-panel-calendar-agenda [issueProvider]="ip"></issue-panel-calendar-agenda>
} @else {
<form
class="example-form"
style="width: 100%; margin: 8px 0 16px"
>
<mat-form-field
style="width: 100%; margin: 0"
appearance="outline"
>
<!-- <mat-icon matPrefix>filter_alt</mat-icon>-->
<!-- <mat-label>Filter</mat-label>-->
<mat-label>Search</mat-label>
<mat-icon
matPrefix
style="opacity: 0.5"
>search</mat-icon
>
<input
#searchTextEl
[ngModel]="searchText()"
(ngModelChange)="searchText.set($event)"
autocomplete="off"
matInput
name="search"
placeholder="Search"
/>
@if (isPinned()) {
<mat-icon
class="keep-ico"
matSuffix
svgIcon="keep_filled"
style="cursor: pointer"
(click)="unPinSearch()"
[matTooltip]="'Clear pinned search query'"
></mat-icon>
} @else if(ip?.pinnedSearch?.length||searchText()?.length >= SEARCH_MIN_LENGTH) {
<mat-icon
class="keep-ico"
matSuffix
svgIcon="keep"
style="cursor: pointer"
(click)="pinSearch()"
[matTooltip]="'Remember search query'"
></mat-icon>
}
<!-- -->
@if (searchText().length ===0 && issueProviderHelpLink()) {
<mat-hint
><a
[href]="issueProviderHelpLink()"
target="_blank"
>{{ISSUE_PROVIDER_HUMANIZED[ip.issueProviderKey]}} search syntax</a
></mat-hint
>
}
<!-- @if (searchText()?.length > 0) {-->
<!-- <mat-icon-->
<!-- style="cursor: pointer"-->
<!-- matSuffix-->
<!-- (click)="searchText.set('')"-->
<!-- >close</mat-icon-->
<!-- >-->
<!-- }-->
</mat-form-field>
</form>
}
<!---->
@if (isLoading()) {
<div class="spinner">
<mat-spinner diameter="50"></mat-spinner>
</div>
} @else if (error()) {
<error-card
[errorTxt]="error()"
[actionAdvice]="'Check your config!'"
></error-card>
} @else if (!issueItems()?.length && searchText()?.length > 0) {
<div class="empty">No items found (already added are not shown)</div>
} @else {
<div
class="item-list"
[@standardList]="issueItems()?.length"
>
<!-- (cdkDropListDropped)="drop($event)"-->
@for (item of issueItems(); track item.issueData.id) {
<!-- <div style="display: flex; align-items: center">-->
<!-- <button-->
<!-- mat-icon-button-->
<!-- color=""-->
<!-- >-->
<!-- <mat-icon>add</mat-icon>-->
<!-- </button>-->
<issue-preview-item
[issueProviderId]="ip.id"
[itemData]="item"
(addIssue)="addIssue($event)"
></issue-preview-item>
<!-- </div>-->
} }
</div> <!---->
} } @if (ip.issueProviderKey === 'ICAL') {
<issue-panel-calendar-agenda [issueProvider]="ip"></issue-panel-calendar-agenda>
} @else {
<form
class="example-form"
style="width: 100%; margin: 8px 0 16px"
>
<mat-form-field
style="width: 100%; margin: 0"
appearance="outline"
>
<!-- <mat-icon matPrefix>filter_alt</mat-icon>-->
<!-- <mat-label>Filter</mat-label>-->
<mat-label>Search</mat-label>
<mat-icon
matPrefix
style="opacity: 0.5"
>search</mat-icon
>
<input
#searchTextEl
[ngModel]="searchText()"
(ngModelChange)="searchText.set($event)"
autocomplete="off"
matInput
name="search"
placeholder="Search"
/>
@if (isPinned()) {
<mat-icon
class="keep-ico"
matSuffix
svgIcon="keep_filled"
style="cursor: pointer"
(click)="unPinSearch()"
[matTooltip]="'Clear pinned search query'"
></mat-icon>
} @else if (
ip?.pinnedSearch?.length || searchText()?.length >= SEARCH_MIN_LENGTH
) {
<mat-icon
class="keep-ico"
matSuffix
svgIcon="keep"
style="cursor: pointer"
(click)="pinSearch()"
[matTooltip]="'Remember search query'"
></mat-icon>
}
<!-- -->
@if (searchText().length === 0 && issueProviderHelpLink()) {
<mat-hint
><a
[href]="issueProviderHelpLink()"
target="_blank"
>{{ ISSUE_PROVIDER_HUMANIZED[ip.issueProviderKey] }} search syntax</a
></mat-hint
>
}
<!-- @if (searchText()?.length > 0) {-->
<!-- <mat-icon-->
<!-- style="cursor: pointer"-->
<!-- matSuffix-->
<!-- (click)="searchText.set('')"-->
<!-- >close</mat-icon-->
<!-- >-->
<!-- }-->
</mat-form-field>
</form>
}
<!---->
@if (isLoading()) {
<div class="spinner">
<mat-spinner diameter="50"></mat-spinner>
</div>
} @else if (error()) {
<error-card
[errorTxt]="error()"
[actionAdvice]="'Check your config!'"
></error-card>
} @else if (!issueItems()?.length && searchText()?.length > 0) {
<div class="empty">No items found (already added are not shown)</div>
} @else {
<div
class="item-list"
[@standardList]="issueItems()?.length"
>
<!-- (cdkDropListDropped)="drop($event)"-->
@for (item of issueItems(); track item.issueData.id) {
<!-- <div style="display: flex; align-items: center">-->
<!-- <button-->
<!-- mat-icon-button-->
<!-- color=""-->
<!-- >-->
<!-- <mat-icon>add</mat-icon>-->
<!-- </button>-->
<issue-preview-item
[issueProviderId]="ip.id"
[itemData]="item"
(addIssue)="addIssue($event)"
></issue-preview-item>
<!-- </div>-->
}
</div>
}
}

View file

@ -7,7 +7,7 @@
<h1 mat-dialog-title> <h1 mat-dialog-title>
<mat-icon <mat-icon
class="dialog-header-icon" class="dialog-header-icon"
[svgIcon]="(issueProviderKey)|issueIcon" [svgIcon]="issueProviderKey | issueIcon"
></mat-icon> ></mat-icon>
<!-- TODO improve title --> <!-- TODO improve title -->
@ -20,95 +20,108 @@
(ngSubmit)="submit()" (ngSubmit)="submit()"
> >
<mat-dialog-content> <mat-dialog-content>
@if (configFormSection?.help||configFormSection?.helpArr) { @if (configFormSection?.help || configFormSection?.helpArr) {
<help-section> <help-section>
@if (configFormSection?.help) { @if (configFormSection?.help) {
<div [innerHtml]="configFormSection?.help|translate"></div> <div [innerHtml]="configFormSection?.help | translate"></div>
} @if (configFormSection?.helpArr) { @for (helpSection of }
configFormSection?.helpArr; track helpSection) { @if (helpSection.h) { @if (configFormSection?.helpArr) {
<div class="mat-caption">{{ helpSection.h|translate }}</div> @for (helpSection of configFormSection?.helpArr; track helpSection) {
} @if (helpSection.p) { @if (helpSection.h) {
<p [innerHTML]="helpSection.p|translate"></p> <div class="mat-caption">{{ helpSection.h | translate }}</div>
} @if (helpSection.p2) { }
<p [innerHTML]="helpSection.p2|translate"></p> @if (helpSection.p) {
} @if (helpSection.p3) { <p [innerHTML]="helpSection.p | translate"></p>
<p [innerHTML]="helpSection.p3|translate"></p> }
} @if (helpSection.p4) { @if (helpSection.p2) {
<p [innerHTML]="helpSection.p4|translate"></p> <p [innerHTML]="helpSection.p2 | translate"></p>
} } } }
</help-section> @if (helpSection.p3) {
} @if (isEdit) { <p [innerHTML]="helpSection.p3 | translate"></p>
<div style="margin-bottom: 32px"> }
<mat-slide-toggle @if (helpSection.p4) {
[ngModel]="model.isEnabled" <p [innerHTML]="helpSection.p4 | translate"></p>
(ngModelChange)="changeEnabled($event)" }
[ngModelOptions]="{standalone: true}" }
> }
{{ T.G.ENABLED|translate }} </help-section>
</mat-slide-toggle> }
</div> @if (isEdit) {
<div style="margin-bottom: 32px">
<mat-slide-toggle
[ngModel]="model.isEnabled"
(ngModelChange)="changeEnabled($event)"
[ngModelOptions]="{ standalone: true }"
>
{{ T.G.ENABLED | translate }}
</mat-slide-toggle>
</div>
} }
<!-- --> <!-- -->
@if (model.isEnabled) { @if (model.isEnabled) {
<!-- --> <!-- -->
@if (issueProviderKey === ICAL_TYPE) { @if (issueProviderKey === ICAL_TYPE) {
<!-- --> <!-- -->
@if(d.calendarContextInfoTarget === 'GOOGLE'){ @if (d.calendarContextInfoTarget === 'GOOGLE') {
<div class="tpl"> <div class="tpl">
<p> <p>
<a <a
target="_blank" target="_blank"
href="https://support.google.com/calendar/answer/37648?hl=en#zippy=%2Cget-your-calendar-view-only" href="https://support.google.com/calendar/answer/37648?hl=en#zippy=%2Cget-your-calendar-view-only"
>How to get the iCal url for Google Calendar (view only)?</a >How to get the iCal url for Google Calendar (view only)?</a
> >
</p> </p>
<!-- <p [innerHTML]="T.G.EXTENSION_INFO|translate"></p>--> <!-- <p [innerHTML]="T.G.EXTENSION_INFO|translate"></p>-->
</div> </div>
} }
<!-- --> <!-- -->
@if(d.calendarContextInfoTarget === 'OUTLOOK365'){ @if (d.calendarContextInfoTarget === 'OUTLOOK365') {
<div class="tpl"> <div class="tpl">
<p> <p>
<a <a
target="_blank" target="_blank"
href="https://support.pushpay.com/s/article/How-do-I-get-an-iCal-link-from-Office-365" href="https://support.pushpay.com/s/article/How-do-I-get-an-iCal-link-from-Office-365"
>How to get the iCal url for Outlook 365 (ICS)?</a >How to get the iCal url for Outlook 365 (ICS)?</a
> >
</p> </p>
<!-- <p [innerHTML]="T.G.EXTENSION_INFO|translate"></p>--> <!-- <p [innerHTML]="T.G.EXTENSION_INFO|translate"></p>-->
</div> </div>
} } }
<!-- --> }
@if (issueProviderKey === 'JIRA') { <!-- -->
<div [ngClass]="HelperClasses.isHideForAdvancedFeatures"> @if (issueProviderKey === 'JIRA') {
<p [innerHTML]="T.G.EXTENSION_INFO|translate"></p> <div [ngClass]="HelperClasses.isHideForAdvancedFeatures">
</div> <p [innerHTML]="T.G.EXTENSION_INFO | translate"></p>
} </div>
}
<formly-form <formly-form
[model]="model" [model]="model"
(modelChange)="formlyModelChange($event)" (modelChange)="formlyModelChange($event)"
[fields]="fields" [fields]="fields"
[form]="form" [form]="form"
></formly-form> ></formly-form>
@switch (issueProviderKey) { @switch (issueProviderKey) {
<!-- --> <!-- -->
@case ("JIRA") { @case ('JIRA') {
<jira-additonal-cfg <jira-additonal-cfg
[section]="configFormSection" [section]="configFormSection"
[cfg]="model" [cfg]="model"
(modelChange)="customCfgCmpSave($event)" (modelChange)="customCfgCmpSave($event)"
></jira-additonal-cfg> ></jira-additonal-cfg>
<!-- --> <!-- -->
} @case ("OPEN_PROJECT") { }
<open-project-additional-cfg @case ('OPEN_PROJECT') {
[section]="configFormSection" <open-project-additional-cfg
[cfg]="model" [section]="configFormSection"
(modelChange)="customCfgCmpSave($event)" [cfg]="model"
></open-project-additional-cfg> (modelChange)="customCfgCmpSave($event)"
<!-- --> ></open-project-additional-cfg>
} } } <!-- -->
}
}
}
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
@ -118,39 +131,39 @@
mat-button mat-button
type="button" type="button"
> >
{{ T.G.CANCEL|translate }} {{ T.G.CANCEL | translate }}
</button> </button>
@if (isEdit) { @if (isEdit) {
<button <button
(click)="remove()" (click)="remove()"
color="warn" color="warn"
mat-button mat-button
type="button" type="button"
> >
<mat-icon>delete_forever</mat-icon> <mat-icon>delete_forever</mat-icon>
{{ T.G.DELETE|translate }} {{ T.G.DELETE | translate }}
</button> </button>
} @else { } @else {
<!-- --> <!-- -->
@if (isConnectionWorks()) { @if (isConnectionWorks()) {
<div class="success-info"> <div class="success-info">
<mat-icon>check</mat-icon> <mat-icon>check</mat-icon>
</div> </div>
} @else { } @else {
<button <button
(click)="testConnection()" (click)="testConnection()"
mat-button mat-button
color="primary" color="primary"
type="button" type="button"
[disabled]="form.invalid" [disabled]="form.invalid"
> >
<mat-icon>online_prediction</mat-icon> <mat-icon>online_prediction</mat-icon>
Test Test
<!-- {{ T.G.DELETE|translate }}--> <!-- {{ T.G.DELETE|translate }}-->
</button> </button>
} }
<!-- --> <!-- -->
} }
<button <button
color="primary" color="primary"
@ -159,7 +172,7 @@
[disabled]="form.invalid" [disabled]="form.invalid"
> >
<mat-icon>save</mat-icon> <mat-icon>save</mat-icon>
{{ T.G.SAVE|translate }} {{ T.G.SAVE | translate }}
</button> </button>
</mat-dialog-actions> </mat-dialog-actions>
</form> </form>

View file

@ -1,36 +1,42 @@
@if (task?.issueType===JIRA_TYPE) { @if (task?.issueType === JIRA_TYPE) {
<jira-issue-content <jira-issue-content
[issue]="issueData()" [issue]="issueData()"
[task]="task" [task]="task"
></jira-issue-content> ></jira-issue-content>
} @if (task?.issueType===GITHUB_TYPE) { }
<github-issue-content @if (task?.issueType === GITHUB_TYPE) {
[issue]="issueData()" <github-issue-content
[task]="task" [issue]="issueData()"
></github-issue-content> [task]="task"
} @if (task?.issueType===REDMINE_TYPE) { ></github-issue-content>
<redmine-issue-content }
[issue]="issueData()" @if (task?.issueType === REDMINE_TYPE) {
[task]="task" <redmine-issue-content
></redmine-issue-content> [issue]="issueData()"
} @if (task?.issueType===GITLAB_TYPE) { [task]="task"
<gitlab-issue-content ></redmine-issue-content>
[issue]="issueData()" }
[task]="task" @if (task?.issueType === GITLAB_TYPE) {
></gitlab-issue-content> <gitlab-issue-content
} @if (task?.issueType===CALDAV_TYPE) { [issue]="issueData()"
<caldav-issue-content [task]="task"
[issue]="issueData()" ></gitlab-issue-content>
[task]="task" }
></caldav-issue-content> @if (task?.issueType === CALDAV_TYPE) {
} @if (task?.issueType===OPEN_PROJECT_TYPE) { <caldav-issue-content
<open-project-issue-content [issue]="issueData()"
[issue]="issueData()" [task]="task"
[task]="task" ></caldav-issue-content>
></open-project-issue-content> }
} @if (task?.issueType===GITEA_TYPE) { @if (task?.issueType === OPEN_PROJECT_TYPE) {
<gitea-issue-content <open-project-issue-content
[issue]="issueData()" [issue]="issueData()"
[task]="task" [task]="task"
></gitea-issue-content> ></open-project-issue-content>
}
@if (task?.issueType === GITEA_TYPE) {
<gitea-issue-content
[issue]="issueData()"
[task]="task"
></gitea-issue-content>
} }

View file

@ -1,15 +1,21 @@
@if (task?.issueType === JIRA_TYPE) { @if (task?.issueType === JIRA_TYPE) {
<jira-issue-header [task]="task"></jira-issue-header> <jira-issue-header [task]="task"></jira-issue-header>
} @if (task?.issueType === GITHUB_TYPE) { }
<github-issue-header [task]="task"></github-issue-header> @if (task?.issueType === GITHUB_TYPE) {
} @if (task?.issueType === REDMINE_TYPE) { <github-issue-header [task]="task"></github-issue-header>
<redmine-issue-header [task]="task"></redmine-issue-header> }
} @if (task?.issueType === GITLAB_TYPE) { @if (task?.issueType === REDMINE_TYPE) {
<gitlab-issue-header [task]="task"></gitlab-issue-header> <redmine-issue-header [task]="task"></redmine-issue-header>
} @if (task?.issueType === CALDAV_TYPE) { }
<caldav-issue-header [task]="task"></caldav-issue-header> @if (task?.issueType === GITLAB_TYPE) {
} @if (task?.issueType === OPEN_PROJECT_TYPE) { <gitlab-issue-header [task]="task"></gitlab-issue-header>
<open-project-issue-header [task]="task"></open-project-issue-header> }
} @if (task?.issueType === GITEA_TYPE) { @if (task?.issueType === CALDAV_TYPE) {
<gitea-issue-header [task]="task"></gitea-issue-header> <caldav-issue-header [task]="task"></caldav-issue-header>
}
@if (task?.issueType === OPEN_PROJECT_TYPE) {
<open-project-issue-header [task]="task"></open-project-issue-header>
}
@if (task?.issueType === GITEA_TYPE) {
<gitea-issue-header [task]="task"></gitea-issue-header>
} }

View file

@ -1,51 +1,54 @@
<ng-container> <ng-container>
@if (task()?.issueWasUpdated) { @if (task()?.issueWasUpdated) {
<div <div
@expand @expand
style="text-align: center" style="text-align: center"
>
<button
(click)="hideUpdates()"
color="accent"
mat-raised-button
> >
{{T.F.CALDAV.ISSUE_CONTENT.MARK_AS_CHECKED|translate}} <button
</button> (click)="hideUpdates()"
</div> color="accent"
mat-raised-button
>
{{ T.F.CALDAV.ISSUE_CONTENT.MARK_AS_CHECKED | translate }}
</button>
</div>
} }
<div class="table-wrapper"> <div class="table-wrapper">
<table class="issue-table"> <table class="issue-table">
<tr> <tr>
<th>{{T.F.CALDAV.ISSUE_CONTENT.SUMMARY|translate}}</th> <th>{{ T.F.CALDAV.ISSUE_CONTENT.SUMMARY | translate }}</th>
<td><strong>{{issue?.summary}}</strong></td> <td>
<strong>{{ issue?.summary }}</strong>
</td>
</tr> </tr>
<tr> <tr>
<th>{{T.F.CALDAV.ISSUE_CONTENT.STATUS|translate}}</th> <th>{{ T.F.CALDAV.ISSUE_CONTENT.STATUS | translate }}</th>
<td>{{issue?.completed}}</td> <td>{{ issue?.completed }}</td>
</tr> </tr>
@if (issue?.labels?.length) { @if (issue?.labels?.length) {
<tr> <tr>
<th>{{T.F.CALDAV.ISSUE_CONTENT.LABELS|translate}}</th> <th>{{ T.F.CALDAV.ISSUE_CONTENT.LABELS | translate }}</th>
<td> <td>
<mat-chip-listbox> <mat-chip-listbox>
@for (label of issue?.labels; track label) { @for (label of issue?.labels; track label) {
<mat-chip-option [title]="label">{{label}} </mat-chip-option> <mat-chip-option [title]="label">{{ label }} </mat-chip-option>
} }
</mat-chip-listbox> </mat-chip-listbox>
</td> </td>
</tr> </tr>
} @if (issue?.note) { }
<tr> @if (issue?.note) {
<th>{{T.F.CALDAV.ISSUE_CONTENT.DESCRIPTION|translate}}</th> <tr>
<td class="issue-description"> <th>{{ T.F.CALDAV.ISSUE_CONTENT.DESCRIPTION | translate }}</th>
<div <td class="issue-description">
[data]="issue?.note" <div
class="description markdown" [data]="issue?.note"
markdown class="description markdown"
></div> markdown
</td> ></div>
</tr> </td>
</tr>
} }
</table> </table>
</div> </div>

View file

@ -1,14 +1,15 @@
@if (task()?.issueWasUpdated) { @if (task()?.issueWasUpdated) {
<mat-icon <mat-icon
color="accent" color="accent"
style="margin-right: 8px" style="margin-right: 8px"
>update >update
</mat-icon> </mat-icon>
} @if (!task()?.issueWasUpdated) { }
<mat-icon @if (!task()?.issueWasUpdated) {
style="margin-right: 8px" <mat-icon
svgIcon="caldav" style="margin-right: 8px"
> svgIcon="caldav"
</mat-icon> >
</mat-icon>
} }
<span class="tab-label-text">Caldav</span> <span class="tab-label-text">Caldav</span>

View file

@ -1,72 +1,74 @@
<ng-container> <ng-container>
@if (task()?.issueWasUpdated) { @if (task()?.issueWasUpdated) {
<div <div
@expand @expand
style="text-align: center" style="text-align: center"
>
<button
(click)="hideUpdates()"
color="accent"
mat-raised-button
> >
{{T.F.GITEA.ISSUE_CONTENT.MARK_AS_CHECKED|translate}} <button
</button> (click)="hideUpdates()"
</div> color="accent"
mat-raised-button
>
{{ T.F.GITEA.ISSUE_CONTENT.MARK_AS_CHECKED | translate }}
</button>
</div>
} }
<div class="table-wrapper"> <div class="table-wrapper">
<table class="issue-table"> <table class="issue-table">
<tr> <tr>
<th>{{T.F.GITEA.ISSUE_CONTENT.SUMMARY|translate}}</th> <th>{{ T.F.GITEA.ISSUE_CONTENT.SUMMARY | translate }}</th>
<td> <td>
<a <a
[href]="issue?.html_url" [href]="issue?.html_url"
target="_blank" target="_blank"
><strong>{{issue?.title}} #{{issue?.number}}</strong></a ><strong>{{ issue?.title }} #{{ issue?.number }}</strong></a
> >
</td> </td>
</tr> </tr>
<tr> <tr>
<th>{{T.F.GITEA.ISSUE_CONTENT.PROJECT|translate}}</th> <th>{{ T.F.GITEA.ISSUE_CONTENT.PROJECT | translate }}</th>
<td>{{issue?.repository.name}}</td> <td>{{ issue?.repository.name }}</td>
</tr> </tr>
<tr> <tr>
<th>{{T.F.GITEA.ISSUE_CONTENT.STATUS|translate}}</th> <th>{{ T.F.GITEA.ISSUE_CONTENT.STATUS | translate }}</th>
<td>{{issue?.state}}</td> <td>{{ issue?.state }}</td>
</tr> </tr>
@if (issue?.assignee?.web_url) { @if (issue?.assignee?.web_url) {
<tr> <tr>
<th>{{T.F.GITEA.ISSUE_CONTENT.ASSIGNEE|translate}}</th> <th>{{ T.F.GITEA.ISSUE_CONTENT.ASSIGNEE | translate }}</th>
<td> <td>
<a <a
[href]="issue?.assignee?.web_url" [href]="issue?.assignee?.web_url"
target="_blank" target="_blank"
>{{issue?.assignee?.username}}</a >{{ issue?.assignee?.username }}</a
> >
</td> </td>
</tr> </tr>
} @if (issue?.labels?.length) { }
<tr> @if (issue?.labels?.length) {
<th>{{T.F.GITEA.ISSUE_CONTENT.LABELS|translate}}</th> <tr>
<td> <th>{{ T.F.GITEA.ISSUE_CONTENT.LABELS | translate }}</th>
<mat-chip-listbox> <td>
@for (label of issue?.labels; track label) { <mat-chip-listbox>
<mat-chip-option [title]="label.name">{{label.name}} </mat-chip-option> @for (label of issue?.labels; track label) {
} <mat-chip-option [title]="label.name">{{ label.name }} </mat-chip-option>
</mat-chip-listbox> }
</td> </mat-chip-listbox>
</tr> </td>
} @if (issue?.body) { </tr>
<tr> }
<th>{{T.F.GITEA.ISSUE_CONTENT.DESCRIPTION|translate}}</th> @if (issue?.body) {
<td class="issue-description"> <tr>
<div <th>{{ T.F.GITEA.ISSUE_CONTENT.DESCRIPTION | translate }}</th>
[data]="issue?.body" <td class="issue-description">
class="description markdown" <div
markdown [data]="issue?.body"
></div> class="description markdown"
</td> markdown
</tr> ></div>
</td>
</tr>
} }
</table> </table>
<div style="text-align: center"> <div style="text-align: center">
@ -78,7 +80,7 @@
target="_blank" target="_blank"
> >
<mat-icon>textsms</mat-icon> <mat-icon>textsms</mat-icon>
{{T.F.GITEA.ISSUE_CONTENT.WRITE_A_COMMENT|translate}} {{ T.F.GITEA.ISSUE_CONTENT.WRITE_A_COMMENT | translate }}
</a> </a>
</div> </div>
</div> </div>

View file

@ -1,14 +1,15 @@
@if (task()?.issueWasUpdated) { @if (task()?.issueWasUpdated) {
<mat-icon <mat-icon
color="accent" color="accent"
style="margin-right: 8px" style="margin-right: 8px"
>update >update
</mat-icon> </mat-icon>
} @if (!task()?.issueWasUpdated) { }
<mat-icon @if (!task()?.issueWasUpdated) {
style="margin-right: 8px" <mat-icon
svgIcon="gitea" style="margin-right: 8px"
> svgIcon="gitea"
</mat-icon> >
</mat-icon>
} }
<span class="tab-label-text">Gitea</span> <span class="tab-label-text">Gitea</span>

View file

@ -1,156 +1,172 @@
<ng-container> <ng-container>
@if (task()?.issueWasUpdated) { @if (task()?.issueWasUpdated) {
<div <div
@expand @expand
style="text-align: center" style="text-align: center"
>
<button
(click)="hideUpdates()"
color="accent"
mat-raised-button
> >
{{T.F.GITHUB.ISSUE_CONTENT.MARK_AS_CHECKED|translate}} <button
</button> (click)="hideUpdates()"
</div> color="accent"
mat-raised-button
>
{{ T.F.GITHUB.ISSUE_CONTENT.MARK_AS_CHECKED | translate }}
</button>
</div>
} }
<div class="table-wrapper"> <div class="table-wrapper">
<table class="issue-table"> <table class="issue-table">
<tr> <tr>
<th>{{T.F.GITHUB.ISSUE_CONTENT.SUMMARY|translate}}</th> <th>{{ T.F.GITHUB.ISSUE_CONTENT.SUMMARY | translate }}</th>
<td> <td>
<a <a
[href]="issue?.html_url" [href]="issue?.html_url"
target="_blank" target="_blank"
><strong>{{issue?.title}} #{{issue?.number}}</strong></a ><strong>{{ issue?.title }} #{{ issue?.number }}</strong></a
> >
</td> </td>
</tr> </tr>
<tr> <tr>
<th>{{T.F.GITHUB.ISSUE_CONTENT.STATUS|translate}}</th> <th>{{ T.F.GITHUB.ISSUE_CONTENT.STATUS | translate }}</th>
<td>{{issue?.state}}</td> <td>{{ issue?.state }}</td>
</tr> </tr>
@if (issue?.assignee?.html_url) { @if (issue?.assignee?.html_url) {
<tr> <tr>
<th>{{T.F.GITHUB.ISSUE_CONTENT.ASSIGNEE|translate}}</th> <th>{{ T.F.GITHUB.ISSUE_CONTENT.ASSIGNEE | translate }}</th>
<td> <td>
<a <a
[href]="issue?.assignee?.html_url" [href]="issue?.assignee?.html_url"
target="_blank" target="_blank"
>{{issue?.assignee?.login}}</a >{{ issue?.assignee?.login }}</a
> >
</td> </td>
</tr> </tr>
} @if (issue?.labels?.length) { }
<tr> @if (issue?.labels?.length) {
<th>{{T.F.GITHUB.ISSUE_CONTENT.LABELS|translate}}</th> <tr>
<td> <th>{{ T.F.GITHUB.ISSUE_CONTENT.LABELS | translate }}</th>
<mat-chip-listbox> <td>
@for (label of issue?.labels; track trackByIndex($index, label)) { <mat-chip-listbox>
<mat-chip-option [title]="label.description">{{label.name}} </mat-chip-option> @for (label of issue?.labels; track trackByIndex($index, label)) {
} <mat-chip-option [title]="label.description"
</mat-chip-listbox> >{{ label.name }}
</td> </mat-chip-option>
</tr> }
} @if (issue?.body && !isCollapsedIssueSummary()) { </mat-chip-listbox>
<tr> </td>
<th>{{T.F.GITHUB.ISSUE_CONTENT.DESCRIPTION|translate}}</th> </tr>
<td class="issue-description"> }
<div @if (issue?.body && !isCollapsedIssueSummary()) {
[data]="issue?.body" <tr>
class="description markdown" <th>{{ T.F.GITHUB.ISSUE_CONTENT.DESCRIPTION | translate }}</th>
markdown <td class="issue-description">
></div> <div
</td> [data]="issue?.body"
</tr> class="description markdown"
markdown
></div>
</td>
</tr>
} }
</table> </table>
@if (issue?.comments?.length) { @if (issue?.comments?.length) {
<div> <div>
@if (isCollapsedIssueComments()) { @if (isCollapsedIssueComments()) {
<div style="text-align: center"> <div style="text-align: center">
<button <button
mat-stroked-button mat-stroked-button
class="load-comments-and-all-data" class="load-comments-and-all-data"
(click)="isForceShowDescription=true; isForceShowAllComments= true" (click)="isForceShowDescription = true; isForceShowAllComments = true"
>
<mat-icon>download</mat-icon>
@if (isCollapsedIssueSummary()) {
<span style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap"
>{{T.F.GITHUB.ISSUE_CONTENT.LOAD_DESCRIPTION_AND_ALL_COMMENTS|translate}}</span
>
} @if (!isCollapsedIssueSummary()) {
{{T.F.GITHUB.ISSUE_CONTENT.LOAD_ALL_COMMENTS|translate:{ nr:
issue?.comments?.length } }} }
</button>
</div>
<h3 class="last-comment-headline">
{{T.F.GITHUB.ISSUE_CONTENT.LAST_COMMENT|translate}}
</h3>
<div class="comment isLastComment">
<!--<img [src]="comment.author.avatarUrl"-->
<!--class="author-avatar">-->
<div class="name-and-comment-content">
<div>
<span class="author-name">{{lastComment().user?.login}}</span>
<span class="when"
>{{T.F.GITHUB.ISSUE_CONTENT.AT|translate}}
{{lastComment().created_at|date:'short'}}</span
> >
<mat-icon>download</mat-icon>
@if (isCollapsedIssueSummary()) {
<span
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap"
>{{
T.F.GITHUB.ISSUE_CONTENT.LOAD_DESCRIPTION_AND_ALL_COMMENTS | translate
}}</span
>
}
@if (!isCollapsedIssueSummary()) {
{{
T.F.GITHUB.ISSUE_CONTENT.LOAD_ALL_COMMENTS
| translate: { nr: issue?.comments?.length }
}}
}
</button>
</div> </div>
@if (lastComment().body) { <h3 class="last-comment-headline">
<div {{ T.F.GITHUB.ISSUE_CONTENT.LAST_COMMENT | translate }}
[innerHTML]="lastComment().body|markdown|async" </h3>
class="markdown" <div class="comment isLastComment">
></div> <!--<img [src]="comment.author.avatarUrl"-->
} <!--class="author-avatar">-->
</div> <div class="name-and-comment-content">
</div> <div>
} @if (!isCollapsedIssueComments()) { @for (comment of <span class="author-name">{{ lastComment().user?.login }}</span>
(issue?.comments|sort:'created_at'); track trackByIndex($index, comment)) { <span class="when"
<div class="comment"> >{{ T.F.GITHUB.ISSUE_CONTENT.AT | translate }}
<!--<img [src]="comment.author.avatarUrl"--> {{ lastComment().created_at | date: 'short' }}</span
<!--class="author-avatar">--> >
<div class="name-and-comment-content"> </div>
<div> @if (lastComment().body) {
<span class="author-name">{{comment.user?.login}}</span> <div
<span class="when" [innerHTML]="lastComment().body | markdown | async"
>{{T.F.GITHUB.ISSUE_CONTENT.AT|translate}} class="markdown"
{{comment.created_at|date:'short'}}</span ></div>
> }
</div>
</div> </div>
@if (comment.body) { }
<div @if (!isCollapsedIssueComments()) {
[innerHTML]="comment?.body|markdown|async" @for (
class="markdown" comment of issue?.comments | sort: 'created_at';
></div> track trackByIndex($index, comment)
) {
<div class="comment">
<!--<img [src]="comment.author.avatarUrl"-->
<!--class="author-avatar">-->
<div class="name-and-comment-content">
<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>
@if (comment.body) {
<div
[innerHTML]="comment?.body | markdown | async"
class="markdown"
></div>
}
</div>
</div>
} }
</div> }
<!-- <div-->
<!-- *ngFor="let comment of (issue?.comments|sort:'created_at'); trackBy: trackByIndex"-->
<!-- class="comment"-->
<!-- >-->
<!-- &lt;!&ndash;<img [src]="comment.author.avatarUrl"&ndash;&gt;-->
<!-- &lt;!&ndash;class="author-avatar">&ndash;&gt;-->
<!-- <div class="name-and-comment-content">-->
<!-- <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-->
<!-- *ngIf="comment.body"-->
<!-- [innerHTML]="comment?.body|markdown"-->
<!-- class="markdown"-->
<!-- ></div>-->
<!-- </div>-->
<!-- </div>-->
</div> </div>
} }
<!-- <div-->
<!-- *ngFor="let comment of (issue?.comments|sort:'created_at'); trackBy: trackByIndex"-->
<!-- class="comment"-->
<!-- >-->
<!-- &lt;!&ndash;<img [src]="comment.author.avatarUrl"&ndash;&gt;-->
<!-- &lt;!&ndash;class="author-avatar">&ndash;&gt;-->
<!-- <div class="name-and-comment-content">-->
<!-- <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-->
<!-- *ngIf="comment.body"-->
<!-- [innerHTML]="comment?.body|markdown"-->
<!-- class="markdown"-->
<!-- ></div>-->
<!-- </div>-->
<!-- </div>-->
</div>
} }
<div style="text-align: center"> <div style="text-align: center">
@ -162,7 +178,7 @@
target="_blank" target="_blank"
> >
<mat-icon>textsms</mat-icon> <mat-icon>textsms</mat-icon>
{{T.F.GITHUB.ISSUE_CONTENT.WRITE_A_COMMENT|translate}} {{ T.F.GITHUB.ISSUE_CONTENT.WRITE_A_COMMENT | translate }}
</a> </a>
</div> </div>
<!--<pre><code>--> <!--<pre><code>-->

View file

@ -1,14 +1,15 @@
@if (task()?.issueWasUpdated) { @if (task()?.issueWasUpdated) {
<mat-icon <mat-icon
color="accent" color="accent"
style="margin-right: 8px" style="margin-right: 8px"
>update >update
</mat-icon> </mat-icon>
} @if (!task()?.issueWasUpdated) { }
<mat-icon @if (!task()?.issueWasUpdated) {
style="margin-right: 8px" <mat-icon
svgIcon="github" style="margin-right: 8px"
> svgIcon="github"
</mat-icon> >
</mat-icon>
} }
<span class="tab-label-text">Github</span> <span class="tab-label-text">Github</span>

View file

@ -3,26 +3,28 @@
class="dialog-header-icon" class="dialog-header-icon"
svgIcon="gitlab" svgIcon="gitlab"
></mat-icon> ></mat-icon>
<span>{{ T.F.GITLAB.DIALOG_SUBMIT_WORKLOG.TITLE|translate }}</span> <span>{{ T.F.GITLAB.DIALOG_SUBMIT_WORKLOG.TITLE | translate }}</span>
</h1> </h1>
<mat-dialog-content> <mat-dialog-content>
@if (isLoading) { @if (isLoading) {
<div class="loading-wrapper"> <div class="loading-wrapper">
<mat-progress-spinner <mat-progress-spinner
class="example-margin" class="example-margin"
[color]="'primary'" [color]="'primary'"
[mode]="'indeterminate'" [mode]="'indeterminate'"
> >
</mat-progress-spinner> </mat-progress-spinner>
</div> </div>
} }
<h3>For gitlab project: <strong>{{ (issueProviderCfg$|async)?.project }}</strong></h3> <h3>
For gitlab project: <strong>{{ (issueProviderCfg$ | async)?.project }}</strong>
</h3>
<div class="table-wrapper"> <div class="table-wrapper">
<table <table
[dataSource]="tmpTasks$|async" [dataSource]="tmpTasks$ | async"
class="summary-table" class="summary-table"
mat-table mat-table
> >
@ -31,7 +33,7 @@
*matHeaderCellDef *matHeaderCellDef
mat-header-cell mat-header-cell
> >
{{ T.F.GITLAB.DIALOG_SUBMIT_WORKLOG.T_TITLE|translate }} Title {{ T.F.GITLAB.DIALOG_SUBMIT_WORKLOG.T_TITLE | translate }} Title
</th> </th>
<td <td
*matCellDef="let tmpTask" *matCellDef="let tmpTask"
@ -46,13 +48,13 @@
*matHeaderCellDef *matHeaderCellDef
mat-header-cell mat-header-cell
> >
{{ T.F.GITLAB.DIALOG_SUBMIT_WORKLOG.T_ALREADY_TRACKED|translate }} {{ T.F.GITLAB.DIALOG_SUBMIT_WORKLOG.T_ALREADY_TRACKED | translate }}
</th> </th>
<td <td
*matCellDef="let tmpTask" *matCellDef="let tmpTask"
mat-cell mat-cell
> >
{{ tmpTask.timeTrackedAlreadyRemote|msToClockString }} {{ tmpTask.timeTrackedAlreadyRemote | msToClockString }}
</td> </td>
</ng-container> </ng-container>
@ -61,22 +63,22 @@
*matHeaderCellDef *matHeaderCellDef
mat-header-cell mat-header-cell
> >
{{ T.F.GITLAB.DIALOG_SUBMIT_WORKLOG.T_TO_BE_SUBMITTED|translate }} {{ T.F.GITLAB.DIALOG_SUBMIT_WORKLOG.T_TO_BE_SUBMITTED | translate }}
</th> </th>
<td <td
*matCellDef="let tmpTask" *matCellDef="let tmpTask"
mat-cell mat-cell
> >
@if (tmpTask.isPastTrackedData) { @if (tmpTask.isPastTrackedData) {
<span <span
class="past-info-ico" class="past-info-ico"
[matTooltip]="T.F.GITLAB.DIALOG_SUBMIT_WORKLOG.PAST_DAY_INFO|translate" [matTooltip]="T.F.GITLAB.DIALOG_SUBMIT_WORKLOG.PAST_DAY_INFO | translate"
>!!!</span >!!!</span
> >
} }
<inline-input <inline-input
(changed)="updateTimeSpentTodayForTask(tmpTask, $event)" (changed)="updateTimeSpentTodayForTask(tmpTask, $event)"
[displayValue]="tmpTask.timeToSubmit|msToClockString" [displayValue]="tmpTask.timeToSubmit | msToClockString"
[type]="'duration'" [type]="'duration'"
[value]="tmpTask.timeToSubmit" [value]="tmpTask.timeToSubmit"
> >
@ -85,11 +87,14 @@
</ng-container> </ng-container>
<tr <tr
*matHeaderRowDef="['title', 'timeTrackedAlreadyRemote','timeToSubmit']" *matHeaderRowDef="['title', 'timeTrackedAlreadyRemote', 'timeToSubmit']"
mat-header-row mat-header-row
></tr> ></tr>
<tr <tr
*matRowDef="let row; columns: ['title','timeTrackedAlreadyRemote','timeToSubmit']" *matRowDef="
let row;
columns: ['title', 'timeTrackedAlreadyRemote', 'timeToSubmit']
"
mat-row mat-row
></tr> ></tr>
</table> </table>
@ -97,8 +102,14 @@
<div <div
class="total-msg" class="total-msg"
[innerHTML]="T.F.GITLAB.DIALOG_SUBMIT_WORKLOG.TOTAL_MSG|translate:{totalTimeToSubmit: totalTimeToSubmit$|async|msToString, [innerHTML]="
nrOfTasksToSubmit: (tmpTasksToTrack$|async)?.length}" T.F.GITLAB.DIALOG_SUBMIT_WORKLOG.TOTAL_MSG
| translate
: {
totalTimeToSubmit: totalTimeToSubmit$ | async | msToString,
nrOfTasksToSubmit: (tmpTasksToTrack$ | async)?.length,
}
"
></div> ></div>
</mat-dialog-content> </mat-dialog-content>
@ -109,7 +120,7 @@
mat-button mat-button
type="button" type="button"
> >
{{ T.G.CANCEL|translate }} {{ T.G.CANCEL | translate }}
</button> </button>
<button <button
@ -122,6 +133,6 @@
class="dialog-header-icon" class="dialog-header-icon"
svgIcon="gitlab" svgIcon="gitlab"
></mat-icon> ></mat-icon>
{{ T.G.SUBMIT|translate }} {{ T.G.SUBMIT | translate }}
</button> </button>
</mat-dialog-actions> </mat-dialog-actions>

View file

@ -1,28 +1,28 @@
<ng-container> <ng-container>
@if (task()?.issueWasUpdated) { @if (task()?.issueWasUpdated) {
<div <div
@expand @expand
style="text-align: center" style="text-align: center"
>
<button
(click)="hideUpdates()"
color="accent"
mat-raised-button
> >
{{T.F.GITLAB.ISSUE_CONTENT.MARK_AS_CHECKED|translate}} <button
</button> (click)="hideUpdates()"
</div> color="accent"
mat-raised-button
>
{{ T.F.GITLAB.ISSUE_CONTENT.MARK_AS_CHECKED | translate }}
</button>
</div>
} }
<div class="table-wrapper"> <div class="table-wrapper">
<table class="issue-table"> <table class="issue-table">
<tr> <tr>
<th>{{T.F.GITLAB.ISSUE_CONTENT.SUMMARY|translate}}</th> <th>{{ T.F.GITLAB.ISSUE_CONTENT.SUMMARY | translate }}</th>
<td> <td>
<a <a
[href]="issue?.html_url" [href]="issue?.html_url"
target="_blank" target="_blank"
><strong>{{issue?.title}} #{{issue?.number}}</strong></a ><strong>{{ issue?.title }} #{{ issue?.number }}</strong></a
> >
</td> </td>
</tr> </tr>
@ -31,68 +31,72 @@
<!-- <td>{{issue?.project}}</td>--> <!-- <td>{{issue?.project}}</td>-->
<!-- </tr>--> <!-- </tr>-->
<tr> <tr>
<th>{{T.F.GITLAB.ISSUE_CONTENT.STATUS|translate}}</th> <th>{{ T.F.GITLAB.ISSUE_CONTENT.STATUS | translate }}</th>
<td>{{issue?.state}}</td> <td>{{ issue?.state }}</td>
</tr> </tr>
@if (issue?.assignee?.web_url) { @if (issue?.assignee?.web_url) {
<tr> <tr>
<th>{{T.F.GITLAB.ISSUE_CONTENT.ASSIGNEE|translate}}</th> <th>{{ T.F.GITLAB.ISSUE_CONTENT.ASSIGNEE | translate }}</th>
<td> <td>
<a <a
[href]="issue?.assignee?.web_url" [href]="issue?.assignee?.web_url"
target="_blank" target="_blank"
>{{issue?.assignee?.username}}</a >{{ issue?.assignee?.username }}</a
> >
</td> </td>
</tr> </tr>
} @if (issue?.labels?.length) { }
<tr> @if (issue?.labels?.length) {
<th>{{T.F.GITLAB.ISSUE_CONTENT.LABELS|translate}}</th> <tr>
<td> <th>{{ T.F.GITLAB.ISSUE_CONTENT.LABELS | translate }}</th>
<mat-chip-listbox> <td>
@for (label of issue?.labels; track label) { <mat-chip-listbox>
<mat-chip-option [title]="label">{{label}} </mat-chip-option> @for (label of issue?.labels; track label) {
} <mat-chip-option [title]="label">{{ label }} </mat-chip-option>
</mat-chip-listbox> }
</td> </mat-chip-listbox>
</tr> </td>
} @if (issue?.body) { </tr>
<tr> }
<th>{{T.F.GITLAB.ISSUE_CONTENT.DESCRIPTION|translate}}</th> @if (issue?.body) {
<td class="issue-description"> <tr>
<div <th>{{ T.F.GITLAB.ISSUE_CONTENT.DESCRIPTION | translate }}</th>
[data]="issue?.body" <td class="issue-description">
class="description markdown" <div
markdown [data]="issue?.body"
></div> class="description markdown"
</td> markdown
</tr> ></div>
</td>
</tr>
} }
</table> </table>
@if (issue?.comments) { @if (issue?.comments) {
<div> <div>
@for (comment of (issue?.comments|sort:'created_at'); track trackByIndex($index, @for (
comment)) { comment of issue?.comments | sort: 'created_at';
<div class="comment"> track trackByIndex($index, comment)
<div class="name-and-comment-content"> ) {
<div> <div class="comment">
<span class="author-name">{{comment.author?.username}}</span> <div class="name-and-comment-content">
<span class="when" <div>
>{{T.F.GITLAB.ISSUE_CONTENT.AT|translate}} <span class="author-name">{{ comment.author?.username }}</span>
{{comment.created_at|date:'short'}}</span <span class="when"
> >{{ T.F.GITLAB.ISSUE_CONTENT.AT | translate }}
{{ comment.created_at | date: 'short' }}</span
>
</div>
@if (comment.body) {
<div
[innerHTML]="comment?.body | markdown | async"
class="markdown"
></div>
}
</div>
</div> </div>
@if (comment.body) { }
<div
[innerHTML]="comment?.body|markdown|async"
class="markdown"
></div>
}
</div>
</div> </div>
}
</div>
} }
<div style="text-align: center"> <div style="text-align: center">
@ -104,7 +108,7 @@
target="_blank" target="_blank"
> >
<mat-icon>textsms</mat-icon> <mat-icon>textsms</mat-icon>
{{T.F.GITLAB.ISSUE_CONTENT.WRITE_A_COMMENT|translate}} {{ T.F.GITLAB.ISSUE_CONTENT.WRITE_A_COMMENT | translate }}
</a> </a>
</div> </div>
</div> </div>

View file

@ -1,14 +1,15 @@
@if (task()?.issueWasUpdated) { @if (task()?.issueWasUpdated) {
<mat-icon <mat-icon
color="accent" color="accent"
style="margin-right: 8px" style="margin-right: 8px"
>update >update
</mat-icon> </mat-icon>
} @if (!task()?.issueWasUpdated) { }
<mat-icon @if (!task()?.issueWasUpdated) {
style="margin-right: 8px" <mat-icon
svgIcon="gitlab" style="margin-right: 8px"
> svgIcon="gitlab"
</mat-icon> >
</mat-icon>
} }
<span class="tab-label-text">Gitlab</span> <span class="tab-label-text">Gitlab</span>

View file

@ -1,134 +1,140 @@
<div class="wrapper"> <div class="wrapper">
@if (task?.issueWasUpdated) { @if (task?.issueWasUpdated) {
<div <div
[@expand] [@expand]
class="updates" class="updates"
> >
<div> <div>
<button <button
(click)="hideUpdates()" (click)="hideUpdates()"
color="accent" color="accent"
mat-raised-button mat-raised-button
> >
{{T.F.JIRA.ISSUE_CONTENT.MARK_AS_CHECKED|translate}} {{ T.F.JIRA.ISSUE_CONTENT.MARK_AS_CHECKED | translate }}
</button> </button>
</div>
<h3 class="mat-h3">{{ T.F.JIRA.ISSUE_CONTENT.LIST_OF_CHANGES | translate }}</h3>
<ul class="changelog">
@for (entry of issue?.changelog; track entry) {
<li>
@if (entry.author) {
<em>{{ entry.author.displayName }}</em>
}
{{ T.F.JIRA.ISSUE_CONTENT.CHANGED | translate }}
<strong>{{ entry.field }}</strong>
{{ T.F.JIRA.ISSUE_CONTENT.ON | translate }}
{{ entry.created | date: 'short' }}
</li>
}
</ul>
</div> </div>
<h3 class="mat-h3">{{T.F.JIRA.ISSUE_CONTENT.LIST_OF_CHANGES|translate}}</h3>
<ul class="changelog">
@for (entry of issue?.changelog; track entry) {
<li>
@if (entry.author) {
<em>{{entry.author.displayName}}</em>
} {{T.F.JIRA.ISSUE_CONTENT.CHANGED|translate}}
<strong>{{entry.field}}</strong>
{{T.F.JIRA.ISSUE_CONTENT.ON|translate}} {{entry.created|date:'short'}}
</li>
}
</ul>
</div>
} }
<table class="issue-table"> <table class="issue-table">
<tr> <tr>
<th>{{T.F.JIRA.ISSUE_CONTENT.SUMMARY|translate}}</th> <th>{{ T.F.JIRA.ISSUE_CONTENT.SUMMARY | translate }}</th>
<td class="summary"> <td class="summary">
<strong <strong
><a ><a
[href]="issueUrl$|async" [href]="issueUrl$ | async"
target="_blank" target="_blank"
>{{issue?.key}} {{issue?.summary}}</a >{{ issue?.key }} {{ issue?.summary }}</a
></strong ></strong
> >
</td> </td>
</tr> </tr>
<tr> <tr>
<th>{{T.F.JIRA.ISSUE_CONTENT.STATUS|translate}}</th> <th>{{ T.F.JIRA.ISSUE_CONTENT.STATUS | translate }}</th>
<td> <td>
<!--<img [src]="issue?.status?.iconUrl"--> <!--<img [src]="issue?.status?.iconUrl"-->
<!--*ngIf="issue?.status?.iconUrl">--> <!--*ngIf="issue?.status?.iconUrl">-->
{{issue?.status?.name}} {{ issue?.status?.name }}
</td> </td>
</tr> </tr>
@if (issue?.storyPoints) { @if (issue?.storyPoints) {
<tr> <tr>
<th>{{T.F.JIRA.ISSUE_CONTENT.STORY_POINTS|translate}}</th> <th>{{ T.F.JIRA.ISSUE_CONTENT.STORY_POINTS | translate }}</th>
<td>{{issue?.storyPoints}}</td> <td>{{ issue?.storyPoints }}</td>
</tr> </tr>
} }
<tr> <tr>
<th>{{T.F.JIRA.ISSUE_CONTENT.ASSIGNEE|translate}}</th> <th>{{ T.F.JIRA.ISSUE_CONTENT.ASSIGNEE | translate }}</th>
<td>{{issue?.assignee?.displayName || ''}}</td> <td>{{ issue?.assignee?.displayName || '' }}</td>
</tr> </tr>
@if (issue?.timespent || issue?.timeestimate) { @if (issue?.timespent || issue?.timeestimate) {
<tr> <tr>
<th>{{T.F.JIRA.ISSUE_CONTENT.WORKLOG|translate}}</th> <th>{{ T.F.JIRA.ISSUE_CONTENT.WORKLOG | translate }}</th>
<td> <td>
{{(issue?.timespent * 1000)|msToString}} / {{(issue?.timeestimate * {{ issue?.timespent * 1000 | msToString }} /
1000)|msToString}} {{ issue?.timeestimate * 1000 | msToString }}
</td> </td>
</tr> </tr>
} @if ((jiraSubTasks$|async); as jiraSubTasks) { }
<tr> @if (jiraSubTasks$ | async; as jiraSubTasks) {
<th>{{T.F.JIRA.ISSUE_CONTENT.SUB_TASKS|translate}}</th> <tr>
<td> <th>{{ T.F.JIRA.ISSUE_CONTENT.SUB_TASKS | translate }}</th>
<ul class="subtask-list"> <td>
@for (st of jiraSubTasks; track st) { <ul class="subtask-list">
<li> @for (st of jiraSubTasks; track st) {
<a <li>
target="_blank" <a
[href]="st.href" target="_blank"
> [href]="st.href"
{{st.key}} {{st.summary}}</a >
> {{ st.key }} {{ st.summary }}</a
</li> >
</li>
}
</ul>
</td>
</tr>
}
@if (jiraRelatedIssues$ | async; as relatedIssues) {
<tr>
<th>{{ T.F.JIRA.ISSUE_CONTENT.RELATED | translate }}</th>
<td>
<ul class="related-issue-list">
@for (ri of relatedIssues; track ri.id) {
<li>
<i>{{ ri.relatedHow }} => </i>
<a
target="_blank"
[href]="ri['href']"
>{{ ri.key }} {{ ri.summary }}</a
>
</li>
}
</ul>
</td>
</tr>
}
@if (issue?.components?.length) {
<tr>
<th>{{ T.F.JIRA.ISSUE_CONTENT.COMPONENTS | translate }}</th>
<td>
<mat-chip-listbox>
@for (component of issue?.components; track trackByIndex($index, component)) {
<mat-chip-option [title]="component.description"
>{{ component.name }}
</mat-chip-option>
}
</mat-chip-listbox>
</td>
</tr>
}
@if (issue?.description) {
<tr class="description-row">
<th>{{ T.F.JIRA.ISSUE_CONTENT.DESCRIPTION | translate }}</th>
<td>
@if (description) {
<div
[data]="description"
class="issue-description markdown"
markdown
></div>
} }
</ul> </td>
</td> </tr>
</tr>
} @if ((jiraRelatedIssues$|async); as relatedIssues) {
<tr>
<th>{{T.F.JIRA.ISSUE_CONTENT.RELATED|translate}}</th>
<td>
<ul class="related-issue-list">
@for (ri of relatedIssues; track ri.id) {
<li>
<i>{{ri.relatedHow}} => </i>
<a
target="_blank"
[href]="ri['href']"
>{{ri.key}} {{ri.summary}}</a
>
</li>
}
</ul>
</td>
</tr>
} @if (issue?.components?.length) {
<tr>
<th>{{T.F.JIRA.ISSUE_CONTENT.COMPONENTS|translate}}</th>
<td>
<mat-chip-listbox>
@for (component of issue?.components; track trackByIndex($index, component)) {
<mat-chip-option [title]="component.description"
>{{component.name}}
</mat-chip-option>
}
</mat-chip-listbox>
</td>
</tr>
} @if (issue?.description) {
<tr class="description-row">
<th>{{T.F.JIRA.ISSUE_CONTENT.DESCRIPTION|translate}}</th>
<td>
@if (description) {
<div
[data]="description"
class="issue-description markdown"
markdown
></div>
}
</td>
</tr>
} }
<!-- <tr *ngIf="attachments?.length">--> <!-- <tr *ngIf="attachments?.length">-->
<!-- <th>{{T.F.JIRA.ISSUE_CONTENT.ATTACHMENTS|translate}}</th>--> <!-- <th>{{T.F.JIRA.ISSUE_CONTENT.ATTACHMENTS|translate}}</th>-->
@ -141,43 +147,45 @@
<!-- </td>--> <!-- </td>-->
<!-- </tr>--> <!-- </tr>-->
@if (issue?.comments) { @if (issue?.comments) {
<tr> <tr>
<th>{{T.F.JIRA.ISSUE_CONTENT.COMMENTS|translate}}</th> <th>{{ T.F.JIRA.ISSUE_CONTENT.COMMENTS | translate }}</th>
<td> <td>
@for (comment of (issue?.comments|sort:'created'); track trackByIndex($index, @for (
comment)) { comment of issue?.comments | sort: 'created';
<div class="comment"> track trackByIndex($index, comment)
<img ) {
[src]="comment.author.avatarUrl" <div class="comment">
class="author-avatar" <img
/> [src]="comment.author.avatarUrl"
<div class="name-and-comment-content"> class="author-avatar"
<div> />
<span class="author-name">{{comment.author.displayName}}</span> <div class="name-and-comment-content">
<span class="when" <div>
>{{T.F.JIRA.ISSUE_CONTENT.AT|translate}} <span class="author-name">{{ comment.author.displayName }}</span>
{{comment.created|date:'short'}}</span <span class="when"
> >{{ T.F.JIRA.ISSUE_CONTENT.AT | translate }}
{{ comment.created | date: 'short' }}</span
>
</div>
@if (comment.body) {
<div
[innerHTML]="comment.body | jiraToMarkdown | markdown | async"
class="markdown"
></div>
}
</div>
</div> </div>
@if (comment.body) { }
<div <a
[innerHTML]="comment.body|jiraToMarkdown|markdown|async" [href]="issueUrl$ | async"
class="markdown" mat-stroked-button
></div> target="_blank"
} >
</div> <mat-icon>textsms</mat-icon>
</div> {{ T.F.JIRA.ISSUE_CONTENT.WRITE_A_COMMENT | translate }}</a
} >
<a </td>
[href]="issueUrl$|async" </tr>
mat-stroked-button
target="_blank"
>
<mat-icon>textsms</mat-icon>
{{T.F.JIRA.ISSUE_CONTENT.WRITE_A_COMMENT|translate}}</a
>
</td>
</tr>
} }
</table> </table>
</div> </div>

View file

@ -1,20 +1,23 @@
@if ((isOnline$|async)) { @if (task()?.issueWasUpdated) { @if (isOnline$ | async) {
<mat-icon @if (task()?.issueWasUpdated) {
color="accent" <mat-icon
style="margin-right: 8px" color="accent"
>update style="margin-right: 8px"
</mat-icon> >update
} @if (!task()?.issueWasUpdated) { </mat-icon>
<mat-icon }
style="margin-right: 8px" @if (!task()?.issueWasUpdated) {
svgIcon="jira" <mat-icon
> style="margin-right: 8px"
</mat-icon> svgIcon="jira"
} } @else { >
<mat-icon </mat-icon>
[matTooltip]="'No internet!'" }
style="margin-right: 8px" } @else {
>cloud_off <mat-icon
</mat-icon> [matTooltip]="'No internet!'"
style="margin-right: 8px"
>cloud_off
</mat-icon>
} }
<span class="tab-label-text">Jira</span> <span class="tab-label-text">Jira</span>

View file

@ -1,5 +1,5 @@
<form <form
(submit)="$event.preventDefault();submitWorklog()" (submit)="$event.preventDefault(); submitWorklog()"
class="mat-body" class="mat-body"
name="time-estimate-form" name="time-estimate-form"
> >
@ -8,21 +8,22 @@
class="dialog-header-icon" class="dialog-header-icon"
svgIcon="jira" svgIcon="jira"
></mat-icon> ></mat-icon>
<span>{{T.F.JIRA.DIALOG_WORKLOG.TITLE|translate}}</span> <span>{{ T.F.JIRA.DIALOG_WORKLOG.TITLE | translate }}</span>
</h1> </h1>
<mat-dialog-content> <mat-dialog-content>
<p> <p>
{{T.F.JIRA.DIALOG_WORKLOG.SUBMIT_WORKLOG_FOR|translate}} {{ T.F.JIRA.DIALOG_WORKLOG.SUBMIT_WORKLOG_FOR | translate }}
<strong>{{issue.key}} {{issue.summary}}</strong>. <strong>{{ issue.key }} {{ issue.summary }}</strong
>.
</p> </p>
<p> <p>
{{T.F.JIRA.DIALOG_WORKLOG.CURRENTLY_LOGGED|translate}} {{ T.F.JIRA.DIALOG_WORKLOG.CURRENTLY_LOGGED | translate }}
<strong>{{(timeLogged)|msToString}}</strong> <strong>{{ timeLogged | msToString }}</strong>
</p> </p>
<div class="form-wrapper"> <div class="form-wrapper">
<mat-label>{{T.F.JIRA.DIALOG_WORKLOG.TIME_SPENT|translate}}</mat-label> <mat-label>{{ T.F.JIRA.DIALOG_WORKLOG.TIME_SPENT | translate }}</mat-label>
<mat-form-field> <mat-form-field>
<input <input
[(ngModel)]="timeSpent" [(ngModel)]="timeSpent"
@ -37,7 +38,7 @@
class="suffix-wrapper" class="suffix-wrapper"
matSuffix matSuffix
[matMenuTriggerFor]="contextMenu" [matMenuTriggerFor]="contextMenu"
[matTooltip]="T.F.JIRA.DIALOG_WORKLOG.TIME_SPENT_TOOLTIP|translate" [matTooltip]="T.F.JIRA.DIALOG_WORKLOG.TIME_SPENT_TOOLTIP | translate"
> >
<button <button
mat-icon-button mat-icon-button
@ -57,29 +58,31 @@
<mat-menu #contextMenu="matMenu"> <mat-menu #contextMenu="matMenu">
<ng-template matMenuContent> <ng-template matMenuContent>
@for (opt of defaultTimeOptions; track opt) { @for (opt of defaultTimeOptions; track opt) {
<button <button
mat-menu-item mat-menu-item
type="button" type="button"
(click)="fill(opt.value)" (click)="fill(opt.value)"
> >
{{opt.label|translate}} ({{(getTimeToLogForMode(opt.value)|msToString)}}) {{ opt.label | translate }} ({{
</button> getTimeToLogForMode(opt.value) | msToString
}})
</button>
} }
</ng-template> </ng-template>
</mat-menu> </mat-menu>
@if (defaultTimeCheckboxContent) { @if (defaultTimeCheckboxContent) {
<mat-checkbox <mat-checkbox
[@expandFade] [@expandFade]
[checked]="defaultTimeCheckboxContent.isChecked" [checked]="defaultTimeCheckboxContent.isChecked"
(change)="defaultTimeCheckboxContent.isChecked = $event.checked" (change)="defaultTimeCheckboxContent.isChecked = $event.checked"
style="margin-bottom: 20px" style="margin-bottom: 20px"
>{{defaultTimeCheckboxContent.label|translate}} >{{ defaultTimeCheckboxContent.label | translate }}
</mat-checkbox> </mat-checkbox>
} }
<mat-form-field> <mat-form-field>
<mat-label>{{T.F.JIRA.DIALOG_WORKLOG.STARTED|translate}}</mat-label> <mat-label>{{ T.F.JIRA.DIALOG_WORKLOG.STARTED | translate }}</mat-label>
<input <input
[(ngModel)]="started" [(ngModel)]="started"
matInput matInput
@ -87,7 +90,7 @@
required required
type="datetime-local" type="datetime-local"
/> />
<mat-error>{{T.F.JIRA.DIALOG_WORKLOG.INVALID_DATE|translate}}</mat-error> <mat-error>{{ T.F.JIRA.DIALOG_WORKLOG.INVALID_DATE | translate }}</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>Comment</mat-label> <mat-label>Comment</mat-label>
@ -112,7 +115,7 @@
mat-button mat-button
type="button" type="button"
> >
{{T.G.CANCEL|translate}} {{ T.G.CANCEL | translate }}
</button> </button>
<button <button
class="btn btn-primary submit-button" class="btn btn-primary submit-button"
@ -121,7 +124,7 @@
type="submit" type="submit"
> >
<mat-icon>save</mat-icon> <mat-icon>save</mat-icon>
{{T.F.JIRA.DIALOG_WORKLOG.SAVE_WORKLOG|translate}} {{ T.F.JIRA.DIALOG_WORKLOG.SAVE_WORKLOG | translate }}
</button> </button>
</div> </div>
</mat-dialog-actions> </mat-dialog-actions>

View file

@ -3,36 +3,38 @@
class="dialog-header-icon" class="dialog-header-icon"
svgIcon="jira" svgIcon="jira"
></mat-icon> ></mat-icon>
<span>{{T.F.JIRA.DIALOG_TRANSITION.TITLE|translate}}</span> <span>{{ T.F.JIRA.DIALOG_TRANSITION.TITLE | translate }}</span>
</h1> </h1>
<mat-dialog-content> <mat-dialog-content>
<table> <table>
<tr> <tr>
<th>{{T.F.JIRA.DIALOG_TRANSITION.TASK_NAME|translate}}</th> <th>{{ T.F.JIRA.DIALOG_TRANSITION.TASK_NAME | translate }}</th>
<td>{{data.task ? data.task?.title : ''}}</td> <td>{{ data.task ? data.task?.title : '' }}</td>
</tr> </tr>
<tr> <tr>
<th>{{T.F.JIRA.DIALOG_TRANSITION.CURRENT_STATUS|translate}}</th> <th>{{ T.F.JIRA.DIALOG_TRANSITION.CURRENT_STATUS | translate }}</th>
<td>{{data.issue?.status ? data.issue?.status?.name : ''}}</td> <td>{{ data.issue?.status ? data.issue?.status?.name : '' }}</td>
</tr> </tr>
<tr> <tr>
<th>{{T.F.JIRA.DIALOG_TRANSITION.CURRENT_ASSIGNEE|translate}}</th> <th>{{ T.F.JIRA.DIALOG_TRANSITION.CURRENT_ASSIGNEE | translate }}</th>
<td>{{data.issue?.assignee ? data.issue?.assignee?.displayName : ''}}</td> <td>{{ data.issue?.assignee ? data.issue?.assignee?.displayName : '' }}</td>
</tr> </tr>
</table> </table>
<mat-form-field> <mat-form-field>
<label>{{T.F.JIRA.DIALOG_TRANSITION.CHOOSE_STATUS|translate}}</label> <label>{{ T.F.JIRA.DIALOG_TRANSITION.CHOOSE_STATUS | translate }}</label>
<mat-select [(ngModel)]="chosenTransition"> <mat-select [(ngModel)]="chosenTransition">
<!--<mat-option value="DO_NOT">Don't transition</mat-option>--> <!--<mat-option value="DO_NOT">Don't transition</mat-option>-->
<!--<mat-option value="ALWAYS_ASK">Always open dialog</mat-option>--> <!--<mat-option value="ALWAYS_ASK">Always open dialog</mat-option>-->
@for (transition of (availableTransitions$|async); track trackByIndex($index, @for (
transition)) { transition of availableTransitions$ | async;
<mat-option [value]="transition"> track trackByIndex($index, transition)
<!--<img [src]="transition.to.iconUrl">--> ) {
{{transition.name}} <mat-option [value]="transition">
</mat-option> <!--<img [src]="transition.to.iconUrl">-->
{{ transition.name }}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@ -47,7 +49,7 @@
mat-button mat-button
type="button" type="button"
> >
{{T.G.CANCEL|translate}} {{ T.G.CANCEL | translate }}
</button> </button>
<button <button
(click)="transitionIssue()" (click)="transitionIssue()"
@ -55,7 +57,7 @@
color="primary" color="primary"
mat-stroked-button mat-stroked-button
> >
{{T.F.JIRA.DIALOG_TRANSITION.TITLE|translate}} {{ T.F.JIRA.DIALOG_TRANSITION.TITLE | translate }}
</button> </button>
</div> </div>
</mat-dialog-actions> </mat-dialog-actions>

View file

@ -1,84 +1,89 @@
<form [formGroup]="form"> <form [formGroup]="form">
<h3 class="sub-section-heading">{{ T.F.JIRA.CFG_CMP.TRANSITION|translate }}</h3> <h3 class="sub-section-heading">{{ T.F.JIRA.CFG_CMP.TRANSITION | translate }}</h3>
<mat-slide-toggle <mat-slide-toggle
[ngModel]="cfg.isTransitionIssuesEnabled" [ngModel]="cfg.isTransitionIssuesEnabled"
(ngModelChange)="partialModelChange({isTransitionIssuesEnabled: $event})" (ngModelChange)="partialModelChange({ isTransitionIssuesEnabled: $event })"
[ngModelOptions]="{standalone: true}" [ngModelOptions]="{ standalone: true }"
name="isTransitionIssuesEnabled" name="isTransitionIssuesEnabled"
style="margin-bottom: 8px" style="margin-bottom: 8px"
> >
{{ T.F.JIRA.CFG_CMP.ENABLE_TRANSITIONS|translate }} {{ T.F.JIRA.CFG_CMP.ENABLE_TRANSITIONS | translate }}
</mat-slide-toggle> </mat-slide-toggle>
@if (cfg.isTransitionIssuesEnabled) { @if (cfg.isTransitionIssuesEnabled) {
<section @expand> <section @expand>
<mat-form-field>
<mat-label
>{{ T.F.JIRA.CFG_CMP.SELECT_ISSUE_FOR_TRANSITIONS|translate }}
</mat-label>
<input
[formControl]="issueSuggestionsCtrl"
[matAutocomplete]="autoEl"
class="border-color-primary"
matInput
/>
<mat-autocomplete
#autoEl="matAutocomplete"
(optionSelected)="updateTransitionOptions()"
[autoActiveFirstOption]="true"
[displayWith]="displayIssueWith"
>
@if ((isLoading$|async)) {
<mat-option
[value]="issueSuggestionsCtrl.value"
class="is-loading"
>
<mat-spinner diameter="50"></mat-spinner>
</mat-option>
}
<!---->
@for (issue of (filteredIssueSuggestions$|async); track issue.issueData.id) {
<mat-option [value]="issue"><span>{{ issue?.title }}</span> </mat-option>
}
</mat-autocomplete>
</mat-form-field>
@for (opt of transitionConfigOpts; track opt) {
<div>
<mat-form-field> <mat-form-field>
<!-- @if (opt.key==='OPEN') {--> <mat-label
<!-- <label>{{ T.F.JIRA.CFG_CMP.OPEN|translate }}</label>--> >{{ T.F.JIRA.CFG_CMP.SELECT_ISSUE_FOR_TRANSITIONS | translate }}
<!-- }--> </mat-label>
@if (opt.key==='IN_PROGRESS') { <input
<label>{{ T.F.JIRA.CFG_CMP.IN_PROGRESS|translate }}</label> [formControl]="issueSuggestionsCtrl"
} @if (opt.key==='DONE') { [matAutocomplete]="autoEl"
<label>{{ T.F.JIRA.CFG_CMP.DONE|translate }}</label> class="border-color-primary"
} matInput
<!-- TODO check for a better way to do this --> />
<!-- <mat-select [(ngModel)]="cfg.transitionConfig[opt.key]"--> <mat-autocomplete
<mat-select #autoEl="matAutocomplete"
(ngModelChange)="setTransition(opt.key, $event)" (optionSelected)="updateTransitionOptions()"
[ngModelOptions]="{standalone: true}" [autoActiveFirstOption]="true"
[ngModel]="getTransition(opt.key)" [displayWith]="displayIssueWith"
> >
<mat-option value="DO_NOT">{{ T.F.JIRA.CFG_CMP.DO_NOT|translate }}</mat-option> @if (isLoading$ | async) {
<mat-option value="ALWAYS_ASK" <mat-option
>{{ T.F.JIRA.CFG_CMP.ALWAYS_ASK|translate }} [value]="issueSuggestionsCtrl.value"
</mat-option> class="is-loading"
@for (transition of cfg.availableTransitions; track transition) { >
<mat-option [value]="transition"> {{ transition.name }} </mat-option> <mat-spinner diameter="50"></mat-spinner>
</mat-option>
} }
</mat-select> <!---->
@for (issue of filteredIssueSuggestions$ | async; track issue.issueData.id) {
<mat-option [value]="issue"
><span>{{ issue?.title }}</span>
</mat-option>
}
</mat-autocomplete>
</mat-form-field> </mat-form-field>
</div> @for (opt of transitionConfigOpts; track opt) {
} <div>
</section> <mat-form-field>
<!-- @if (opt.key==='OPEN') {-->
<!-- <label>{{ T.F.JIRA.CFG_CMP.OPEN|translate }}</label>-->
<!-- }-->
@if (opt.key === 'IN_PROGRESS') {
<label>{{ T.F.JIRA.CFG_CMP.IN_PROGRESS | translate }}</label>
}
@if (opt.key === 'DONE') {
<label>{{ T.F.JIRA.CFG_CMP.DONE | translate }}</label>
}
<!-- TODO check for a better way to do this -->
<!-- <mat-select [(ngModel)]="cfg.transitionConfig[opt.key]"-->
<mat-select
(ngModelChange)="setTransition(opt.key, $event)"
[ngModelOptions]="{ standalone: true }"
[ngModel]="getTransition(opt.key)"
>
<mat-option value="DO_NOT">{{
T.F.JIRA.CFG_CMP.DO_NOT | translate
}}</mat-option>
<mat-option value="ALWAYS_ASK"
>{{ T.F.JIRA.CFG_CMP.ALWAYS_ASK | translate }}
</mat-option>
@for (transition of cfg.availableTransitions; track transition) {
<mat-option [value]="transition"> {{ transition.name }} </mat-option>
}
</mat-select>
</mat-form-field>
</div>
}
</section>
} }
<section> <section>
<h3 class="sub-section-heading"> <h3 class="sub-section-heading">
{{ T.F.JIRA.CFG_CMP.MAP_CUSTOM_FIELDS|translate }} {{ T.F.JIRA.CFG_CMP.MAP_CUSTOM_FIELDS | translate }}
</h3> </h3>
<p>{{ T.F.JIRA.CFG_CMP.MAP_CUSTOM_FIELDS_INFO|translate }}</p> <p>{{ T.F.JIRA.CFG_CMP.MAP_CUSTOM_FIELDS_INFO | translate }}</p>
<div> <div>
<button <button
@ -86,14 +91,14 @@
mat-raised-button mat-raised-button
type="button" type="button"
> >
{{ T.F.JIRA.CFG_CMP.LOAD_SUGGESTIONS|translate }} {{ T.F.JIRA.CFG_CMP.LOAD_SUGGESTIONS | translate }}
</button> </button>
<br /> <br />
<br /> <br />
</div> </div>
<mat-form-field> <mat-form-field>
<mat-label>{{ T.F.JIRA.CFG_CMP.STORY_POINTS|translate }}</mat-label> <mat-label>{{ T.F.JIRA.CFG_CMP.STORY_POINTS | translate }}</mat-label>
<input <input
[formControl]="customFieldSuggestionsCtrl" [formControl]="customFieldSuggestionsCtrl"
[matAutocomplete]="storyPointAutoEl" [matAutocomplete]="storyPointAutoEl"
@ -105,11 +110,13 @@
#storyPointAutoEl="matAutocomplete" #storyPointAutoEl="matAutocomplete"
[autoActiveFirstOption]="true" [autoActiveFirstOption]="true"
> >
@for (field of (filteredCustomFieldSuggestions$|async); track @for (
trackByCustomFieldId($index, field)) { field of filteredCustomFieldSuggestions$ | async;
<mat-option [value]="field.id" track trackByCustomFieldId($index, field)
><span>{{ field?.id }}: {{ field?.name }}</span> ) {
</mat-option> <mat-option [value]="field.id"
><span>{{ field?.id }}: {{ field?.name }}</span>
</mat-option>
} }
</mat-autocomplete> </mat-autocomplete>
</mat-form-field> </mat-form-field>

View file

@ -1,64 +1,67 @@
<ng-container> <ng-container>
@if (task()?.issueWasUpdated) { @if (task()?.issueWasUpdated) {
<div <div
@expand @expand
style="text-align: center" style="text-align: center"
>
<button
(click)="hideUpdates()"
color="accent"
mat-raised-button
> >
{{T.F.OPEN_PROJECT.ISSUE_CONTENT.MARK_AS_CHECKED|translate}} <button
</button> (click)="hideUpdates()"
</div> color="accent"
mat-raised-button
>
{{ T.F.OPEN_PROJECT.ISSUE_CONTENT.MARK_AS_CHECKED | translate }}
</button>
</div>
} }
<div class="table-wrapper"> <div class="table-wrapper">
<table class="issue-table"> <table class="issue-table">
<tr> <tr>
<th>{{T.F.OPEN_PROJECT.ISSUE_CONTENT.SUMMARY|translate}}</th> <th>{{ T.F.OPEN_PROJECT.ISSUE_CONTENT.SUMMARY | translate }}</th>
<td> <td>
<a <a
[href]="issue?.url" [href]="issue?.url"
target="_blank" target="_blank"
><strong>{{issue?.subject}} #{{issue?.id}}</strong></a ><strong>{{ issue?.subject }} #{{ issue?.id }}</strong></a
> >
</td> </td>
</tr> </tr>
@if (issue?._embedded.type?.name) { @if (issue?._embedded.type?.name) {
<tr> <tr>
<th>{{T.F.OPEN_PROJECT.ISSUE_CONTENT.TYPE|translate}}</th> <th>{{ T.F.OPEN_PROJECT.ISSUE_CONTENT.TYPE | translate }}</th>
<td>{{issue?._embedded.type.name}}</td> <td>{{ issue?._embedded.type.name }}</td>
</tr> </tr>
} @if (issue?._embedded.status) { }
<tr> @if (issue?._embedded.status) {
<th>{{T.F.OPEN_PROJECT.ISSUE_CONTENT.STATUS|translate}}</th> <tr>
<td> <th>{{ T.F.OPEN_PROJECT.ISSUE_CONTENT.STATUS | translate }}</th>
<span <td>
class="dot" <span
[style.backgroud-color]="issue?._embedded.status.color" class="dot"
></span [style.backgroud-color]="issue?._embedded.status.color"
>{{issue?._embedded.status.name}} ></span
</td> >{{ issue?._embedded.status.name }}
</tr> </td>
} @if (issue?._embedded.assignee?.name) { </tr>
<tr> }
<th>{{T.F.OPEN_PROJECT.ISSUE_CONTENT.ASSIGNEE|translate}}</th> @if (issue?._embedded.assignee?.name) {
<td>{{issue?._embedded.assignee.name}}</td> <tr>
</tr> <th>{{ T.F.OPEN_PROJECT.ISSUE_CONTENT.ASSIGNEE | translate }}</th>
} @if (issue?.description?.raw || issue?.description?.html) { <td>{{ issue?._embedded.assignee.name }}</td>
<tr> </tr>
<th>{{T.F.OPEN_PROJECT.ISSUE_CONTENT.DESCRIPTION|translate}}</th> }
<td class="issue-description"> @if (issue?.description?.raw || issue?.description?.html) {
<div <tr>
[data]="issue?.description.raw || issue?.description.html" <th>{{ T.F.OPEN_PROJECT.ISSUE_CONTENT.DESCRIPTION | translate }}</th>
class="description markdown" <td class="issue-description">
markdown <div
></div> [data]="issue?.description.raw || issue?.description.html"
</td> class="description markdown"
</tr> markdown
></div>
</td>
</tr>
} }
</table> </table>

View file

@ -1,14 +1,15 @@
@if (task()?.issueWasUpdated) { @if (task()?.issueWasUpdated) {
<mat-icon <mat-icon
color="accent" color="accent"
style="margin-right: 8px" style="margin-right: 8px"
>update >update
</mat-icon> </mat-icon>
} @if (!task()?.issueWasUpdated) { }
<mat-icon @if (!task()?.issueWasUpdated) {
style="margin-right: 8px" <mat-icon
svgIcon="open_project" style="margin-right: 8px"
> svgIcon="open_project"
</mat-icon> >
</mat-icon>
} }
<span class="tab-label-text">OpenProject</span> <span class="tab-label-text">OpenProject</span>

View file

@ -1,5 +1,5 @@
<form <form
(submit)="$event.preventDefault();postTime()" (submit)="$event.preventDefault(); postTime()"
class="mat-body" class="mat-body"
name="time-estimate-form" name="time-estimate-form"
> >
@ -8,31 +8,33 @@
class="dialog-header-icon" class="dialog-header-icon"
svgIcon="open_project" svgIcon="open_project"
></mat-icon> ></mat-icon>
<span>{{T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.TITLE|translate}}</span> <span>{{ T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.TITLE | translate }}</span>
</h1> </h1>
<mat-dialog-content> <mat-dialog-content>
<p> <p>
{{T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.SUBMIT_TIME_FOR|translate}}<br /> {{ T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.SUBMIT_TIME_FOR | translate }}<br />
<strong> <strong>
<a <a
[href]="workPackage?.url" [href]="workPackage?.url"
target="_blank" target="_blank"
> >
{{workPackage.id}} {{workPackage.subject}}</a {{ workPackage.id }} {{ workPackage.subject }}</a
></strong ></strong
>. >.
</p> </p>
<p> <p>
{{T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.CURRENTLY_LOGGED|translate}} {{ T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.CURRENTLY_LOGGED | translate }}
<strong>{{(timeLoggedForWorkPackage)|msToString}}</strong> <strong>{{ timeLoggedForWorkPackage | msToString }}</strong>
</p> </p>
<br /> <br />
<br /> <br />
<div class="form-wrapper"> <div class="form-wrapper">
<mat-form-field> <mat-form-field>
<mat-label>{{T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.TIME_SPENT|translate}}</mat-label> <mat-label>{{
T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.TIME_SPENT | translate
}}</mat-label>
<input <input
[(ngModel)]="timeSpent" [(ngModel)]="timeSpent"
inputDuration="optional" inputDuration="optional"
@ -45,7 +47,7 @@
class="suffix-wrapper" class="suffix-wrapper"
matSuffix matSuffix
[matMenuTriggerFor]="contextMenu" [matMenuTriggerFor]="contextMenu"
[matTooltip]="T.F.JIRA.DIALOG_WORKLOG.TIME_SPENT_TOOLTIP|translate" [matTooltip]="T.F.JIRA.DIALOG_WORKLOG.TIME_SPENT_TOOLTIP | translate"
> >
<button <button
mat-icon-button mat-icon-button
@ -65,29 +67,33 @@
<mat-menu #contextMenu="matMenu"> <mat-menu #contextMenu="matMenu">
<ng-template matMenuContent> <ng-template matMenuContent>
@for (opt of defaultTimeOptions; track opt) { @for (opt of defaultTimeOptions; track opt) {
<button <button
mat-menu-item mat-menu-item
type="button" type="button"
(click)="fill(opt.value)" (click)="fill(opt.value)"
> >
{{opt.label|translate}} ({{(getTimeToLogForMode(opt.value)|msToString)}}) {{ opt.label | translate }} ({{
</button> getTimeToLogForMode(opt.value) | msToString
}})
</button>
} }
</ng-template> </ng-template>
</mat-menu> </mat-menu>
@if (defaultTimeCheckboxContent) { @if (defaultTimeCheckboxContent) {
<mat-checkbox <mat-checkbox
[@expandFade] [@expandFade]
[checked]="defaultTimeCheckboxContent.isChecked" [checked]="defaultTimeCheckboxContent.isChecked"
(change)="defaultTimeCheckboxContent.isChecked = $event.checked" (change)="defaultTimeCheckboxContent.isChecked = $event.checked"
style="margin-bottom: 20px" style="margin-bottom: 20px"
>{{defaultTimeCheckboxContent.label|translate}} >{{ defaultTimeCheckboxContent.label | translate }}
</mat-checkbox> </mat-checkbox>
} }
<mat-form-field> <mat-form-field>
<mat-label>{{T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.STARTED|translate}}</mat-label> <mat-label>{{
T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.STARTED | translate
}}</mat-label>
<input <input
[(ngModel)]="started" [(ngModel)]="started"
matInput matInput
@ -95,19 +101,21 @@
required required
type="datetime-local" type="datetime-local"
/> />
<mat-error <mat-error>{{
>{{T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.INVALID_DATE|translate}}</mat-error T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.INVALID_DATE | translate
> }}</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>{{T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.ACTIVITY|translate}}</mat-label> <mat-label>{{
T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.ACTIVITY | translate
}}</mat-label>
<mat-select <mat-select
[(ngModel)]="activityId" [(ngModel)]="activityId"
name="activity" name="activity"
> >
@for (activity of (activities$|async); track activity) { @for (activity of activities$ | async; track activity) {
<mat-option [value]="activity.id"> {{activity.name}} </mat-option> <mat-option [value]="activity.id"> {{ activity.name }} </mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@ -134,7 +142,7 @@
mat-button mat-button
type="button" type="button"
> >
{{T.G.CANCEL|translate}} {{ T.G.CANCEL | translate }}
</button> </button>
<button <button
color="primary" color="primary"
@ -142,7 +150,7 @@
type="submit" type="submit"
> >
<mat-icon>save</mat-icon> <mat-icon>save</mat-icon>
{{T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.POST_TIME|translate}} {{ T.F.OPEN_PROJECT.DIALOG_TRACK_TIME.POST_TIME | translate }}
</button> </button>
</div> </div>
</mat-dialog-actions> </mat-dialog-actions>

View file

@ -3,31 +3,35 @@
class="dialog-header-icon" class="dialog-header-icon"
svgIcon="open_project" svgIcon="open_project"
></mat-icon> ></mat-icon>
<span>{{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.TITLE|translate }}</span> <span>{{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.TITLE | translate }}</span>
</h1> </h1>
<mat-dialog-content> <mat-dialog-content>
<table> <table>
<tr> <tr>
<th>{{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.TASK_NAME|translate }}</th> <th>{{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.TASK_NAME | translate }}</th>
<td>{{ data.task ? data.task?.title : '' }}</td> <td>{{ data.task ? data.task?.title : '' }}</td>
</tr> </tr>
<tr> <tr>
<th>{{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.CURRENT_STATUS|translate }}</th> <th>{{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.CURRENT_STATUS | translate }}</th>
<td> <td>
{{ data.issue?._embedded?.status?.name ? data.issue?._embedded?.status?.name : '' {{
data.issue?._embedded?.status?.name ? data.issue?._embedded?.status?.name : ''
}} }}
</td> </td>
</tr> </tr>
<tr> <tr>
<th>{{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.CURRENT_ASSIGNEE|translate }}</th> <th>{{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.CURRENT_ASSIGNEE | translate }}</th>
<td> <td>
{{ data.issue?._embedded?.assignee?.name ? data.issue?._embedded?.assignee?.name : {{
'' }} data.issue?._embedded?.assignee?.name
? data.issue?._embedded?.assignee?.name
: ''
}}
</td> </td>
</tr> </tr>
<tr> <tr>
<th>{{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.PERCENTAGE_DONE|translate }}</th> <th>{{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.PERCENTAGE_DONE | translate }}</th>
<td> <td>
<!-- TODO: The 'tickInterval' property no longer exists --> <!-- TODO: The 'tickInterval' property no longer exists -->
<mat-slider <mat-slider
@ -45,16 +49,18 @@
</tr> </tr>
</table> </table>
<mat-form-field> <mat-form-field>
<label>{{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.CHOOSE_STATUS|translate }}</label> <label>{{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.CHOOSE_STATUS | translate }}</label>
<mat-select [(ngModel)]="chosenTransition"> <mat-select [(ngModel)]="chosenTransition">
<!--<mat-option value="DO_NOT">Don't transition</mat-option>--> <!--<mat-option value="DO_NOT">Don't transition</mat-option>-->
<!--<mat-option value="ALWAYS_ASK">Always open dialog</mat-option>--> <!--<mat-option value="ALWAYS_ASK">Always open dialog</mat-option>-->
@for (transition of (availableTransitions$|async); track trackByIndex($index, @for (
transition)) { transition of availableTransitions$ | async;
<mat-option [value]="transition"> track trackByIndex($index, transition)
<!--<img [src]="transition.to.iconUrl">--> ) {
{{ transition.name }} <mat-option [value]="transition">
</mat-option> <!--<img [src]="transition.to.iconUrl">-->
{{ transition.name }}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@ -69,7 +75,7 @@
mat-button mat-button
type="button" type="button"
> >
{{ T.G.CANCEL|translate }} {{ T.G.CANCEL | translate }}
</button> </button>
<button <button
(click)="transitionIssue()" (click)="transitionIssue()"
@ -77,7 +83,7 @@
color="primary" color="primary"
mat-stroked-button mat-stroked-button
> >
{{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.TITLE|translate }} {{ T.F.OPEN_PROJECT.DIALOG_TRANSITION.TITLE | translate }}
</button> </button>
</div> </div>
</mat-dialog-actions> </mat-dialog-actions>

View file

@ -1,100 +1,106 @@
<form [formGroup]="form"> <form [formGroup]="form">
<h3 class="sub-section-heading">{{ T.F.OPEN_PROJECT.CFG_CMP.TRANSITION|translate }}</h3> <h3 class="sub-section-heading">
{{ T.F.OPEN_PROJECT.CFG_CMP.TRANSITION | translate }}
</h3>
<mat-slide-toggle <mat-slide-toggle
[ngModel]="cfg.isTransitionIssuesEnabled" [ngModel]="cfg.isTransitionIssuesEnabled"
(ngModelChange)="partialModelChange({isTransitionIssuesEnabled: $event})" (ngModelChange)="partialModelChange({ isTransitionIssuesEnabled: $event })"
[ngModelOptions]="{standalone: true}" [ngModelOptions]="{ standalone: true }"
name="isTransitionIssuesEnabled" name="isTransitionIssuesEnabled"
style="margin-bottom: 8px" style="margin-bottom: 8px"
> >
{{ T.F.OPEN_PROJECT.CFG_CMP.ENABLE_TRANSITIONS|translate }} {{ T.F.OPEN_PROJECT.CFG_CMP.ENABLE_TRANSITIONS | translate }}
</mat-slide-toggle> </mat-slide-toggle>
@if (cfg.isTransitionIssuesEnabled) { @if (cfg.isTransitionIssuesEnabled) {
<section @expand> <section @expand>
<mat-form-field>
<mat-label>
{{ T.F.OPEN_PROJECT.CFG_CMP.SELECT_ISSUE_FOR_TRANSITIONS|translate }}
</mat-label>
<input
[formControl]="issueSuggestionsCtrl"
[matAutocomplete]="autoEl"
class="border-color-primary"
matInput
/>
<mat-autocomplete
#autoEl="matAutocomplete"
(optionSelected)="updateTransitionOptions()"
[autoActiveFirstOption]="true"
[displayWith]="displayIssueWith"
>
@if ((isLoading$|async)) {
<mat-option
[value]="issueSuggestionsCtrl.value"
class="is-loading"
>
<mat-spinner diameter="50"></mat-spinner>
</mat-option>
} @for (issue of (filteredIssueSuggestions$|async); track issue.issueData.id) {
<mat-option [value]="issue"><span>{{ issue?.title }}</span> </mat-option>
}
</mat-autocomplete>
</mat-form-field>
@for (opt of transitionConfigOpts; track opt.key) {
<div>
<mat-form-field> <mat-form-field>
<!-- @if (opt.key==='OPEN') {--> <mat-label>
<!-- <label> {{ T.F.OPEN_PROJECT.CFG_CMP.OPEN|translate }} </label>--> {{ T.F.OPEN_PROJECT.CFG_CMP.SELECT_ISSUE_FOR_TRANSITIONS | translate }}
<!-- } --> </mat-label>
@if (opt.key==='IN_PROGRESS') { <input
<label> {{ T.F.OPEN_PROJECT.CFG_CMP.IN_PROGRESS|translate }} </label> [formControl]="issueSuggestionsCtrl"
} @if (opt.key==='DONE') { [matAutocomplete]="autoEl"
<label> {{ T.F.OPEN_PROJECT.CFG_CMP.DONE|translate }} </label> class="border-color-primary"
} matInput
<mat-select />
(ngModelChange)="setTransition(opt.key, $event)" <mat-autocomplete
[ngModelOptions]="{standalone: true}" #autoEl="matAutocomplete"
[ngModel]="getTransition(opt.key)" (optionSelected)="updateTransitionOptions()"
[autoActiveFirstOption]="true"
[displayWith]="displayIssueWith"
> >
<mat-option value="DO_NOT"> @if (isLoading$ | async) {
{{ T.F.OPEN_PROJECT.CFG_CMP.DO_NOT|translate }} <mat-option
</mat-option> [value]="issueSuggestionsCtrl.value"
<mat-option value="ALWAYS_ASK"> class="is-loading"
{{ T.F.OPEN_PROJECT.CFG_CMP.ALWAYS_ASK|translate }} >
</mat-option> <mat-spinner diameter="50"></mat-spinner>
@for (transition of cfg.availableTransitions; track transition.id) { </mat-option>
<mat-option [value]="transition"> {{ transition.name }} </mat-option>
} }
</mat-select> @for (issue of filteredIssueSuggestions$ | async; track issue.issueData.id) {
<mat-option [value]="issue"
><span>{{ issue?.title }}</span>
</mat-option>
}
</mat-autocomplete>
</mat-form-field> </mat-form-field>
@if (showSetProgressOption(opt.key)) { @for (opt of transitionConfigOpts; track opt.key) {
<div> <div>
<mat-checkbox <mat-form-field>
[ngModel]="this.cfg.isSetProgressOnTaskDone" <!-- @if (opt.key==='OPEN') {-->
(ngModelChange)="partialModelChange({isSetProgressOnTaskDone: $event})" <!-- <label> {{ T.F.OPEN_PROJECT.CFG_CMP.OPEN|translate }} </label>-->
[ngModelOptions]="{standalone: true}" <!-- } -->
> @if (opt.key === 'IN_PROGRESS') {
{{ T.F.OPEN_PROJECT.CFG_CMP.PROGRESS_ON_SAVE|translate }} <label> {{ T.F.OPEN_PROJECT.CFG_CMP.IN_PROGRESS | translate }} </label>
</mat-checkbox> }
<!-- TODO: The 'tickInterval' property no longer exists --> @if (opt.key === 'DONE') {
@if (this.cfg.isSetProgressOnTaskDone) { <label> {{ T.F.OPEN_PROJECT.CFG_CMP.DONE | translate }} </label>
<mat-slider }
thumbLabel <mat-select
[displayWith]="displayThumbWith" (ngModelChange)="setTransition(opt.key, $event)"
min="0" [ngModelOptions]="{ standalone: true }"
max="100" [ngModel]="getTransition(opt.key)"
step="5" >
aria-label="units" <mat-option value="DO_NOT">
[ngModel]="this.cfg.progressOnDone" {{ T.F.OPEN_PROJECT.CFG_CMP.DO_NOT | translate }}
(ngModelChange)="partialModelChange({progressOnDone: $event})" </mat-option>
[ngModelOptions]="{standalone: true}" <mat-option value="ALWAYS_ASK">
><input matSliderThumb {{ T.F.OPEN_PROJECT.CFG_CMP.ALWAYS_ASK | translate }}
/></mat-slider> </mat-option>
} @for (transition of cfg.availableTransitions; track transition.id) {
</div> <mat-option [value]="transition"> {{ transition.name }} </mat-option>
}
</mat-select>
</mat-form-field>
@if (showSetProgressOption(opt.key)) {
<div>
<mat-checkbox
[ngModel]="this.cfg.isSetProgressOnTaskDone"
(ngModelChange)="partialModelChange({ isSetProgressOnTaskDone: $event })"
[ngModelOptions]="{ standalone: true }"
>
{{ T.F.OPEN_PROJECT.CFG_CMP.PROGRESS_ON_SAVE | translate }}
</mat-checkbox>
<!-- TODO: The 'tickInterval' property no longer exists -->
@if (this.cfg.isSetProgressOnTaskDone) {
<mat-slider
thumbLabel
[displayWith]="displayThumbWith"
min="0"
max="100"
step="5"
aria-label="units"
[ngModel]="this.cfg.progressOnDone"
(ngModelChange)="partialModelChange({ progressOnDone: $event })"
[ngModelOptions]="{ standalone: true }"
><input matSliderThumb
/></mat-slider>
}
</div>
}
</div>
} }
</div> </section>
}
</section>
} }
</form> </form>

View file

@ -4,48 +4,48 @@
[href]="issue?.url" [href]="issue?.url"
target="_blank" target="_blank"
> >
{{issue?.tracker.name}} #{{issue?.id}} {{ issue?.tracker.name }} #{{ issue?.id }}
</a> </a>
</h3> </h3>
<div class="table-wrapper"> <div class="table-wrapper">
<table class="issue-table"> <table class="issue-table">
<tr> <tr>
<th>{{T.F.REDMINE.ISSUE_CONTENT.AUTHOR|translate}}</th> <th>{{ T.F.REDMINE.ISSUE_CONTENT.AUTHOR | translate }}</th>
<td>{{issue?.author.name}}</td> <td>{{ issue?.author.name }}</td>
</tr> </tr>
<tr> <tr>
<th>{{T.F.REDMINE.ISSUE_CONTENT.STATUS|translate}}</th> <th>{{ T.F.REDMINE.ISSUE_CONTENT.STATUS | translate }}</th>
<td>{{issue?.status.name}}</td> <td>{{ issue?.status.name }}</td>
</tr> </tr>
<tr> <tr>
<th>{{T.F.REDMINE.ISSUE_CONTENT.PRIORITY|translate}}</th> <th>{{ T.F.REDMINE.ISSUE_CONTENT.PRIORITY | translate }}</th>
<td>{{issue?.priority.name}}</td> <td>{{ issue?.priority.name }}</td>
</tr> </tr>
@if (issue?.description) { @if (issue?.description) {
<tr> <tr>
<th>{{T.F.REDMINE.ISSUE_CONTENT.DESCRIPTION|translate}}</th> <th>{{ T.F.REDMINE.ISSUE_CONTENT.DESCRIPTION | translate }}</th>
<td>{{issue?.description}}</td> <td>{{ issue?.description }}</td>
</tr> </tr>
} }
</table> </table>
</div> </div>
@if (task()?.issueWasUpdated) { @if (task()?.issueWasUpdated) {
<div <div
@expand @expand
style="text-align: center" style="text-align: center"
>
<button
(click)="hideUpdates()"
color="accent"
mat-raised-button
> >
{{T.F.REDMINE.ISSUE_CONTENT.MARK_AS_CHECKED|translate}} <button
</button> (click)="hideUpdates()"
</div> color="accent"
mat-raised-button
>
{{ T.F.REDMINE.ISSUE_CONTENT.MARK_AS_CHECKED | translate }}
</button>
</div>
} }
</ng-container> </ng-container>

View file

@ -1,14 +1,15 @@
@if (task()?.issueWasUpdated) { @if (task()?.issueWasUpdated) {
<mat-icon <mat-icon
color="accent" color="accent"
style="margin-right: 8px" style="margin-right: 8px"
>update >update
</mat-icon> </mat-icon>
} @if (!task()?.issueWasUpdated) { }
<mat-icon @if (!task()?.issueWasUpdated) {
style="margin-right: 8px" <mat-icon
svgIcon="redmine" style="margin-right: 8px"
> svgIcon="redmine"
</mat-icon> >
</mat-icon>
} }
<span class="tab-label-text">Redmine</span> <span class="tab-label-text">Redmine</span>

View file

@ -1,98 +1,104 @@
<div class="wrapper mat-elevation-z1"> <div class="wrapper mat-elevation-z1">
<help-section> <help-section>
<p>{{T.F.METRIC.EVAL_FORM.HELP_P1|translate}}</p> <p>{{ T.F.METRIC.EVAL_FORM.HELP_P1 | translate }}</p>
<p><a routerLink="/metrics">{{T.F.METRIC.EVAL_FORM.HELP_LINK_TXT|translate}}</a></p> <p>
<a routerLink="/metrics">{{ T.F.METRIC.EVAL_FORM.HELP_LINK_TXT | translate }}</a>
</p>
<h3 class="mat-h3">{{T.F.METRIC.EVAL_FORM.HELP_H1|translate}}</h3> <h3 class="mat-h3">{{ T.F.METRIC.EVAL_FORM.HELP_H1 | translate }}</h3>
<p>{{T.F.METRIC.EVAL_FORM.HELP_P2|translate}}</p> <p>{{ T.F.METRIC.EVAL_FORM.HELP_P2 | translate }}</p>
</help-section> </help-section>
@if (metricForDay) { @if (metricForDay) {
<form <form
#f="ngForm" #f="ngForm"
name="form" name="form"
novalidate novalidate
> >
<div class="row"> <div class="row">
<mat-form-field> <mat-form-field>
<mat-label>{{T.F.METRIC.EVAL_FORM.MOOD|translate}}</mat-label> <mat-label>{{ T.F.METRIC.EVAL_FORM.MOOD | translate }}</mat-label>
<input <input
#mood="ngModel" #mood="ngModel"
(ngModelChange)="updateMood($event)" (ngModelChange)="updateMood($event)"
[ngModel]="metricForDay.mood" [ngModel]="metricForDay.mood"
matInput matInput
max="10" max="10"
maxlength="2" maxlength="2"
min="1" min="1"
name="mood" name="mood"
required required
type="number" type="number"
/> />
<mat-hint>{{T.F.METRIC.EVAL_FORM.MOOD_HINT|translate}}</mat-hint> <mat-hint>{{ T.F.METRIC.EVAL_FORM.MOOD_HINT | translate }}</mat-hint>
@if (mood.invalid && (mood.dirty || mood.touched)) { @if (mood.invalid && (mood.dirty || mood.touched)) {
<mat-error> {{T.V.E_1TO10|translate}} </mat-error> <mat-error> {{ T.V.E_1TO10 | translate }} </mat-error>
} }
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>{{T.F.METRIC.EVAL_FORM.PRODUCTIVITY|translate}}</mat-label> <mat-label>{{ T.F.METRIC.EVAL_FORM.PRODUCTIVITY | translate }}</mat-label>
<input <input
#productivity="ngModel" #productivity="ngModel"
(ngModelChange)="updateProductivity($event)" (ngModelChange)="updateProductivity($event)"
[ngModel]="metricForDay.productivity" [ngModel]="metricForDay.productivity"
matInput matInput
max="10" max="10"
maxlength="2" maxlength="2"
min="1" min="1"
name="productivity" name="productivity"
required required
type="number" type="number"
/> />
<mat-hint>{{T.F.METRIC.EVAL_FORM.PRODUCTIVITY_HINT|translate}}</mat-hint> <mat-hint>{{ T.F.METRIC.EVAL_FORM.PRODUCTIVITY_HINT | translate }}</mat-hint>
@if (productivity.invalid && (productivity.dirty || productivity.touched)) { @if (productivity.invalid && (productivity.dirty || productivity.touched)) {
<mat-error> {{T.V.E_1TO10|translate}} </mat-error> <mat-error> {{ T.V.E_1TO10 | translate }} </mat-error>
} }
</mat-form-field> </mat-form-field>
</div> </div>
<chip-list-input <chip-list-input
(addItem)="addObstruction($event)" (addItem)="addObstruction($event)"
(addNewItem)="addNewObstruction($event)" (addNewItem)="addNewObstruction($event)"
(removeItem)="removeObstruction($event)" (removeItem)="removeObstruction($event)"
[label]="T.F.METRIC.EVAL_FORM.OBSTRUCTIONS|translate" [label]="T.F.METRIC.EVAL_FORM.OBSTRUCTIONS | translate"
[model]="metricForDay.obstructions" [model]="metricForDay.obstructions"
[suggestions]="(obstructionService.obstructions$|async)" [suggestions]="obstructionService.obstructions$ | async"
></chip-list-input> ></chip-list-input>
<chip-list-input <chip-list-input
(addItem)="addImprovement($event)" (addItem)="addImprovement($event)"
(addNewItem)="addNewImprovement($event)" (addNewItem)="addNewImprovement($event)"
(removeItem)="removeImprovement($event)" (removeItem)="removeImprovement($event)"
[label]="T.F.METRIC.EVAL_FORM.IMPROVEMENTS|translate" [label]="T.F.METRIC.EVAL_FORM.IMPROVEMENTS | translate"
[model]="metricForDay.improvements" [model]="metricForDay.improvements"
[suggestions]="(improvementService.improvements$|async)" [suggestions]="improvementService.improvements$ | async"
></chip-list-input> ></chip-list-input>
<chip-list-input <chip-list-input
(addItem)="addImprovementTomorrow($event)" (addItem)="addImprovementTomorrow($event)"
(addNewItem)="addNewImprovementTomorrow($event)" (addNewItem)="addNewImprovementTomorrow($event)"
(additionalAction)="toggleImprovementRepeat($event)" (additionalAction)="toggleImprovementRepeat($event)"
(removeItem)="removeImprovementTomorrow($event)" (removeItem)="removeImprovementTomorrow($event)"
[additionalActionTooltipUnToggle]="T.F.METRIC.EVAL_FORM.DISABLE_REPEAT_EVERY_DAY|translate" [additionalActionTooltipUnToggle]="
[additionalActionTooltip]="T.F.METRIC.EVAL_FORM.ENABLE_REPEAT_EVERY_DAY|translate" T.F.METRIC.EVAL_FORM.DISABLE_REPEAT_EVERY_DAY | translate
[label]="T.F.METRIC.EVAL_FORM.IMPROVEMENTS_TOMORROW|translate" "
[model]="metricForDay.improvementsTomorrow" [additionalActionTooltip]="
[suggestions]="(improvementService.improvements$|async)" T.F.METRIC.EVAL_FORM.ENABLE_REPEAT_EVERY_DAY | translate
[toggledItems]="improvementService.repeatedImprovementIds$|async" "
additionalActionIcon="repeat" [label]="T.F.METRIC.EVAL_FORM.IMPROVEMENTS_TOMORROW | translate"
></chip-list-input> [model]="metricForDay.improvementsTomorrow"
</form> [suggestions]="improvementService.improvements$ | async"
[toggledItems]="improvementService.repeatedImprovementIds$ | async"
additionalActionIcon="repeat"
></chip-list-input>
</form>
} }
</div> </div>
@if ((workContextService.isActiveWorkContextProject$|async)) { @if (workContextService.isActiveWorkContextProject$ | async) {
<div style="text-align: center; margin-top: 8px; margin-bottom: 16px"> <div style="text-align: center; margin-top: 8px; margin-bottom: 16px">
<button <button
(click)="addNote()" (click)="addNote()"
mat-button mat-button
> >
<mat-icon>add</mat-icon> <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> </button>
</div> </div>
} }

View file

@ -3,29 +3,29 @@
class="improvements" class="improvements"
> >
@for (improvement of improvements; track trackById($index, improvement)) { @for (improvement of improvements; track trackById($index, improvement)) {
<div <div
class="improvement" class="improvement"
mat-ripple mat-ripple
>
<button
(click)="dismiss(improvement)"
[matTooltip]="T.G.DISMISS|translate"
class="dismiss"
disableRipple
mat-icon-button
> >
<mat-icon>close</mat-icon> <button
</button> (click)="dismiss(improvement)"
<div class="title">{{improvement?.title}}</div> [matTooltip]="T.G.DISMISS | translate"
<button class="dismiss"
(click)="check(improvement)" disableRipple
[matTooltip]="T.F.METRIC.BANNER.CHECK|translate" mat-icon-button
class="check" >
disableRipple <mat-icon>close</mat-icon>
mat-icon-button </button>
> <div class="title">{{ improvement?.title }}</div>
<mat-icon>check</mat-icon> <button
</button> (click)="check(improvement)"
</div> [matTooltip]="T.F.METRIC.BANNER.CHECK | translate"
class="check"
disableRipple
mat-icon-button
>
<mat-icon>check</mat-icon>
</button>
</div>
} }
</div> </div>

View file

@ -1,156 +1,165 @@
<div class="wrapper"> <div class="wrapper">
@if (projectMetricsService.simpleMetrics$|async; as sm) { @if (projectMetricsService.simpleMetrics$ | async; as sm) {
<section <section
class="basic-stats" class="basic-stats"
[@fade] [@fade]
>
<h1
class="mat-h1"
style="text-align: center"
> >
{{ T.PM.TITLE|translate }} <h1
</h1> class="mat-h1"
<!-- <h2>Basic Metrics</h2>--> style="text-align: center"
<p><i>{{ sm.start }} {{ sm.end }}</i></p> >
<div class="material-table"> {{ T.PM.TITLE | translate }}
<table> </h1>
<tr> <!-- <h2>Basic Metrics</h2>-->
<th>{{ T.F.METRIC.CMP.TIME_SPENT|translate }}</th> <p>
<td>{{ sm.timeSpent|msToString }}</td> <i>{{ sm.start }} {{ sm.end }}</i>
</tr> </p>
<tr> <div class="material-table">
<th>{{ T.F.METRIC.CMP.TIME_ESTIMATED|translate }}</th> <table>
<td>{{ sm.timeEstimate|msToString }}</td> <tr>
</tr> <th>{{ T.F.METRIC.CMP.TIME_SPENT | translate }}</th>
<tr> <td>{{ sm.timeSpent | msToString }}</td>
<th>{{ T.F.METRIC.CMP.TASKS_DONE_CREATED|translate }}</th> </tr>
<td>{{ sm.nrOfCompletedTasks }} / {{ sm.nrOfAllTasks }}</td> <tr>
</tr> <th>{{ T.F.METRIC.CMP.TIME_ESTIMATED | translate }}</th>
<tr> <td>{{ sm.timeEstimate | msToString }}</td>
<th>{{ T.F.METRIC.CMP.DAYS_WORKED|translate }}</th> </tr>
<td>{{ sm.daysWorked }}</td> <tr>
</tr> <th>{{ T.F.METRIC.CMP.TASKS_DONE_CREATED | translate }}</th>
<tr> <td>{{ sm.nrOfCompletedTasks }} / {{ sm.nrOfAllTasks }}</td>
<th>{{ T.F.METRIC.CMP.AVG_TASKS_PER_DAY_WORKED|translate }}</th> </tr>
<td>{{ sm.avgTasksPerDay|number:'1.0-1' }}</td> <tr>
</tr> <th>{{ T.F.METRIC.CMP.DAYS_WORKED | translate }}</th>
<tr> <td>{{ sm.daysWorked }}</td>
<th>{{ T.F.METRIC.CMP.AVG_BREAKS_PER_DAY|translate }}</th> </tr>
<td>{{ sm.avgBreakNr|number:'1.0-1' }}</td> <tr>
</tr> <th>{{ T.F.METRIC.CMP.AVG_TASKS_PER_DAY_WORKED | translate }}</th>
<tr> <td>{{ sm.avgTasksPerDay | number: '1.0-1' }}</td>
<th>{{ T.F.METRIC.CMP.AVG_TIME_SPENT_PER_DAY|translate }}</th> </tr>
<td>{{ sm.avgTimeSpentOnDay|msToString }}</td> <tr>
</tr> <th>{{ T.F.METRIC.CMP.AVG_BREAKS_PER_DAY | translate }}</th>
<tr> <td>{{ sm.avgBreakNr | number: '1.0-1' }}</td>
<th>{{ T.F.METRIC.CMP.AVG_TIME_SPENT_PER_TASK|translate }}</th> </tr>
<td>{{ sm.avgTimeSpentOnTask|msToString }}</td> <tr>
</tr> <th>{{ T.F.METRIC.CMP.AVG_TIME_SPENT_PER_DAY | translate }}</th>
<tr> <td>{{ sm.avgTimeSpentOnDay | msToString }}</td>
<th> </tr>
{{ T.F.METRIC.CMP.AVG_TIME_SPENT_PER_TASK|translate }} <tr>
<br />{{ T.F.METRIC.CMP.COUNTING_SUBTASKS|translate }} <th>{{ T.F.METRIC.CMP.AVG_TIME_SPENT_PER_TASK | translate }}</th>
</th> <td>{{ sm.avgTimeSpentOnTask | msToString }}</td>
<td>{{ sm.avgTimeSpentOnTaskIncludingSubTasks|msToString }}</td> </tr>
</tr> <tr>
<tr> <th>
<th>{{ T.F.METRIC.CMP.AVG_TIME_SPENT_ON_BREAKS|translate }}</th> {{ T.F.METRIC.CMP.AVG_TIME_SPENT_PER_TASK | translate }}
<td>{{ sm.avgBreakTime|msToString }}</td> <br />{{ T.F.METRIC.CMP.COUNTING_SUBTASKS | translate }}
</tr> </th>
</table> <td>{{ sm.avgTimeSpentOnTaskIncludingSubTasks | msToString }}</td>
</div> </tr>
</section> <tr>
} @if (!(metricService.hasData$|async)) { <th>{{ T.F.METRIC.CMP.AVG_TIME_SPENT_ON_BREAKS | translate }}</th>
<p style="margin-top: 32px">{{ T.F.METRIC.CMP.NO_ADDITIONAL_DATA_YET|translate }}</p> <td>{{ sm.avgBreakTime | msToString }}</td>
} @if ((metricService.hasData$|async)) { </tr>
<section class="metric-metrics"> </table>
<h1>{{ T.F.METRIC.CMP.GLOBAL_METRICS|translate }}</h1> </div>
<section class="pie-charts">
@if ((metricService.improvementCountsPieChartData$|async); as improvementCounts) {
<section>
<h3>{{ T.F.METRIC.CMP.IMPROVEMENT_SELECTION_COUNT|translate }}</h3>
<canvas
[type]="pieChartType"
[data]="improvementCounts"
[legend]="(improvementCounts?.datasets[0].data.length < 12)"
[options]="pieChartOptions"
baseChart
>
</canvas>
</section>
} @if ((metricService.obstructionCountsPieChartData$|async); as obstructionCounts) {
<section>
<h3>{{ T.F.METRIC.CMP.OBSTRUCTION_SELECTION_COUNT|translate }}</h3>
<canvas
[type]="pieChartType"
[data]="obstructionCounts"
[legend]="(obstructionCounts?.datasets[0].data.length < 12)"
[options]="pieChartOptions"
baseChart
>
</canvas>
</section>
}
</section> </section>
<section class="line-charts"> }
@if ((productivityHappiness$|async); as productivityHappiness) { @if (!(metricService.hasData$ | async)) {
<section> <p style="margin-top: 32px">
<h3>{{ T.F.METRIC.CMP.MOOD_PRODUCTIVITY_OVER_TIME|translate }}</h3> {{ T.F.METRIC.CMP.NO_ADDITIONAL_DATA_YET | translate }}
<div class="chart-wrapper"> </p>
<div class="inner-chart-wrapper"> }
@if (metricService.hasData$ | async) {
<section class="metric-metrics">
<h1>{{ T.F.METRIC.CMP.GLOBAL_METRICS | translate }}</h1>
<section class="pie-charts">
@if (metricService.improvementCountsPieChartData$ | async; as improvementCounts) {
<section>
<h3>{{ T.F.METRIC.CMP.IMPROVEMENT_SELECTION_COUNT | translate }}</h3>
<canvas <canvas
[type]="lineChartType" [type]="pieChartType"
[data]="productivityHappiness" [data]="improvementCounts"
[legend]="true" [legend]="improvementCounts?.datasets[0].data.length < 12"
[options]="lineChartOptions" [options]="pieChartOptions"
baseChart
></canvas>
</div>
</div>
</section>
}
</section>
</section>
} @if ((metricService.hasData$|async)) {
<section class="metric-metrics">
<h2>{{ T.F.METRIC.CMP.SIMPLE_COUNTERS|translate }}</h2>
<section class="line-charts">
@if ((simpleClickCounterData$|async); as simpleCounterClickData) {
<section>
<h3>{{ T.F.METRIC.CMP.SIMPLE_CLICK_COUNTERS_OVER_TIME|translate }}</h3>
<div class="chart-wrapper">
<div class="inner-chart-wrapper">
<canvas
[type]="lineChartType"
[data]="simpleCounterClickData"
[labels]="simpleCounterClickData.labels"
[options]="lineChartOptions"
[legend]="true"
baseChart baseChart
> >
</canvas> </canvas>
</div> </section>
</div> }
</section> @if (metricService.obstructionCountsPieChartData$ | async; as obstructionCounts) {
} @if ((simpleCounterStopWatchData$|async); as simpleCounterStopWatchData) { <section>
<section> <h3>{{ T.F.METRIC.CMP.OBSTRUCTION_SELECTION_COUNT | translate }}</h3>
<h3>{{ T.F.METRIC.CMP.SIMPLE_STOPWATCH_COUNTERS_OVER_TIME|translate }}</h3>
<div class="chart-wrapper">
<div class="inner-chart-wrapper">
<canvas <canvas
[type]="lineChartType" [type]="pieChartType"
[data]="simpleCounterStopWatchData" [data]="obstructionCounts"
[labels]="simpleCounterStopWatchData.labels" [legend]="obstructionCounts?.datasets[0].data.length < 12"
[options]="lineChartOptions" [options]="pieChartOptions"
[legend]="true"
baseChart baseChart
> >
</canvas> </canvas>
</div> </section>
</div> }
</section>
<section class="line-charts">
@if (productivityHappiness$ | async; as productivityHappiness) {
<section>
<h3>{{ T.F.METRIC.CMP.MOOD_PRODUCTIVITY_OVER_TIME | translate }}</h3>
<div class="chart-wrapper">
<div class="inner-chart-wrapper">
<canvas
[type]="lineChartType"
[data]="productivityHappiness"
[legend]="true"
[options]="lineChartOptions"
baseChart
></canvas>
</div>
</div>
</section>
}
</section>
</section>
}
@if (metricService.hasData$ | async) {
<section class="metric-metrics">
<h2>{{ T.F.METRIC.CMP.SIMPLE_COUNTERS | translate }}</h2>
<section class="line-charts">
@if (simpleClickCounterData$ | async; as simpleCounterClickData) {
<section>
<h3>{{ T.F.METRIC.CMP.SIMPLE_CLICK_COUNTERS_OVER_TIME | translate }}</h3>
<div class="chart-wrapper">
<div class="inner-chart-wrapper">
<canvas
[type]="lineChartType"
[data]="simpleCounterClickData"
[labels]="simpleCounterClickData.labels"
[options]="lineChartOptions"
[legend]="true"
baseChart
>
</canvas>
</div>
</div>
</section>
}
@if (simpleCounterStopWatchData$ | async; as simpleCounterStopWatchData) {
<section>
<h3>{{ T.F.METRIC.CMP.SIMPLE_STOPWATCH_COUNTERS_OVER_TIME | translate }}</h3>
<div class="chart-wrapper">
<div class="inner-chart-wrapper">
<canvas
[type]="lineChartType"
[data]="simpleCounterStopWatchData"
[labels]="simpleCounterStopWatchData.labels"
[options]="lineChartOptions"
[legend]="true"
baseChart
>
</canvas>
</div>
</div>
</section>
}
</section> </section>
}
</section> </section>
</section>
} }
</div> </div>

View file

@ -1,55 +1,58 @@
@if (note) { @if (note) {
<div
[class.isFocused]="isFocus()"
[class.isImg]="note.imgUrl"
class="note"
>
@if (note.imgUrl) {
<img
[enlargeImg]="note.imgUrl"
[src]="note.imgUrl"
(longPress)="editFullscreen($event)"
class="note-img"
/>
} @if (!note.imgUrl) {
<div class="content">
<div
(click)="editFullscreen($event)"
markdown
[data]="isLongNote ? shortenedNote : note.content"
class="markdown-preview markdown"
></div>
</div>
}
<div <div
class="bottom-controls handle-drag" [class.isFocused]="isFocus()"
[class.isOver]="note.imgUrl" [class.isImg]="note.imgUrl"
class="note"
> >
@if (note.projectId) { @if (note.imgUrl) {
<button <img
mat-icon-button [enlargeImg]="note.imgUrl"
(click)="togglePinToToday()" [src]="note.imgUrl"
> (longPress)="editFullscreen($event)"
@if (!note.isPinnedToToday) { class="note-img"
<mat-icon>wb_sunny</mat-icon> />
} @if (note.isPinnedToToday) {
<mat-icon svgIcon="remove_today"></mat-icon>
}
</button>
} @if (projectTag$|async; as projectTag) {
<tag [tag]="projectTag"></tag>
} }
<!-- <button mat-icon-button>--> @if (!note.imgUrl) {
<!-- <mat-icon class="drag-handle-ico" svgIcon="drag_handle"></mat-icon>--> <div class="content">
<!-- </button>--> <div
<button (click)="editFullscreen($event)"
[matMenuTriggerFor]="menu" markdown
mat-icon-button [data]="isLongNote ? shortenedNote : note.content"
class="markdown-preview markdown"
></div>
</div>
}
<div
class="bottom-controls handle-drag"
[class.isOver]="note.imgUrl"
> >
<mat-icon>more_vert</mat-icon> @if (note.projectId) {
</button> <button
mat-icon-button
(click)="togglePinToToday()"
>
@if (!note.isPinnedToToday) {
<mat-icon>wb_sunny</mat-icon>
}
@if (note.isPinnedToToday) {
<mat-icon svgIcon="remove_today"></mat-icon>
}
</button>
}
@if (projectTag$ | async; as projectTag) {
<tag [tag]="projectTag"></tag>
}
<!-- <button mat-icon-button>-->
<!-- <mat-icon class="drag-handle-ico" svgIcon="drag_handle"></mat-icon>-->
<!-- </button>-->
<button
[matMenuTriggerFor]="menu"
mat-icon-button
>
<mat-icon>more_vert</mat-icon>
</button>
</div>
</div> </div>
</div>
} }
<mat-menu #menu="matMenu"> <mat-menu #menu="matMenu">
@ -59,22 +62,31 @@
mat-menu-item mat-menu-item
> >
<mat-icon>forward</mat-icon> <mat-icon>forward</mat-icon>
{{(note.projectId ? T.F.TASK.CMP.MOVE_TO_OTHER_PROJECT : {{
T.F.TASK.CMP.ADD_TO_PROJECT)|translate}} (note.projectId
? T.F.TASK.CMP.MOVE_TO_OTHER_PROJECT
: T.F.TASK.CMP.ADD_TO_PROJECT
) | translate
}}
</button> </button>
@if (!note.imgUrl) { @if (!note.imgUrl) {
<button <button
(click)="toggleLock()" (click)="toggleLock()"
mat-menu-item mat-menu-item
> >
@if (note.isLock) { @if (note.isLock) {
<mat-icon>lock</mat-icon> <mat-icon>lock</mat-icon>
} @if (!note.isLock) { }
<mat-icon>lock_open</mat-icon> @if (!note.isLock) {
} {{note.isLock ? (T.F.NOTE.NOTE_CMP.ENABLE_PARSE|translate) : <mat-icon>lock_open</mat-icon>
(T.F.NOTE.NOTE_CMP.DISABLE_PARSE|translate)}} }
</button> {{
note.isLock
? (T.F.NOTE.NOTE_CMP.ENABLE_PARSE | translate)
: (T.F.NOTE.NOTE_CMP.DISABLE_PARSE | translate)
}}
</button>
} }
<button <button
@ -82,19 +94,21 @@
mat-menu-item mat-menu-item
> >
<mat-icon style="color: #e15d63">delete_forever</mat-icon> <mat-icon style="color: #e15d63">delete_forever</mat-icon>
{{T.G.DELETE|translate}} {{ T.G.DELETE | translate }}
</button> </button>
<mat-menu #projectMenu="matMenu"> <mat-menu #projectMenu="matMenu">
<ng-template matMenuContent> <ng-template matMenuContent>
@for (project of (moveToProjectList$|async); track trackByProjectId($index, @for (
project)) { project of moveToProjectList$ | async;
<button track trackByProjectId($index, project)
(click)="moveNoteToProject(project.id)" ) {
mat-menu-item <button
> (click)="moveNoteToProject(project.id)"
{{project.title}} mat-menu-item
</button> >
{{ project.title }}
</button>
} }
</ng-template> </ng-template>
</mat-menu> </mat-menu>

View file

@ -6,22 +6,22 @@
mat-button mat-button
> >
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
{{ T.F.NOTE.NOTES_CMP.ADD_BTN|translate }} {{ T.F.NOTE.NOTES_CMP.ADD_BTN | translate }}
</button> </button>
</header> </header>
@if (isDragOver) { @if (isDragOver) {
<div <div
@fade @fade
class="bgc-accent drag-over-msg" class="bgc-accent drag-over-msg"
> >
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
{{ T.F.NOTE.NOTES_CMP.DROP_TO_ADD|translate }} {{ T.F.NOTE.NOTES_CMP.DROP_TO_ADD | translate }}
</div> </div>
} }
<!----> <!---->
@let notes = workContextService.notes$|async; @let notes = workContextService.notes$ | async;
<div <div
[@standardList]="notes?.length" [@standardList]="notes?.length"
cdkDropList cdkDropList
@ -30,16 +30,16 @@
class="notes" class="notes"
> >
<!----> <!---->
@for( note of notes; track note.id) { @for (note of notes; track note.id) {
<div cdkDrag> <div cdkDrag>
<note <note
[isFocus]="isElementWasAdded && $index===0" [isFocus]="isElementWasAdded && $index === 0"
[note]="note" [note]="note"
></note> ></note>
</div> </div>
} }
<!----> <!---->
@if(notes?.length === 0) { @if (notes?.length === 0) {
<div class="no-notes-info">{{ T.F.NOTE.NOTES_CMP.NO_NOTES|translate }}</div> <div class="no-notes-info">{{ T.F.NOTE.NOTES_CMP.NO_NOTES | translate }}</div>
} }
</div> </div>

View file

@ -1,19 +1,20 @@
@if (!isShowAddTask) { @if (!isShowAddTask) {
<div <div
style="text-align: center" style="text-align: center"
(click)="isShowAddTask = true" (click)="isShowAddTask = true"
> >
<button mat-button> <button mat-button>
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
{{ T.G.ADD|translate }} {{ T.G.ADD | translate }}
</button> </button>
</div> </div>
} @if (isShowAddTask) { }
<add-task-bar @if (isShowAddTask) {
[isElevated]="true " <add-task-bar
[isHideTagTitles]="true " [isElevated]="true"
(blurred)="isShowAddTask = false" [isHideTagTitles]="true"
(done)="isShowAddTask = false" (blurred)="isShowAddTask = false"
[planForDay]="planForDay()" (done)="isShowAddTask = false"
></add-task-bar> [planForDay]="planForDay()"
></add-task-bar>
} }

View file

@ -19,22 +19,23 @@
* schedule tasks need to be indicated * schedule tasks need to be indicated
--> -->
@if (filteredTasks$|async; as allTasks) { @if (filteredTasks$ | async; as allTasks) {
<div <div
class="tasks" class="tasks"
cdkDropList cdkDropList
cdkDropListSortingDisabled cdkDropListSortingDisabled
[cdkDropListData]="ADD_TASK_PANEL " [cdkDropListData]="ADD_TASK_PANEL"
(cdkDropListDropped)="drop($event)" (cdkDropListDropped)="drop($event)"
> >
@for (task of allTasks; track task.id) { @for (task of allTasks; track task.id) {
<planner-task <planner-task
cdkDrag cdkDrag
[cdkDragData]="task" [cdkDragData]="task"
[task]="task" [task]="task"
></planner-task> ></planner-task>
} @if (allTasks.length === 0) { }
<div class="empty">{{ T.F.PLANNER.NO_TASKS|translate }}</div> @if (allTasks.length === 0) {
} <div class="empty">{{ T.F.PLANNER.NO_TASKS | translate }}</div>
</div> }
</div>
} }

View file

@ -2,88 +2,98 @@
mat-dialog-title mat-dialog-title
align="center" align="center"
> >
<span>{{ T.F.PLANNER.D.ADD_PLANNED.TITLE|translate }}</span> <span>{{ T.F.PLANNER.D.ADD_PLANNED.TITLE | translate }}</span>
</h1> </h1>
@if ((day$|async); as day) { @if (day$ | async; as day) {
<mat-dialog-content> <mat-dialog-content>
<header> <header>
<!--<div class="day-estimate">{{ day.timeEstimate |roundDuration|msToString }}</div>--> <!--<div class="day-estimate">{{ day.timeEstimate |roundDuration|msToString }}</div>-->
<div class="day-counts"> <div class="day-counts">
<span>{{ day.timeEstimate |roundDuration|msToString }}</span> <span>{{ day.timeEstimate | roundDuration | msToString }}</span>
@if (day.itemsTotal > 5 ) { @if (day.itemsTotal > 5) {
<mat-icon inline="true">task_alt</mat-icon> <mat-icon inline="true">task_alt</mat-icon>
<span>{{ day.itemsTotal }}</span> <span>{{ day.itemsTotal }}</span>
} }
</div> </div>
</header> </header>
<div class="normal-tasks"> <div class="normal-tasks">
<div class="normal-tasks-items"> <div class="normal-tasks-items">
@for (task of day.tasks; track task.id) { @for (task of day.tasks; track task.id) {
<planner-task <planner-task
[task]="task" [task]="task"
[day]="day.dayDate" [day]="day.dayDate"
></planner-task> ></planner-task>
}
<!-- -->
@for (repeatProjection of day.noStartTimeRepeatProjections; track
repeatProjection.id) {
<planner-repeat-projection
[repeatCfg]="repeatProjection.repeatCfg"
></planner-repeat-projection>
}
<!-- -->
@if (day.tasks.length === 0 && day.noStartTimeRepeatProjections.length === 0) {
<div class="empty">{{ T.F.PLANNER.NO_TASKS|translate }}</div>
}
</div>
<add-task-inline [planForDay]="day.dayDate"></add-task-inline>
</div>
<div class="scheduled">
<div class="section-title">
<mat-icon>alarm</mat-icon>
</div>
<div class="scheduled-items">
@for (scheduledItem of day.scheduledIItems; track scheduledItem.id) {
<div
class="scheduled-item"
[ngClass]="scheduledItem.type"
>
@if (scheduledItem.type === SCHEDULE_ITEM_TYPE.Task) {
<div
class="time"
(click)="editTaskReminderOrReScheduleIfPossible(scheduledItem.task)"
>
<span>{{ (scheduledItem.start|roundDuration|date:'HH:mm') }}</span>
<mat-icon>alarm</mat-icon>
</div>
} @else {
<div class="time">{{ (scheduledItem.start|roundDuration|date:'HH:mm') }}</div>
} }
<!-- --> <!-- -->
@switch (scheduledItem.type) { @case (SCHEDULE_ITEM_TYPE.Task) { @for (
<planner-task repeatProjection of day.noStartTimeRepeatProjections;
[task]="scheduledItem.task" track repeatProjection.id
[day]="day.dayDate" ) {
></planner-task> <planner-repeat-projection
} @case (SCHEDULE_ITEM_TYPE.CalEvent) { [repeatCfg]="repeatProjection.repeatCfg"
<planner-calendar-event ></planner-repeat-projection>
[calendarEvent]="scheduledItem.calendarEvent" }
></planner-calendar-event> <!-- -->
} @case (SCHEDULE_ITEM_TYPE.RepeatProjection) { @if (day.tasks.length === 0 && day.noStartTimeRepeatProjections.length === 0) {
<planner-repeat-projection <div class="empty">{{ T.F.PLANNER.NO_TASKS | translate }}</div>
[repeatCfg]="scheduledItem.repeatCfg" }
></planner-repeat-projection>
} }
</div> </div>
} <add-task-inline [planForDay]="day.dayDate"></add-task-inline>
<!-- -->
@if (day.scheduledIItems.length === 0) {
<div class="empty">{{ T.F.PLANNER.PLAN_VIEW.NO_SCHEDULED_ITEMS|translate }}</div>
}
</div> </div>
</div> <div class="scheduled">
</mat-dialog-content> <div class="section-title">
<mat-icon>alarm</mat-icon>
</div>
<div class="scheduled-items">
@for (scheduledItem of day.scheduledIItems; track scheduledItem.id) {
<div
class="scheduled-item"
[ngClass]="scheduledItem.type"
>
@if (scheduledItem.type === SCHEDULE_ITEM_TYPE.Task) {
<div
class="time"
(click)="editTaskReminderOrReScheduleIfPossible(scheduledItem.task)"
>
<span>{{ scheduledItem.start | roundDuration | date: 'HH:mm' }}</span>
<mat-icon>alarm</mat-icon>
</div>
} @else {
<div class="time">
{{ scheduledItem.start | roundDuration | date: 'HH:mm' }}
</div>
}
<!-- -->
@switch (scheduledItem.type) {
@case (SCHEDULE_ITEM_TYPE.Task) {
<planner-task
[task]="scheduledItem.task"
[day]="day.dayDate"
></planner-task>
}
@case (SCHEDULE_ITEM_TYPE.CalEvent) {
<planner-calendar-event
[calendarEvent]="scheduledItem.calendarEvent"
></planner-calendar-event>
}
@case (SCHEDULE_ITEM_TYPE.RepeatProjection) {
<planner-repeat-projection
[repeatCfg]="scheduledItem.repeatCfg"
></planner-repeat-projection>
}
}
</div>
}
<!-- -->
@if (day.scheduledIItems.length === 0) {
<div class="empty">
{{ T.F.PLANNER.PLAN_VIEW.NO_SCHEDULED_ITEMS | translate }}
</div>
}
</div>
</div>
</mat-dialog-content>
} }
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
@ -93,7 +103,7 @@
mat-button mat-button
type="button" type="button"
> >
{{ T.G.DISMISS|translate }} {{ T.G.DISMISS | translate }}
</button> </button>
<button <button
@ -102,6 +112,6 @@
(click)="addTasksToToday()" (click)="addTasksToToday()"
> >
<mat-icon>wb_sunny</mat-icon> <mat-icon>wb_sunny</mat-icon>
{{ T.F.PLANNER.D.ADD_PLANNED.ADD_TO_TODAY|translate }} {{ T.F.PLANNER.D.ADD_PLANNED.ADD_TO_TODAY | translate }}
</button> </button>
</mat-dialog-actions> </mat-dialog-actions>

View file

@ -6,44 +6,44 @@
<!-- >--> <!-- >-->
<!-- <mat-icon>history</mat-icon>--> <!-- <mat-icon>history</mat-icon>-->
<!-- </button>--> <!-- </button>-->
@if(isShowRemoveFromToday()){ @if (isShowRemoveFromToday()) {
<button <button
mat-icon-button mat-icon-button
(click)="quickAccessBtnClick(0)" (click)="quickAccessBtnClick(0)"
[matTooltip]="(T.F.TASK.D_SCHEDULE_TASK.QA_REMOVE_TODAY|translate)" [matTooltip]="T.F.TASK.D_SCHEDULE_TASK.QA_REMOVE_TODAY | translate"
> >
<mat-icon svgIcon="remove_today"></mat-icon> <mat-icon svgIcon="remove_today"></mat-icon>
</button> </button>
} }
<!-- --> <!-- -->
@if(isShowAddToToday()){ @if (isShowAddToToday()) {
<button <button
mat-icon-button mat-icon-button
(click)="quickAccessBtnClick(1)" (click)="quickAccessBtnClick(1)"
[matTooltip]="(T.F.TASK.D_SCHEDULE_TASK.QA_TODAY|translate)" [matTooltip]="T.F.TASK.D_SCHEDULE_TASK.QA_TODAY | translate"
> >
<mat-icon>wb_sunny</mat-icon> <mat-icon>wb_sunny</mat-icon>
</button> </button>
} }
<button <button
mat-icon-button mat-icon-button
(click)="quickAccessBtnClick(2)" (click)="quickAccessBtnClick(2)"
[matTooltip]="(T.F.TASK.D_SCHEDULE_TASK.QA_TOMORROW|translate)" [matTooltip]="T.F.TASK.D_SCHEDULE_TASK.QA_TOMORROW | translate"
> >
<mat-icon svgIcon="tomorrow"></mat-icon> <mat-icon svgIcon="tomorrow"></mat-icon>
</button> </button>
<button <button
mat-icon-button mat-icon-button
(click)="quickAccessBtnClick(3)" (click)="quickAccessBtnClick(3)"
[matTooltip]="(T.F.TASK.D_SCHEDULE_TASK.QA_NEXT_WEEK|translate)" [matTooltip]="T.F.TASK.D_SCHEDULE_TASK.QA_NEXT_WEEK | translate"
> >
<mat-icon svgIcon="next_week"></mat-icon> <mat-icon svgIcon="next_week"></mat-icon>
</button> </button>
<button <button
mat-icon-button mat-icon-button
(click)="quickAccessBtnClick(4)" (click)="quickAccessBtnClick(4)"
[matTooltip]="(T.F.TASK.D_SCHEDULE_TASK.QA_NEXT_MONTH|translate)" [matTooltip]="T.F.TASK.D_SCHEDULE_TASK.QA_NEXT_MONTH | translate"
> >
<mat-icon>bedtime</mat-icon> <mat-icon>bedtime</mat-icon>
</button> </button>
@ -58,12 +58,12 @@
></mat-calendar> ></mat-calendar>
@if (isShowEnterMsg) { @if (isShowEnterMsg) {
<div <div
class="press-enter-msg" class="press-enter-msg"
@fade @fade
> >
{{ T.DATETIME_SCHEDULE.PRESS_ENTER_AGAIN|translate }} {{ T.DATETIME_SCHEDULE.PRESS_ENTER_AGAIN | translate }}
</div> </div>
} }
<div class="form-ctrl-wrapper"> <div class="form-ctrl-wrapper">
@ -79,31 +79,31 @@
(keydown)="onTimeKeyDown($event)" (keydown)="onTimeKeyDown($event)"
/> />
@if (selectedTime) { @if (selectedTime) {
<mat-icon <mat-icon
style="cursor: pointer" style="cursor: pointer"
matSuffix matSuffix
(click)="onTimeClear($event)" (click)="onTimeClear($event)"
>close >close
</mat-icon> </mat-icon>
} }
</mat-form-field> </mat-form-field>
@if (selectedTime) { @if (selectedTime) {
<mat-form-field [@expandFade]> <mat-form-field [@expandFade]>
<mat-icon matPrefix>alarm</mat-icon> <mat-icon matPrefix>alarm</mat-icon>
<mat-label>{{ (T.F.TASK.D_SCHEDULE_TASK.REMIND_AT|translate) }}</mat-label> <mat-label>{{ T.F.TASK.D_SCHEDULE_TASK.REMIND_AT | translate }}</mat-label>
<mat-select <mat-select
[(ngModel)]="selectedReminderCfgId" [(ngModel)]="selectedReminderCfgId"
name="type" name="type"
required="true" required="true"
> >
@for (remindOption of remindAvailableOptions; track remindOption.value) { @for (remindOption of remindAvailableOptions; track remindOption.value) {
<mat-option [value]="remindOption.value"> <mat-option [value]="remindOption.value">
{{ (remindOption.label|translate) }} {{ remindOption.label | translate }}
</mat-option> </mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
} }
</div> </div>
@ -114,20 +114,21 @@
type="button" type="button"
(click)="close()" (click)="close()"
> >
{{ T.G.CANCEL|translate }} {{ T.G.CANCEL | translate }}
</button> </button>
@if (data.task.plannedAt || (plannedDayForTask && plannedDayForTask !== todayStr)) { @if (data.task.plannedAt || (plannedDayForTask && plannedDayForTask !== todayStr)) {
<button <button
(click)="remove()" (click)="remove()"
color="warn" color="warn"
mat-stroked-button mat-stroked-button
> >
@if (selectedTime) { @if (selectedTime) {
<mat-icon>alarm_off</mat-icon> <mat-icon>alarm_off</mat-icon>
} @else { } @else {
<mat-icon>event_busy</mat-icon> <mat-icon>event_busy</mat-icon>
} {{ T.F.TASK.D_SCHEDULE_TASK.UNSCHEDULE|translate }} }
</button> {{ T.F.TASK.D_SCHEDULE_TASK.UNSCHEDULE | translate }}
</button>
} }
<button <button
@ -136,9 +137,10 @@
(click)="submit()" (click)="submit()"
> >
@if (selectedTime) { @if (selectedTime) {
<mat-icon>alarm</mat-icon> <mat-icon>alarm</mat-icon>
} @else { } @else {
<mat-icon>today</mat-icon> <mat-icon>today</mat-icon>
} {{ T.F.TASK.D_SCHEDULE_TASK.SCHEDULE|translate }} }
{{ T.F.TASK.D_SCHEDULE_TASK.SCHEDULE | translate }}
</button> </button>
</mat-dialog-actions> </mat-dialog-actions>

View file

@ -4,4 +4,6 @@
{{ calendarEvent().title }} {{ calendarEvent().title }}
<!-- {{event.start|date:'HH:mm'}} {{(event.start + event.duration)|date:'HH:mm'}}--> <!-- {{event.start|date:'HH:mm'}} {{(event.start + event.duration)|date:'HH:mm'}}-->
</div> </div>
<div class="planner-time-remaining-shared">{{ calendarEvent().duration|msToString }}</div> <div class="planner-time-remaining-shared">
{{ calendarEvent().duration | msToString }}
</div>

View file

@ -1,18 +1,19 @@
<header> <header>
<div class="day-title"> <div class="day-title">
@if (day.isToday) { @if (day.isToday) {
<mat-icon inline="true">wb_sunny</mat-icon> <mat-icon inline="true">wb_sunny</mat-icon>
} {{ day.dayDate|date:'EEE' }} }
<span class="date">{{ day.dayDate|shortDate2 }}</span> {{ day.dayDate | date: 'EEE' }}
<span class="date">{{ day.dayDate | shortDate2 }}</span>
</div> </div>
<!--<div class="day-estimate">{{ day.timeEstimate |roundDuration|msToString }}</div>--> <!--<div class="day-estimate">{{ day.timeEstimate |roundDuration|msToString }}</div>-->
<div class="day-counts"> <div class="day-counts">
<span>{{ day.timeEstimate |roundDuration|msToString }}</span> <span>{{ day.timeEstimate | roundDuration | msToString }}</span>
@if (day.itemsTotal > 5 ) { @if (day.itemsTotal > 5) {
<mat-icon inline="true">task_alt</mat-icon> <mat-icon inline="true">task_alt</mat-icon>
<span>{{ day.itemsTotal }}</span> <span>{{ day.itemsTotal }}</span>
} }
</div> </div>
</header> </header>
@ -25,25 +26,27 @@
(cdkDropListDropped)="drop('TODO', day.tasks, $event)" (cdkDropListDropped)="drop('TODO', day.tasks, $event)"
> >
@for (task of day.tasks; track task.id) { @for (task of day.tasks; track task.id) {
<planner-task <planner-task
cdkDrag cdkDrag
[cdkDragData]="task" [cdkDragData]="task"
[task]="task" [task]="task"
[day]="day.dayDate" [day]="day.dayDate"
></planner-task> ></planner-task>
} }
<!-- --> <!-- -->
@for (repeatProjection of day.noStartTimeRepeatProjections; track repeatProjection.id) @for (
{ repeatProjection of day.noStartTimeRepeatProjections;
<planner-repeat-projection track repeatProjection.id
[repeatCfg]="repeatProjection.repeatCfg" ) {
></planner-repeat-projection> <planner-repeat-projection
[repeatCfg]="repeatProjection.repeatCfg"
></planner-repeat-projection>
} }
<!-- --> <!-- -->
@if (day.tasks.length === 0 && day.noStartTimeRepeatProjections.length === 0) { @if (day.tasks.length === 0 && day.noStartTimeRepeatProjections.length === 0) {
<div class="empty">{{ T.F.PLANNER.NO_TASKS|translate }}</div> <div class="empty">{{ T.F.PLANNER.NO_TASKS | translate }}</div>
} }
</div> </div>
@ -63,51 +66,55 @@
(cdkDropListDropped)="drop('SCHEDULED', day.scheduledIItems, $event)" (cdkDropListDropped)="drop('SCHEDULED', day.scheduledIItems, $event)"
> >
@for (scheduledItem of day.scheduledIItems; track scheduledItem.id) { @for (scheduledItem of day.scheduledIItems; track scheduledItem.id) {
<div
class="scheduled-item"
[ngClass]="scheduledItem.type"
>
@if (scheduledItem.type === SCHEDULE_ITEM_TYPE.Task) {
<div <div
class="time" class="scheduled-item"
(click)="editTaskReminderOrReScheduleIfPossible(scheduledItem.task)" [ngClass]="scheduledItem.type"
> >
<span @if (scheduledItem.type === SCHEDULE_ITEM_TYPE.Task) {
class="time-time" <div
[innerHTML]="scheduledItem.start|roundDuration|shortTime2" class="time"
></span> (click)="editTaskReminderOrReScheduleIfPossible(scheduledItem.task)"
<mat-icon>alarm</mat-icon> >
</div> <span
} @else { class="time-time"
<div [innerHTML]="scheduledItem.start | roundDuration | shortTime2"
class="time time-time" ></span>
[innerHTML]="scheduledItem.start|roundDuration|shortTime2" <mat-icon>alarm</mat-icon>
></div> </div>
} } @else {
<div
class="time time-time"
[innerHTML]="scheduledItem.start | roundDuration | shortTime2"
></div>
}
<!-- --> <!-- -->
@switch (scheduledItem.type) { @case (SCHEDULE_ITEM_TYPE.Task) { @switch (scheduledItem.type) {
<planner-task @case (SCHEDULE_ITEM_TYPE.Task) {
cdkDrag <planner-task
[task]="scheduledItem.task" cdkDrag
[day]="day.dayDate" [task]="scheduledItem.task"
[cdkDragData]="scheduledItem.task" [day]="day.dayDate"
></planner-task> [cdkDragData]="scheduledItem.task"
} @case (SCHEDULE_ITEM_TYPE.CalEvent) { ></planner-task>
<planner-calendar-event }
[calendarEvent]="scheduledItem.calendarEvent" @case (SCHEDULE_ITEM_TYPE.CalEvent) {
></planner-calendar-event> <planner-calendar-event
} @case (SCHEDULE_ITEM_TYPE.RepeatProjection) { [calendarEvent]="scheduledItem.calendarEvent"
<planner-repeat-projection ></planner-calendar-event>
[repeatCfg]="scheduledItem.repeatCfg" }
></planner-repeat-projection> @case (SCHEDULE_ITEM_TYPE.RepeatProjection) {
} } <planner-repeat-projection
</div> [repeatCfg]="scheduledItem.repeatCfg"
></planner-repeat-projection>
}
}
</div>
} }
<!-- --> <!-- -->
@if (day.scheduledIItems.length === 0) { @if (day.scheduledIItems.length === 0) {
<div class="empty">{{ T.F.PLANNER.PLAN_VIEW.NO_SCHEDULED_ITEMS|translate }}</div> <div class="empty">{{ T.F.PLANNER.PLAN_VIEW.NO_SCHEDULED_ITEMS | translate }}</div>
} }
</div> </div>
</div> </div>

View file

@ -1,5 +1,5 @@
<div class="days"> <div class="days">
@for (day of days$|async; track day.dayDate) { @for (day of days$ | async; track day.dayDate) {
<planner-day [day]="day"></planner-day> <planner-day [day]="day"></planner-day>
} }
</div> </div>

View file

@ -1,6 +1,8 @@
<div <div
(click)="editTaskRepeatCfg()" (click)="editTaskRepeatCfg()"
matTooltip="{{ T.F.PLANNER.EDIT_REPEATED_TASK|translate: {taskName: repeatCfg().title} }}" matTooltip="{{
T.F.PLANNER.EDIT_REPEATED_TASK | translate: { taskName: repeatCfg().title }
}}"
> >
<mat-icon svgIcon="repeat"></mat-icon> <mat-icon svgIcon="repeat"></mat-icon>
<div class="title"> <div class="title">
@ -8,11 +10,14 @@
<!-- {{event.start|date:'HH:mm'}} {{(event.start + event.duration)|date:'HH:mm'}}--> <!-- {{event.start|date:'HH:mm'}} {{(event.start + event.duration)|date:'HH:mm'}}-->
</div> </div>
<div class="planner-time-remaining-shared"> <div class="planner-time-remaining-shared">
@if (overWriteTimeEstimate() > 0) { {{ overWriteTimeEstimate()|msToString }} <br /> @if (overWriteTimeEstimate() > 0) {
<span class="original-time-remaining" {{ overWriteTimeEstimate() | msToString }} <br />
>({{ repeatCfg().defaultEstimate|msToString }})</span <span class="original-time-remaining"
> >({{ repeatCfg().defaultEstimate | msToString }})</span
<!--- --> >
} @else { {{ repeatCfg().defaultEstimate|msToString }} } <!--- -->
} @else {
{{ repeatCfg().defaultEstimate | msToString }}
}
</div> </div>
</div> </div>

View file

@ -6,28 +6,30 @@
svgIcon="drag_handle" svgIcon="drag_handle"
></mat-icon> ></mat-icon>
@if (isCurrent) { @if (isCurrent) {
<mat-icon class="play-icon-indicator">play_arrow </mat-icon> <mat-icon class="play-icon-indicator">play_arrow </mat-icon>
} }
<div class="type-ico-wrapper"> <div class="type-ico-wrapper">
@if (task.repeatCfgId) { @if (task.repeatCfgId) {
<div> <div>
@if (!isRepeatTaskCreatedToday) { @if (!isRepeatTaskCreatedToday) {
<div class="repeat-date-badge">{{ task.created|shortDate2 }}</div> <div class="repeat-date-badge">{{ task.created | shortDate2 }}</div>
} @if (task.repeatCfgId) { }
<mat-icon @if (task.repeatCfgId) {
[style.transform]="isCurrent ? 'scale(1.4)': ''" <mat-icon
svgIcon="repeat" [style.transform]="isCurrent ? 'scale(1.4)' : ''"
> svgIcon="repeat"
</mat-icon> >
} </mat-icon>
</div> }
} @if (task.issueId) { </div>
<div> }
@if (task.issuePoints) { @if (task.issueId) {
<div class="mini-badge bgc-primary">{{ task.issuePoints }}</div> <div>
} @if (task.issuePoints) {
<mat-icon [svgIcon]="task.issueType|issueIcon"></mat-icon> <div class="mini-badge bgc-primary">{{ task.issuePoints }}</div>
</div> }
<mat-icon [svgIcon]="task.issueType | issueIcon"></mat-icon>
</div>
} }
</div> </div>
</div> </div>
@ -40,7 +42,7 @@
> >
<div class="wrap"> <div class="wrap">
@if (parentTitle) { @if (parentTitle) {
<div class="parent-title">{{ parentTitle }}</div> <div class="parent-title">{{ parentTitle }}</div>
} }
<div class="title">{{ task.title }}</div> <div class="title">{{ task.title }}</div>
@ -60,15 +62,15 @@
class="planner-time-remaining-shared" class="planner-time-remaining-shared"
> >
@if (task.subTaskIds?.length) { @if (task.subTaskIds?.length) {
<mat-icon <mat-icon
svgIcon="estimate_remaining" svgIcon="estimate_remaining"
inline="true" inline="true"
></mat-icon> ></mat-icon>
} }
<inline-input <inline-input
(changed)="updateTimeEstimate( $event)" (changed)="updateTimeEstimate($event)"
[displayValue]="timeEstimate|msToString" [displayValue]="timeEstimate | msToString"
[type]="'duration'" [type]="'duration'"
[value]="timeEstimate" [value]="timeEstimate"
> >

View file

@ -37,27 +37,27 @@
</ng-container> </ng-container>
<ng-container better-drawer-side> <ng-container better-drawer-side>
<add-task-panel-planner (closePanel)="isPanelOpen=false"></add-task-panel-planner> <add-task-panel-planner (closePanel)="isPanelOpen = false"></add-task-panel-planner>
</ng-container> </ng-container>
</better-simple-drawer> </better-simple-drawer>
@if (!isPanelOpen) { @if (!isPanelOpen) {
<div class="fab-wrapper FAB-BTN"> <div class="fab-wrapper FAB-BTN">
<button <button
mat-fab mat-fab
class="show-xs-only" class="show-xs-only"
color="primary" color="primary"
(click)="layoutService.showAddTaskBar()" (click)="layoutService.showAddTaskBar()"
> >
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
</button> </button>
<button <button
mat-fab mat-fab
color="primary" color="primary"
matTooltip="{{T.F.PLANNER.TASK_DRAWER|translate}}" matTooltip="{{ T.F.PLANNER.TASK_DRAWER | translate }}"
(click)="isPanelOpen = true" (click)="isPanelOpen = true"
> >
<mat-icon>playlist_add</mat-icon> <mat-icon>playlist_add</mat-icon>
</button> </button>
</div> </div>
} }

View file

@ -1,18 +1,21 @@
<div mat-dialog-content> <div mat-dialog-content>
@if (!(isManualPauseWork$|async)) { @if (!(isManualPauseWork$ | async)) {
<div> <div>
<p <p
[innerHTML]="T.F.POMODORO.FINISH_SESSION_X|translate:{nr: (currentCycle$|async)}" [innerHTML]="
></p> T.F.POMODORO.FINISH_SESSION_X | translate: { nr: (currentCycle$ | async) }
<p>{{T.F.POMODORO.ENJOY_YOURSELF|translate}}</p> "
</div> ></p>
} @if ((isManualPauseWork$|async)) { <p>{{ T.F.POMODORO.ENJOY_YOURSELF | translate }}</p>
<div> </div>
<p>{{T.F.POMODORO.BREAK_IS_DONE|translate}}</p> }
</div> @if (isManualPauseWork$ | async) {
<div>
<p>{{ T.F.POMODORO.BREAK_IS_DONE | translate }}</p>
</div>
} }
<div class="timer">{{currentTime$|async|msToMinuteClockString}}</div> <div class="timer">{{ currentTime$ | async | msToMinuteClockString }}</div>
</div> </div>
<div <div
@ -24,35 +27,37 @@
color="primary" color="primary"
mat-button mat-button
> >
{{T.G.CLOSE|translate}} {{ T.G.CLOSE | translate }}
</button> </button>
@if ((isManualPauseBreak$|async)) { @if (isManualPauseBreak$ | async) {
<button <button
(click)="startBreak()" (click)="startBreak()"
color="primary" color="primary"
mat-stroked-button mat-stroked-button
> >
<mat-icon>free_breakfast</mat-icon> <mat-icon>free_breakfast</mat-icon>
<span>{{T.F.POMODORO.START_BREAK|translate}}</span> <span>{{ T.F.POMODORO.START_BREAK | translate }}</span>
</button> </button>
} @if (!(isManualPauseWork$|async)) { }
<button @if (!(isManualPauseWork$ | async)) {
(click)="nextSession(true)" <button
color="primary" (click)="nextSession(true)"
mat-stroked-button color="primary"
> mat-stroked-button
<mat-icon>skip_next</mat-icon> >
<span>{{T.F.POMODORO.SKIP_BREAK|translate}}</span> <mat-icon>skip_next</mat-icon>
</button> <span>{{ T.F.POMODORO.SKIP_BREAK | translate }}</span>
} @if ((isManualPauseWork$|async)) { </button>
<button }
(click)="nextSession()" @if (isManualPauseWork$ | async) {
color="primary" <button
mat-stroked-button (click)="nextSession()"
> color="primary"
<mat-icon>play_arrow</mat-icon> mat-stroked-button
{{T.F.POMODORO.BACK_TO_WORK|translate}} >
</button> <mat-icon>play_arrow</mat-icon>
{{ T.F.POMODORO.BACK_TO_WORK | translate }}
</button>
} }
</div> </div>

View file

@ -1,37 +1,41 @@
<div class="page-wrapper component-wrapper"> <div class="page-wrapper component-wrapper">
<h1 style="margin-top: 16px; text-align: center"> <h1 style="margin-top: 16px; text-align: center">
{{T.F.PROCRASTINATION.H1|translate}} {{ T.F.PROCRASTINATION.H1 | translate }}
</h1> </h1>
<mat-tab-group dynamicHeight> <mat-tab-group dynamicHeight>
<mat-tab [label]="T.F.PROCRASTINATION.INTRO.TITLE|translate"> <mat-tab [label]="T.F.PROCRASTINATION.INTRO.TITLE | translate">
<section class="tab-inner"> <section class="tab-inner">
<p>{{T.F.PROCRASTINATION.P1|translate}}</p> <p>{{ T.F.PROCRASTINATION.P1 | translate }}</p>
<p [innerHTML]="T.F.PROCRASTINATION.P2|translate"></p> <p [innerHTML]="T.F.PROCRASTINATION.P2 | translate"></p>
<div class="procrastination-graph"> <div class="procrastination-graph">
<div class="wrap"> <div class="wrap">
<div class="text-item">{{T.F.PROCRASTINATION.INTRO.FEAR|translate}}</div> <div class="text-item">{{ T.F.PROCRASTINATION.INTRO.FEAR | translate }}</div>
<div class="text-item">{{T.F.PROCRASTINATION.INTRO.AVOIDING|translate}}</div> <div class="text-item">
{{ T.F.PROCRASTINATION.INTRO.AVOIDING | translate }}
</div>
</div> </div>
<mat-icon>sync</mat-icon> <mat-icon>sync</mat-icon>
<div class="text-item">{{T.F.PROCRASTINATION.INTRO.STRESSED|translate}}</div> <div class="text-item">
{{ T.F.PROCRASTINATION.INTRO.STRESSED | translate }}
</div>
</div> </div>
</section> </section>
</mat-tab> </mat-tab>
<mat-tab [label]="T.F.PROCRASTINATION.CUR.TITLE|translate"> <mat-tab [label]="T.F.PROCRASTINATION.CUR.TITLE | translate">
<section class="tab-inner"> <section class="tab-inner">
<p>{{T.F.PROCRASTINATION.CUR.INTRO|translate}}</p> <p>{{ T.F.PROCRASTINATION.CUR.INTRO | translate }}</p>
<ul> <ul>
<li>{{T.F.PROCRASTINATION.CUR.L1|translate}}</li> <li>{{ T.F.PROCRASTINATION.CUR.L1 | translate }}</li>
<li>{{T.F.PROCRASTINATION.CUR.L2|translate}}</li> <li>{{ T.F.PROCRASTINATION.CUR.L2 | translate }}</li>
<li>{{T.F.PROCRASTINATION.CUR.L3|translate}}</li> <li>{{ T.F.PROCRASTINATION.CUR.L3 | translate }}</li>
<li>{{T.F.PROCRASTINATION.CUR.L4|translate}}</li> <li>{{ T.F.PROCRASTINATION.CUR.L4 | translate }}</li>
<li>{{T.F.PROCRASTINATION.CUR.L5|translate}}</li> <li>{{ T.F.PROCRASTINATION.CUR.L5 | translate }}</li>
</ul> </ul>
<h3>{{T.F.PROCRASTINATION.CUR.PROCRASTINATION_TRIGGERS_TITLE|translate}}</h3> <h3>{{ T.F.PROCRASTINATION.CUR.PROCRASTINATION_TRIGGERS_TITLE | translate }}</h3>
<p>{{T.F.PROCRASTINATION.CUR.PROCRASTINATION_TRIGGERS_TEXT|translate}}</p> <p>{{ T.F.PROCRASTINATION.CUR.PROCRASTINATION_TRIGGERS_TEXT | translate }}</p>
<!-- <mat-form-field>--> <!-- <mat-form-field>-->
<!-- <textarea matInput--> <!-- <textarea matInput-->
@ -60,50 +64,50 @@
</section> </section>
</mat-tab> </mat-tab>
<mat-tab [label]="T.F.PROCRASTINATION.COMP.TITLE|translate"> <mat-tab [label]="T.F.PROCRASTINATION.COMP.TITLE | translate">
<section class="tab-inner"> <section class="tab-inner">
<p>{{T.F.PROCRASTINATION.COMP.INTRO|translate}}</p> <p>{{ T.F.PROCRASTINATION.COMP.INTRO | translate }}</p>
<ul> <ul>
<li>{{T.F.PROCRASTINATION.COMP.L1|translate}}</li> <li>{{ T.F.PROCRASTINATION.COMP.L1 | translate }}</li>
<li>{{T.F.PROCRASTINATION.COMP.L2|translate}}</li> <li>{{ T.F.PROCRASTINATION.COMP.L2 | translate }}</li>
<li>{{T.F.PROCRASTINATION.COMP.L3|translate}}</li> <li>{{ T.F.PROCRASTINATION.COMP.L3 | translate }}</li>
<li>{{T.F.PROCRASTINATION.COMP.L4|translate}}</li> <li>{{ T.F.PROCRASTINATION.COMP.L4 | translate }}</li>
</ul> </ul>
<p [innerHTML]="T.F.PROCRASTINATION.COMP.OUTRO|translate"></p> <p [innerHTML]="T.F.PROCRASTINATION.COMP.OUTRO | translate"></p>
</section> </section>
</mat-tab> </mat-tab>
<mat-tab [label]="T.F.PROCRASTINATION.REFRAME.TITLE|translate"> <mat-tab [label]="T.F.PROCRASTINATION.REFRAME.TITLE | translate">
<section class="tab-inner"> <section class="tab-inner">
<p>{{T.F.PROCRASTINATION.REFRAME.INTRO|translate}}</p> <p>{{ T.F.PROCRASTINATION.REFRAME.INTRO | translate }}</p>
<mat-form-field> <mat-form-field>
<mat-label>{{T.F.PROCRASTINATION.REFRAME.TL1|translate}}</mat-label> <mat-label>{{ T.F.PROCRASTINATION.REFRAME.TL1 | translate }}</mat-label>
<textarea matInput></textarea> <textarea matInput></textarea>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>{{T.F.PROCRASTINATION.REFRAME.TL2|translate}}</mat-label> <mat-label>{{ T.F.PROCRASTINATION.REFRAME.TL2 | translate }}</mat-label>
<textarea matInput></textarea> <textarea matInput></textarea>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>{{T.F.PROCRASTINATION.REFRAME.TL3|translate}}</mat-label> <mat-label>{{ T.F.PROCRASTINATION.REFRAME.TL3 | translate }}</mat-label>
<textarea matInput></textarea> <textarea matInput></textarea>
</mat-form-field> </mat-form-field>
</section> </section>
</mat-tab> </mat-tab>
@if ((taskService.currentTaskOrCurrentParent$|async); as currentTask) { @if (taskService.currentTaskOrCurrentParent$ | async; as currentTask) {
<mat-tab [label]="T.F.PROCRASTINATION.SPLIT_UP.TITLE|translate"> <mat-tab [label]="T.F.PROCRASTINATION.SPLIT_UP.TITLE | translate">
<section class="tab-inner no-box"> <section class="tab-inner no-box">
<p>{{T.F.PROCRASTINATION.SPLIT_UP.INTRO|translate}}</p> <p>{{ T.F.PROCRASTINATION.SPLIT_UP.INTRO | translate }}</p>
<task [task]="currentTask"></task> <task [task]="currentTask"></task>
<p <p
[innerHTML]="T.F.PROCRASTINATION.SPLIT_UP.OUTRO|translate" [innerHTML]="T.F.PROCRASTINATION.SPLIT_UP.OUTRO | translate"
style="margin-top: 16px" style="margin-top: 16px"
></p> ></p>
</section> </section>
</mat-tab> </mat-tab>
} }
</mat-tab-group> </mat-tab-group>
@ -113,7 +117,7 @@
mat-flat-button mat-flat-button
(click)="backToWork()" (click)="backToWork()"
> >
{{T.F.PROCRASTINATION.BACK_TO_WORK|translate}} {{ T.F.PROCRASTINATION.BACK_TO_WORK | translate }}
</button> </button>
</div> </div>
</div> </div>

View file

@ -1,8 +1,9 @@
<h1 mat-dialog-title> <h1 mat-dialog-title>
@if (projectData.id) { @if (projectData.id) {
<span>{{T.F.PROJECT.D_CREATE.EDIT|translate}}</span> <span>{{ T.F.PROJECT.D_CREATE.EDIT | translate }}</span>
} @if (!projectData.id) { }
<span>{{T.F.PROJECT.D_CREATE.CREATE|translate}}</span> @if (!projectData.id) {
<span>{{ T.F.PROJECT.D_CREATE.CREATE | translate }}</span>
} }
</h1> </h1>
@ -30,7 +31,7 @@
mat-button mat-button
type="button" type="button"
> >
{{T.G.CANCEL|translate}} {{ T.G.CANCEL | translate }}
</button> </button>
<button <button
[disabled]="!formBasic.valid" [disabled]="!formBasic.valid"
@ -39,7 +40,7 @@
mat-stroked-button mat-stroked-button
type="submit" type="submit"
> >
{{T.G.SAVE|translate}} {{ T.G.SAVE | translate }}
</button> </button>
</div> </div>
</mat-dialog-actions> </mat-dialog-actions>

View file

@ -1,70 +1,82 @@
<h1>{{ T.F.QUICK_HISTORY.PAGE_TITLE|translate }}</h1> <h1>{{ T.F.QUICK_HISTORY.PAGE_TITLE | translate }}</h1>
<div <div
*ngIf="(worklogService.quickHistoryWeeks$|async) as weeks else spinner" *ngIf="worklogService.quickHistoryWeeks$ | async as weeks; else spinner"
[@fadeInSlow] [@fadeInSlow]
> >
<div <div
class="no-data" class="no-data"
*ngIf="weeks?.length===0" *ngIf="weeks?.length === 0"
> >
{{ T.F.QUICK_HISTORY.NO_DATA|translate }} {{ T.F.QUICK_HISTORY.NO_DATA | translate }}
</div> </div>
<div *ngFor="let week of weeks; let j = index;"> <div *ngFor="let week of weeks; let j = index">
<h2> <h2>
{{ T.F.QUICK_HISTORY.WEEK_TITLE|translate:{ nr: week.weekNr, timeSpent: {{
(week.timeSpent|msToString) } }} T.F.QUICK_HISTORY.WEEK_TITLE
| translate: { nr: week.weekNr, timeSpent: (week.timeSpent | msToString) }
}}
</h2> </h2>
<div class="days"> <div class="days">
<div <div
*ngFor="let day of week?.ent|keyvalue:sortDays trackBy: trackByDay; let i = index;" *ngFor="
let day of week?.ent | keyvalue: sortDays;
trackBy: trackByDay;
let i = index
"
class="day" class="day"
> >
<div class="material-table"> <div class="material-table">
<div <div
(click)="visibility[i+(j*100)]=!visibility[i+(j*100)];" (click)="visibility[i + j * 100] = !visibility[i + j * 100]"
class="caption" class="caption"
mat-ripple mat-ripple
> >
<div> <div>
<span <span
*ngIf="visibility[i+(j*100)]" *ngIf="visibility[i + j * 100]"
[@fade] [@fade]
>{{ T.F.WORKLOG.WEEK.TITLE|translate }}</span >{{ T.F.WORKLOG.WEEK.TITLE | translate }}</span
> >
</div> </div>
<div class="center-box"> <div class="center-box">
<div class="title"> <div class="title">
<h3 class="mat-h3">{{ day.value.dayStr }}</h3> <h3 class="mat-h3">{{ day.value.dayStr }}</h3>
<div <div
*ngIf="!visibility[i+(j*100)]" *ngIf="!visibility[i + j * 100]"
[@expandFade] [@expandFade]
class="icon-indicator-bar" class="icon-indicator-bar"
> >
<strong>∑ {{ day.value.timeSpent|msToClockString }}</strong> <strong>∑ {{ day.value.timeSpent | msToClockString }}</strong>
&nbsp; &nbsp;
<mat-icon>list</mat-icon> <mat-icon>list</mat-icon>
<strong>{{ day.value.logEntries.length }}</strong> <strong>{{ day.value.logEntries.length }}</strong>
<em *ngIf="day.value.workStart" <em *ngIf="day.value.workStart"
><span class="spacer"></span>{{ ><span class="spacer"></span
day.value.workStart|momentFormat:'HH:mm' }} - {{ >{{ day.value.workStart | momentFormat: 'HH:mm' }} -
day.value.workEnd|momentFormat:'HH:mm' }}</em {{ day.value.workEnd | momentFormat: 'HH:mm' }}</em
> >
<div class="simple-counter-items"> <div class="simple-counter-items">
<div <div
*ngFor="let sc of simpleCounterService.enabledSimpleCounters$|async" *ngFor="
let sc of simpleCounterService.enabledSimpleCounters$ | async
"
class="simple-counter-item" class="simple-counter-item"
> >
<mat-icon inline="true">{{ sc.icon }}</mat-icon> <mat-icon inline="true">{{ sc.icon }}</mat-icon>
@if(sc.type==='StopWatch') { @if (sc.type === 'StopWatch') {
<div class="count"> <div class="count">
{{ sc.countOnDay[day.value.dateStr] || 0|msToMinuteClockString }} {{
</div> sc.countOnDay[day.value.dateStr] || 0 | msToMinuteClockString
}}
</div>
} @else { } @else {
<div class="count">{{ sc.countOnDay[day.value.dateStr] || 0 }}</div> <div class="count">
{{ sc.countOnDay[day.value.dateStr] || 0 }}
</div>
} }
</div> </div>
</div> </div>
@ -73,7 +85,7 @@
</div> </div>
<div class="with-icon"> <div class="with-icon">
<mat-icon <mat-icon
*ngIf="visibility[i+(j*100)]" *ngIf="visibility[i + j * 100]"
[@fade] [@fade]
>timer >timer
</mat-icon> </mat-icon>
@ -81,12 +93,15 @@
</div> </div>
<table <table
*ngIf="visibility[i+(j*100)]" *ngIf="visibility[i + j * 100]"
[@expandFade] [@expandFade]
class="task-summary-table" class="task-summary-table"
> >
<tr <tr
*ngFor="let logEntry of filterWorklogDataForDay(day.value.logEntries); trackBy: trackByLogEntry;" *ngFor="
let logEntry of filterWorklogDataForDay(day.value.logEntries);
trackBy: trackByLogEntry
"
> >
<td <td
[class.isSubTask]="logEntry.task.parentId" [class.isSubTask]="logEntry.task.parentId"
@ -97,14 +112,20 @@
</td> </td>
<td class="worked"> <td class="worked">
<span <span
*ngIf="logEntry.task.subTaskIds && logEntry.task.subTaskIds.length>0" *ngIf="logEntry.task.subTaskIds && logEntry.task.subTaskIds.length > 0"
>∑ {{ logEntry.task.timeSpentOnDay[day.value.dateStr]|msToClockString >∑
{{
logEntry.task.timeSpentOnDay[day.value.dateStr] | msToClockString
}}</span }}</span
> >
<inline-input <inline-input
(changed)="updateTimeSpentTodayForTask(logEntry.task,day.value.dateStr, $event)" (changed)="
updateTimeSpentTodayForTask(logEntry.task, day.value.dateStr, $event)
"
*ngIf="!logEntry.task.subTaskIds || !logEntry.task.subTaskIds.length" *ngIf="!logEntry.task.subTaskIds || !logEntry.task.subTaskIds.length"
[displayValue]="logEntry.task.timeSpentOnDay[day.value.dateStr]|msToClockString" [displayValue]="
logEntry.task.timeSpentOnDay[day.value.dateStr] | msToClockString
"
[type]="'duration'" [type]="'duration'"
[value]="logEntry.task.timeSpentOnDay[day.value.dateStr]" [value]="logEntry.task.timeSpentOnDay[day.value.dateStr]"
> >

View file

@ -1,7 +1,7 @@
<better-drawer-container <better-drawer-container
(wasClosed)="close()" (wasClosed)="close()"
[isOpen]="isOpen$|async" [isOpen]="isOpen$ | async"
[isOver]="isAlwaysOver() || (layoutService.isRightPanelOver$|async)" [isOver]="isAlwaysOver() || (layoutService.isRightPanelOver$ | async)"
[sideWidth]="40" [sideWidth]="40"
> >
<ng-container better-drawer-content> <ng-container better-drawer-content>
@ -9,19 +9,21 @@
</ng-container> </ng-container>
<ng-container better-drawer-side> <ng-container better-drawer-side>
@let panelContent = panelContent$ |async; @let panelContent = panelContent$ | async;
<div class="right-panel"> <div class="right-panel">
@if (panelContent === 'ADD_TASK_PANEL') { @if (panelContent === 'ADD_TASK_PANEL') {
<issue-panel [@slideInFromRight]></issue-panel> <issue-panel [@slideInFromRight]></issue-panel>
} @if (panelContent === 'NOTES') { }
<notes [@slideInFromRight]></notes> @if (panelContent === 'NOTES') {
} @if (selectedTaskWithDelayForNone$|async; as selectedTaskWithDelayForNone) { <notes [@slideInFromRight]></notes>
<task-detail-panel }
[isOver]="isAlwaysOver() || (layoutService.isRightPanelOver$|async)" @if (selectedTaskWithDelayForNone$ | async; as selectedTaskWithDelayForNone) {
[@taskDetailPanelTaskChange]=" selectedTaskWithDelayForNone?.id" <task-detail-panel
[@.disabled]="isDisableTaskPanelAni" [isOver]="isAlwaysOver() || (layoutService.isRightPanelOver$ | async)"
[task]="selectedTaskWithDelayForNone" [@taskDetailPanelTaskChange]="selectedTaskWithDelayForNone?.id"
></task-detail-panel> [@.disabled]="isDisableTaskPanelAni"
[task]="selectedTaskWithDelayForNone"
></task-detail-panel>
} }
</div> </div>
</ng-container> </ng-container>

View file

@ -3,21 +3,21 @@
(click)="isForDayMode.set(!isForDayMode())" (click)="isForDayMode.set(!isForDayMode())"
> >
@if (!isForDayMode()) { @if (!isForDayMode()) {
<mat-icon>alarm</mat-icon> <mat-icon>alarm</mat-icon>
<span [innerHTML]="plannedAt()|shortTime2"></span> <span [innerHTML]="plannedAt() | shortTime2"></span>
<!----> <!---->
} @else { } @else {
<mat-icon>today</mat-icon> <mat-icon>today</mat-icon>
<span>{{ date()|date:'shortDate' }} </span> <span>{{ date() | date: 'shortDate' }} </span>
<!----> <!---->
} }
</div> </div>
@if (!isEditMode()) { @if (!isEditMode()) {
<div class="msg"> <div class="msg">
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
click to create task click to create task
</div> </div>
} }
<textarea <textarea

View file

@ -1,29 +1,30 @@
<h1 mat-dialog-title> <h1 mat-dialog-title>
<mat-icon>calendar_view_week</mat-icon> <mat-icon>calendar_view_week</mat-icon>
<span style="margin-left: 8px">{{ T.F.SCHEDULE.D_INITIAL.TITLE|translate }}</span> <span style="margin-left: 8px">{{ T.F.SCHEDULE.D_INITIAL.TITLE | translate }}</span>
</h1> </h1>
<form <form
(submit)="$event.preventDefault();saveAndClose()" (submit)="$event.preventDefault(); saveAndClose()"
[formGroup]="formGroup" [formGroup]="formGroup"
> >
<mat-dialog-content> <mat-dialog-content>
@if (data?.isInfoShownInitially) { @if (data?.isInfoShownInitially) {
<div
class="text"
[innerHTML]="T.F.SCHEDULE.D_INITIAL.TEXT|translate"
></div>
} @if (!data?.isInfoShownInitially) {
<help-section>
<div <div
[innerHTML]="T.F.SCHEDULE.D_INITIAL.TEXT|translate" class="text"
class="side-info" [innerHTML]="T.F.SCHEDULE.D_INITIAL.TEXT | translate"
></div> ></div>
</help-section> }
@if (!data?.isInfoShownInitially) {
<help-section>
<div
[innerHTML]="T.F.SCHEDULE.D_INITIAL.TEXT | translate"
class="side-info"
></div>
</help-section>
} }
<formly-form <formly-form
(modelChange)="timelineCfg=$event" (modelChange)="timelineCfg = $event"
[fields]="formConfig" [fields]="formConfig"
[form]="formGroup" [form]="formGroup"
[model]="timelineCfg" [model]="timelineCfg"
@ -38,7 +39,7 @@
mat-button mat-button
type="button" type="button"
> >
{{T.G.CANCEL|translate}} {{ T.G.CANCEL | translate }}
</button> </button>
<button <button
@ -48,7 +49,7 @@
type="submit" type="submit"
> >
<mat-icon>save</mat-icon> <mat-icon>save</mat-icon>
{{T.G.SAVE|translate}} {{ T.G.SAVE | translate }}
</button> </button>
</mat-dialog-actions> </mat-dialog-actions>
</form> </form>

View file

@ -1,46 +1,52 @@
<div class="ico-wrapper"> <div class="ico-wrapper">
@switch (icoType) { @switch (icoType) {
<!-- --> <!-- -->
@case ('REPEAT') { @case ('REPEAT') {
<mat-icon <mat-icon
svgIcon="repeat" svgIcon="repeat"
class="ico" class="ico"
inline="true" inline="true"
></mat-icon> ></mat-icon>
} @case ('PLANNED_FOR_DAY') { }
<div class="day-of-month">{{ se.dayOfMonth }}</div> @case ('PLANNED_FOR_DAY') {
} @case ('SCHEDULED_TASK') { <div class="day-of-month">{{ se.dayOfMonth }}</div>
<mat-icon }
class="ico" @case ('SCHEDULED_TASK') {
inline="true" <mat-icon
>alarm class="ico"
</mat-icon> inline="true"
} @case ('FLOW') { >alarm
<!--<div class="fake-ico">~</div>--> </mat-icon>
<mat-icon }
class="ico" @case ('FLOW') {
inline="true" <!--<div class="fake-ico">~</div>-->
>wb_sunny <mat-icon
</mat-icon> class="ico"
} @case ('LUNCH_BREAK') { inline="true"
<mat-icon >wb_sunny
class="ico" </mat-icon>
inline="true" }
>restaurant @case ('LUNCH_BREAK') {
</mat-icon> <mat-icon
} @case ('CAL_PROJECTION') { class="ico"
<mat-icon>{{ $any(se.data)?.icon || 'event' }}</mat-icon> inline="true"
<mat-icon>add</mat-icon> >restaurant
} </mat-icon>
<!--- ---> }
@default { } @case ('CAL_PROJECTION') {
<!--- ---> <mat-icon>{{ $any(se.data)?.icon || 'event' }}</mat-icon>
<mat-icon>add</mat-icon>
}
<!--- --->
@default {}
<!--- --->
} }
<!--- --> <!--- -->
@if (se.type === SVEType.ScheduledTask || se.type === SVEType.ScheduledRepeatProjection) @if (
{ se.type === SVEType.ScheduledTask || se.type === SVEType.ScheduledRepeatProjection
<div class="time-badge">{{ scheduledClockStr }}</div> ) {
<div class="time-badge">{{ scheduledClockStr }}</div>
} }
</div> </div>
<!-- --> <!-- -->
@ -51,16 +57,22 @@
<!-- {{se.id}} __ {{se.data?.id}} __--> <!-- {{se.id}} __ {{se.data?.id}} __-->
<!-- --> <!-- -->
@if (se.type === SVEType.SplitTaskContinuedLast || se.type === @if (
SVEType.SplitTaskContinued || se.type === SVEType.RepeatProjectionSplitContinued || se.type === SVEType.SplitTaskContinuedLast ||
se.type === SVEType.RepeatProjectionSplitContinuedLast) { ... se.type === SVEType.SplitTaskContinued ||
<!-- --> se.type === SVEType.RepeatProjectionSplitContinued ||
} @else { {{ title }} } se.type === SVEType.RepeatProjectionSplitContinuedLast
) {
...
<!-- -->
} @else {
{{ title }}
}
</div> </div>
@if (task) { @if (task) {
<task-context-menu <task-context-menu
#taskContextMenu #taskContextMenu
[task]="task" [task]="task"
></task-context-menu> ></task-context-menu>
} }

View file

@ -38,13 +38,13 @@
<div class="filler"><!--for time --></div> <div class="filler"><!--for time --></div>
@for (day of daysToShow; track $index) { @for (day of daysToShow; track $index) {
<div class="day"> <div class="day">
@if ($index === 0) { @if ($index === 0) {
<mat-icon>wb_sunny</mat-icon> <mat-icon>wb_sunny</mat-icon>
} }
<div class="day-num">{{ day|date:'d' }}</div> <div class="day-num">{{ day | date: 'd' }}</div>
<div class="day-day">{{ day|date:'EEE' }}</div> <div class="day-day">{{ day | date: 'EEE' }}</div>
</div> </div>
} }
</div> </div>
</header> </header>
@ -52,130 +52,141 @@
<!--<div class="outer-container">--> <!--<div class="outer-container">-->
<div <div
#gridContainer #gridContainer
class="main-grid-container {{containerExtraClass}}" class="main-grid-container {{ containerExtraClass }}"
[class.isCtrlKeyPressed]="shortcutService.isCtrlPressed$|async" [class.isCtrlKeyPressed]="shortcutService.isCtrlPressed$ | async"
(click)="onGridClick($event)" (click)="onGridClick($event)"
(mousemove)="onMoveOverGrid($event)" (mousemove)="onMoveOverGrid($event)"
> >
<!-- Time --> <!-- Time -->
@for (time of times; track $index) { @for (time of times; track $index) {
<div <div
class="time" class="time"
style="grid-row: {{ $index *FH + 1 }}" style="grid-row: {{ $index * FH + 1 }}"
> >
{{ time }} {{ time }}
</div> </div>
} }
<!-- Grid Rows --> <!-- Grid Rows -->
@for (row of rowsByNr; track $index) { @for (row of rowsByNr; track $index) {
<div <div
class="row" class="row"
style="grid-row: {{ row + 1 }}" style="grid-row: {{ row + 1 }}"
></div> ></div>
} }
<!-- Grid Cols --> <!-- Grid Cols -->
@for (day of daysToShow; track $index) { @for (day of daysToShow; track $index) {
<div <div
class="col" class="col"
[attr.data-day]="day" [attr.data-day]="day"
style="grid-column: {{ $index + 2 }}; grid-row: 1 / span {{($index === 0 ? currentTimeRow :endOfDayColRowStart) -1}}" style="grid-column: {{ $index + 2 }}; grid-row: 1 / span {{
> ($index === 0 ? currentTimeRow : endOfDayColRowStart) - 1
<div class="drop-label">{{ T.F.SCHEDULE.PLAN_START_DAY|translate }}</div> }}"
</div> >
<div <div class="drop-label">{{ T.F.SCHEDULE.PLAN_START_DAY | translate }}</div>
class="col end-of-day" </div>
[attr.data-day]="day" <div
style="grid-column: {{ $index + 2 }}; grid-row: {{($index === 0 ? currentTimeRow :endOfDayColRowStart)}} / span {{totalRows - ($index === 0 ? currentTimeRow :endOfDayColRowStart)}}" class="col end-of-day"
> [attr.data-day]="day"
<div class="drop-label">{{ T.F.SCHEDULE.PLAN_END_DAY|translate }}</div> style="grid-column: {{ $index + 2 }}; grid-row: {{
</div> $index === 0 ? currentTimeRow : endOfDayColRowStart
}} / span {{ totalRows - ($index === 0 ? currentTimeRow : endOfDayColRowStart) }}"
>
<div class="drop-label">{{ T.F.SCHEDULE.PLAN_END_DAY | translate }}</div>
</div>
} }
<!-- Work Start and End --> <!-- Work Start and End -->
@if (workStartEnd) { @if (workStartEnd) {
<div <div
class="work-start" class="work-start"
style="grid-row: {{workStartEnd.workStartRow}}" style="grid-row: {{ workStartEnd.workStartRow }}"
> >
<div>{{ T.F.SCHEDULE.START|translate }}</div> <div>{{ T.F.SCHEDULE.START | translate }}</div>
</div> </div>
<div <div
class="work-end" class="work-end"
style="grid-row: {{workStartEnd.workEndRow}}" style="grid-row: {{ workStartEnd.workEndRow }}"
> >
<div>{{ T.F.SCHEDULE.END|translate }}</div> <div>{{ T.F.SCHEDULE.END | translate }}</div>
</div> </div>
} }
<!-- Events --> <!-- Events -->
@for (ev of (events$|async); track ev.id) { @for (ev of events$ | async; track ev.id) {
<!-- --> <!-- -->
@if (ev.type === SVEType.Task || ev.type === SVEType.SplitTask || ev.type === @if (
SVEType.TaskPlannedForDay || ev.type === SVEType.SplitTaskPlannedForDay) { ev.type === SVEType.Task ||
<schedule-event ev.type === SVEType.SplitTask ||
class="draggable" ev.type === SVEType.TaskPlannedForDay ||
cdkDrag ev.type === SVEType.SplitTaskPlannedForDay
[cdkDragData]="ev" ) {
(cdkDragMoved)="dragMoved($event)" <schedule-event
(cdkDragStarted)="dragStarted($event)" class="draggable"
(cdkDragReleased)="dragReleased($event)" cdkDrag
[cdkDragStartDelay]="IS_TOUCH_PRIMARY ? 75 : 0" [cdkDragData]="ev"
[event]="ev" (cdkDragMoved)="dragMoved($event)"
></schedule-event> (cdkDragStarted)="dragStarted($event)"
} @else { (cdkDragReleased)="dragReleased($event)"
<schedule-event [event]="ev"></schedule-event> [cdkDragStartDelay]="IS_TOUCH_PRIMARY ? 75 : 0"
} } [event]="ev"
></schedule-event>
} @else {
<schedule-event [event]="ev"></schedule-event>
}
}
<!-- Excess tasks planned for day --> <!-- Excess tasks planned for day -->
@for (beyondBudgetDay of (beyondBudget$|async); track i; let i = $index) { @for (beyondBudgetDay of beyondBudget$ | async; track i; let i = $index) {
<!-- --> <!-- -->
@if (beyondBudgetDay.length > 0) { @if (beyondBudgetDay.length > 0) {
<div <div
class="excess-entries" class="excess-entries"
style="grid-column: {{i + 2}}" style="grid-column: {{ i + 2 }}"
> >
<div <div
class="excess-entries-header" class="excess-entries-header"
[matTooltipPosition]="'above'" [matTooltipPosition]="'above'"
[matTooltip]="'Tasks planned for day, but that are beyond the available time budget'" [matTooltip]="
> 'Tasks planned for day, but that are beyond the available time budget'
<mat-icon>hourglass_disabled</mat-icon> "
{{ beyondBudgetDay.length }} >
</div> <mat-icon>hourglass_disabled</mat-icon>
@for (ev of beyondBudgetDay; track ev.id) { {{ beyondBudgetDay.length }}
<schedule-event </div>
[event]="ev" @for (ev of beyondBudgetDay; track ev.id) {
class="draggable" <schedule-event
cdkDrag [event]="ev"
[cdkDragData]="ev" class="draggable"
(cdkDragMoved)="dragMoved($event)" cdkDrag
(cdkDragStarted)="dragStarted($event)" [cdkDragData]="ev"
(cdkDragReleased)="dragReleased($event)" (cdkDragMoved)="dragMoved($event)"
[cdkDragStartDelay]="IS_TOUCH_PRIMARY ? DRAG_DELAY_FOR_TOUCH : 0" (cdkDragStarted)="dragStarted($event)"
></schedule-event> (cdkDragReleased)="dragReleased($event)"
[cdkDragStartDelay]="IS_TOUCH_PRIMARY ? DRAG_DELAY_FOR_TOUCH : 0"
></schedule-event>
}
</div>
} }
</div> <!-- -->
}
<!-- -->
} }
<div <div
class="current-time" class="current-time"
style="grid-column: 2; grid-row: {{currentTimeRow}} / span 1" style="grid-column: 2; grid-row: {{ currentTimeRow }} / span 1"
> >
<div class="circle"></div> <div class="circle"></div>
</div> </div>
@if (newTaskPlaceholder$|async; as newTaskPlaceholder) { @if (newTaskPlaceholder$ | async; as newTaskPlaceholder) {
<create-task-placeholder <create-task-placeholder
[isEditMode]="isCreateTaskActive" [isEditMode]="isCreateTaskActive"
[time]="newTaskPlaceholder.time" [time]="newTaskPlaceholder.time"
[date]="newTaskPlaceholder.date" [date]="newTaskPlaceholder.date"
(editEnd)="isCreateTaskActive = false; this.newTaskPlaceholder$.next(null)" (editEnd)="isCreateTaskActive = false; this.newTaskPlaceholder$.next(null)"
[style]="newTaskPlaceholder.style" [style]="newTaskPlaceholder.style"
> >
</create-task-placeholder> </create-task-placeholder>
} }
</div> </div>
<!--</div>--> <!--</div>-->

View file

@ -5,10 +5,10 @@
class="search-form mat-elevation-z4" class="search-form mat-elevation-z4"
> >
<div class="input-wrapper"> <div class="input-wrapper">
@if ((isLoading$|async)) { @if (isLoading$ | async) {
<div class="spinner"> <div class="spinner">
<mat-spinner diameter="50"></mat-spinner> <mat-spinner diameter="50"></mat-spinner>
</div> </div>
} }
<mat-icon class="search-icon">search</mat-icon> <mat-icon class="search-icon">search</mat-icon>
<input <input
@ -17,7 +17,7 @@
(blur)="onBlur($event)" (blur)="onBlur($event)"
[formControl]="taskSuggestionsCtrl" [formControl]="taskSuggestionsCtrl"
[matAutocomplete]="autoEl" [matAutocomplete]="autoEl"
[placeholder]="(T.F.SEARCH_BAR.PLACEHOLDER|translate)" [placeholder]="T.F.SEARCH_BAR.PLACEHOLDER | translate"
matInput matInput
/> />
@ -33,8 +33,10 @@
<div class="info-bar"> <div class="info-bar">
<div class="info-text"> <div class="info-text">
{{ (!tooManyResults ? T.F.SEARCH_BAR.INFO : {{
T.F.SEARCH_BAR.TOO_MANY_RESULTS)|translate }} (!tooManyResults ? T.F.SEARCH_BAR.INFO : T.F.SEARCH_BAR.TOO_MANY_RESULTS)
| translate
}}
</div> </div>
</div> </div>
@ -44,22 +46,23 @@
autoActiveFirstOption autoActiveFirstOption
[displayWith]="getOptionText" [displayWith]="getOptionText"
> >
@for (item of (filteredIssueSuggestions$|async); track trackByFn($index, item)) { @for (item of filteredIssueSuggestions$ | async; track trackByFn($index, item)) {
<mat-option <mat-option
(click)="navigateToItem(item)" (click)="navigateToItem(item)"
class="search-mat-option" class="search-mat-option"
[value]="item" [value]="item"
> >
@if (item.ctx) { @if (item.ctx) {
<tag [tag]="item.ctx"></tag> <tag [tag]="item.ctx"></tag>
} }
<span>{{ item?.titleHighlighted || item?.title }}</span> <span>{{ item?.titleHighlighted || item?.title }}</span>
@if (item.issueType) { @if (item.issueType) {
<mat-icon [svgIcon]="item.issueType|issueIcon"></mat-icon> <mat-icon [svgIcon]="item.issueType | issueIcon"></mat-icon>
} @if (item.isArchiveTask) { }
<mat-icon>archive</mat-icon> @if (item.isArchiveTask) {
} <mat-icon>archive</mat-icon>
</mat-option> }
</mat-option>
} }
</mat-autocomplete> </mat-autocomplete>
</form> </form>

View file

@ -1,79 +1,84 @@
<form (submit)="$event.preventDefault();submit()"> <form (submit)="$event.preventDefault(); submit()">
<!-- <h1 mat-dialog-title>{{ T.F.SIMPLE_COUNTER.D_EDIT.TITLE|translate }}</h1>--> <!-- <h1 mat-dialog-title>{{ T.F.SIMPLE_COUNTER.D_EDIT.TITLE|translate }}</h1>-->
<h1 mat-dialog-title>{{ data.simpleCounter.title }}</h1> <h1 mat-dialog-title>{{ data.simpleCounter.title }}</h1>
<mat-dialog-content> <mat-dialog-content>
<!----> <!---->
@if (data.simpleCounter.isTrackStreaks) { @if (data.simpleCounter.isTrackStreaks) {
<section style="text-align: center; margin-bottom: 16px"> <section style="text-align: center; margin-bottom: 16px">
<div>{{T.F.SIMPLE_COUNTER.D_EDIT.CURRENT_STREAK|translate}}</div> <div>{{ T.F.SIMPLE_COUNTER.D_EDIT.CURRENT_STREAK | translate }}</div>
<div> <div>
<strong <strong
>{{ currentStreak() }} {{T.F.SIMPLE_COUNTER.D_EDIT.DAYS|translate}}</strong >{{ currentStreak() }}
> {{ T.F.SIMPLE_COUNTER.D_EDIT.DAYS | translate }}</strong
</div> >
</section> </div>
</section>
<section style="text-align: center; margin-bottom: 16px"> <section style="text-align: center; margin-bottom: 16px">
<div>{{T.F.SIMPLE_COUNTER.D_EDIT.DAILY_GOAL|translate}}</div> <div>{{ T.F.SIMPLE_COUNTER.D_EDIT.DAILY_GOAL | translate }}</div>
<div> <div>
<strong <strong>
>@if (data.simpleCounter.type === SimpleCounterType.StopWatch) { {{ @if (data.simpleCounter.type === SimpleCounterType.StopWatch) {
data.simpleCounter.streakMinValue|msToString }} {{ data.simpleCounter.streakMinValue | msToString }}
<!----> <!---->
} @else { {{ data.simpleCounter.streakMinValue }} }</strong } @else {
> {{ data.simpleCounter.streakMinValue }}
</div> }
</section> </strong>
</div>
</section>
} }
<!----> <!---->
@if (stats()) { @if (stats()) {
<section style="margin-bottom: 32px"> <section style="margin-bottom: 32px">
<div class="chart-wrapper"> <div class="chart-wrapper">
<div class="inner-chart-wrapper"> <div class="inner-chart-wrapper">
<canvas <canvas
[type]="'line'" [type]="'line'"
[data]="stats()" [data]="stats()"
[labels]="stats()?.labels" [labels]="stats()?.labels"
[options]="lineChartOptions" [options]="lineChartOptions"
[legend]="true" [legend]="true"
baseChart baseChart
> >
</canvas> </canvas>
</div>
</div> </div>
</div> </section>
</section>
} }
<div class="form-wrapper"> <div class="form-wrapper">
@if (data.simpleCounter.type === SimpleCounterType.ClickCounter || @if (
data.simpleCounter.type === SimpleCounterType.RepeatedCountdownReminder) { data.simpleCounter.type === SimpleCounterType.ClickCounter ||
<mat-form-field> data.simpleCounter.type === SimpleCounterType.RepeatedCountdownReminder
<mat-label>{{ T.F.SIMPLE_COUNTER.D_EDIT.L_COUNTER|translate }}</mat-label> ) {
<input <mat-form-field>
(ngModelChange)="onModelChange($event)" <mat-label>{{ T.F.SIMPLE_COUNTER.D_EDIT.L_COUNTER | translate }}</mat-label>
[ngModel]="val" <input
matInput (ngModelChange)="onModelChange($event)"
name="count" [ngModel]="val"
type="number" matInput
/> name="count"
</mat-form-field> type="number"
/>
</mat-form-field>
} }
<!----> <!---->
@if (data.simpleCounter.type === SimpleCounterType.StopWatch) { @if (data.simpleCounter.type === SimpleCounterType.StopWatch) {
<mat-form-field> <mat-form-field>
<mat-label>{{ T.F.SIMPLE_COUNTER.D_EDIT.L_COUNTER|translate }}</mat-label> <mat-label>{{ T.F.SIMPLE_COUNTER.D_EDIT.L_COUNTER | translate }}</mat-label>
<input <input
(ngModelChange)="onModelChange($event)" (ngModelChange)="onModelChange($event)"
[ngModel]="val" [ngModel]="val"
inputDuration="optional" inputDuration="optional"
matInput matInput
name="count" name="count"
type="text" type="text"
/> />
<mat-icon matPrefix>timer</mat-icon> <mat-icon matPrefix>timer</mat-icon>
</mat-form-field> </mat-form-field>
} }
</div> </div>
</mat-dialog-content> </mat-dialog-content>
@ -87,7 +92,7 @@
mat-button mat-button
type="button" type="button"
> >
{{ T.G.CANCEL|translate }} {{ T.G.CANCEL | translate }}
</button> </button>
<button <button
class="btn btn-primary submit-button" class="btn btn-primary submit-button"
@ -96,7 +101,7 @@
type="submit" type="submit"
> >
<mat-icon>save</mat-icon> <mat-icon>save</mat-icon>
{{ T.G.SAVE|translate }} {{ T.G.SAVE | translate }}
</button> </button>
</div> </div>
</mat-dialog-actions> </mat-dialog-actions>

View file

@ -1,60 +1,64 @@
@if (simpleCounter(); as sc) { @if (simpleCounter(); as sc) {
<div class="wrapper"> <div class="wrapper">
@if (sc.type === SimpleCounterType.StopWatch) { @if (sc.type === SimpleCounterType.StopWatch) {
<button <button
(click)="toggleStopwatch()" (click)="toggleStopwatch()"
(contextmenu)="edit($event)" (contextmenu)="edit($event)"
(longPress)="edit()" (longPress)="edit()"
[color]="sc.isOn? 'accent': ''" [color]="sc.isOn ? 'accent' : ''"
class="main-btn stopwatch" class="main-btn stopwatch"
mat-mini-fab mat-mini-fab
> >
<mat-icon>{{ sc.icon }}</mat-icon> <mat-icon>{{ sc.icon }}</mat-icon>
@if (isSuccess()) { @if (isSuccess()) {
<mat-icon class="check-ico">check</mat-icon> <mat-icon class="check-ico">check</mat-icon>
}
</button>
@if (sc.countOnDay[todayStr()]) {
<div class="label">{{ sc.countOnDay[todayStr()] | msToMinuteClockString }}</div>
}
} }
</button> <!----->
@if (sc.countOnDay[todayStr()]) { @if (sc.type === SimpleCounterType.ClickCounter) {
<div class="label">{{ sc.countOnDay[todayStr()]|msToMinuteClockString }}</div> <button
} } (click)="toggleCounter()"
<!-----> (contextmenu)="edit($event)"
@if (sc.type === SimpleCounterType.ClickCounter) { (longPress)="edit()"
<button class="main-btn"
(click)="toggleCounter()" color=""
(contextmenu)="edit($event)" mat-mini-fab
(longPress)="edit()" >
class="main-btn" <mat-icon>{{ sc.icon }}</mat-icon>
color="" @if (isSuccess()) {
mat-mini-fab <mat-icon class="check-ico">check</mat-icon>
> }
<mat-icon>{{ sc.icon }}</mat-icon> </button>
@if (isSuccess()) { @if (sc.countOnDay[todayStr()]) {
<mat-icon class="check-ico">check</mat-icon> <div class="label">{{ sc.countOnDay[todayStr()] }}</div>
}
} }
</button> <!----->
@if (sc.countOnDay[todayStr()]) { @if (sc.type === SimpleCounterType.RepeatedCountdownReminder) {
<div class="label">{{ sc.countOnDay[todayStr()] }}</div> <button
} } (click)="isTimeUp() ? countUpAndNextRepeatCountdownSession() : toggleStopwatch()"
<!-----> (contextmenu)="edit($event)"
@if (sc.type === SimpleCounterType.RepeatedCountdownReminder) { (longPress)="edit()"
<button [color]="sc.isOn && !isTimeUp() ? 'accent' : ''"
(click)="isTimeUp() ? countUpAndNextRepeatCountdownSession() : toggleStopwatch()" [class.isTimeUp]="isTimeUp()"
(contextmenu)="edit($event)" class="main-btn repeated-countdown"
(longPress)="edit()" mat-mini-fab
[color]="(sc.isOn && !isTimeUp())? 'accent': ''" >
[class.isTimeUp]="isTimeUp()" <mat-icon>{{ sc.icon }}</mat-icon>
class="main-btn repeated-countdown" @if (isSuccess()) {
mat-mini-fab <mat-icon class="check-ico">check</mat-icon>
> }
<mat-icon>{{ sc.icon }}</mat-icon> </button>
@if (isSuccess()) { @if (sc.isOn && (countdownTime$ | async); as countdownTime) {
<mat-icon class="check-ico">check</mat-icon> <div class="extra-label">{{ countdownTime | msToMinuteClockString }}</div>
}
@if (sc.countOnDay[todayStr()] || isTimeUp()) {
<div class="label">{{ isTimeUp() ? '+' : sc.countOnDay[todayStr()] }}</div>
}
} }
</button> </div>
@if (sc.isOn && (countdownTime$|async); as countdownTime) {
<div class="extra-label">{{ countdownTime|msToMinuteClockString }}</div>
} @if (sc.countOnDay[todayStr()] || isTimeUp()) {
<div class="label">{{ isTimeUp() ? "+" : sc.countOnDay[todayStr()] }}</div>
} }
</div>
} }

View file

@ -19,7 +19,7 @@
type="submit" type="submit"
> >
<mat-icon>save</mat-icon> <mat-icon>save</mat-icon>
{{T.G.SAVE|translate}} {{ T.G.SAVE | translate }}
</button> </button>
</div> </div>
</form> </form>

View file

@ -1,6 +1,9 @@
<h1 mat-dialog-title> <h1 mat-dialog-title>
{{isEdit ? (T.F.TAG.D_EDIT.EDIT|translate:{title: title}) : {{
(T.F.TAG.D_EDIT.ADD|translate:{title: title})}} isEdit
? (T.F.TAG.D_EDIT.EDIT | translate: { title: title })
: (T.F.TAG.D_EDIT.ADD | translate: { title: title })
}}
</h1> </h1>
<mat-dialog-content> <mat-dialog-content>
@ -12,9 +15,9 @@
(addNewItem)="addNewTag($event)" (addNewItem)="addNewTag($event)"
(removeItem)="removeTag($event)" (removeItem)="removeTag($event)"
autoFocus autoFocus
[label]="T.F.TAG.D_EDIT.LABEL|translate" [label]="T.F.TAG.D_EDIT.LABEL | translate"
[model]="tagIds" [model]="tagIds"
[suggestions]="(tagSuggestions$|async)" [suggestions]="tagSuggestions$ | async"
(ctrlEnterSubmit)="close()" (ctrlEnterSubmit)="close()"
></chip-list-input> ></chip-list-input>
</div> </div>
@ -28,6 +31,6 @@
type="submit" type="submit"
> >
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
{{T.G.CLOSE|translate}} {{ T.G.CLOSE | translate }}
</button> </button>
</mat-dialog-actions> </mat-dialog-actions>

View file

@ -1,17 +1,17 @@
<mat-chip-grid #chipListElRef> <mat-chip-grid #chipListElRef>
@for (modelItem of tagItems(); track modelItem.id) { @for (modelItem of tagItems(); track modelItem.id) {
<mat-chip-row <mat-chip-row
(removed)="remove(modelItem.id)" (removed)="remove(modelItem.id)"
[removable]="true" [removable]="true"
> >
<tag [tag]="modelItem"></tag> <tag [tag]="modelItem"></tag>
<mat-icon <mat-icon
[title]="T.G.REMOVE|translate" [title]="T.G.REMOVE | translate"
matChipRemove matChipRemove
>cancel >cancel
</mat-icon> </mat-icon>
</mat-chip-row> </mat-chip-row>
} }
<input <input
#inputElRef #inputElRef
@ -30,6 +30,6 @@
(optionSelected)="selected($event)" (optionSelected)="selected($event)"
> >
@for (suggestion of filteredSuggestions(); track suggestion.id) { @for (suggestion of filteredSuggestions(); track suggestion.id) {
<mat-option [value]="suggestion.id">{{ suggestion.title }}</mat-option> <mat-option [value]="suggestion.id">{{ suggestion.title }}</mat-option>
} }
</mat-autocomplete> </mat-autocomplete>

View file

@ -1,10 +1,10 @@
@if ((tags()?.length > 0)) { @if (tags()?.length > 0) {
<div class="tags-container"> <div class="tags-container">
<div class="tags"> <div class="tags">
@for (tag of tags(); track tag.id) { @for (tag of tags(); track tag.id) {
<!-- --> <!-- -->
<tag [tag]="tag"></tag> <tag [tag]="tag"></tag>
} }
</div>
</div> </div>
</div>
} }

View file

@ -1,8 +1,8 @@
<mat-icon <mat-icon
[style.background]="color()" [style.background]="color()"
class="tag-ico" class="tag-ico"
>{{tag().icon}}</mat-icon >{{ tag().icon }}</mat-icon
> >
@if (!isHideTitle()) { @if (!isHideTitle()) {
<span class="tag-title">{{ tag().title }}</span> <span class="tag-title">{{ tag().title }}</span>
} }

View file

@ -1,24 +1,27 @@
<form <form
(submit)="$event.preventDefault();save()" (submit)="$event.preventDefault(); save()"
class="dialog-help-wrapper" class="dialog-help-wrapper"
> >
<h1 mat-dialog-title> <h1 mat-dialog-title>
{{isEdit ? (T.F.TASK_REPEAT.D_EDIT.EDIT|translate) : {{
(T.F.TASK_REPEAT.D_EDIT.ADD|translate)}} isEdit
? (T.F.TASK_REPEAT.D_EDIT.EDIT | translate)
: (T.F.TASK_REPEAT.D_EDIT.ADD | translate)
}}
</h1> </h1>
<mat-dialog-content> <mat-dialog-content>
<!-- <h3 class="mat-h3">{{task.title}}</h3>--> <!-- <h3 class="mat-h3">{{task.title}}</h3>-->
<help-section> <help-section>
<p>{{T.F.TASK_REPEAT.D_EDIT.HELP1|translate}}</p> <p>{{ T.F.TASK_REPEAT.D_EDIT.HELP1 | translate }}</p>
<p>{{T.F.TASK_REPEAT.D_EDIT.HELP2|translate}}</p> <p>{{ T.F.TASK_REPEAT.D_EDIT.HELP2 | translate }}</p>
<p>{{T.F.TASK_REPEAT.D_EDIT.HELP3|translate}}</p> <p>{{ T.F.TASK_REPEAT.D_EDIT.HELP3 | translate }}</p>
<p>{{T.F.TASK_REPEAT.D_EDIT.HELP4|translate}}</p> <p>{{ T.F.TASK_REPEAT.D_EDIT.HELP4 | translate }}</p>
</help-section> </help-section>
<div class="form-wrapper"> <div class="form-wrapper">
<formly-form <formly-form
(modelChange)="repeatCfg=$event" (modelChange)="repeatCfg = $event"
[form]="formGroup1" [form]="formGroup1"
[fields]="TASK_REPEAT_CFG_FORM_CFG_BEFORE_TAGS" [fields]="TASK_REPEAT_CFG_FORM_CFG_BEFORE_TAGS"
[model]="repeatCfg" [model]="repeatCfg"
@ -27,14 +30,14 @@
(addItem)="addTag($event)" (addItem)="addTag($event)"
(addNewItem)="addNewTag($event)" (addNewItem)="addNewTag($event)"
(removeItem)="removeTag($event)" (removeItem)="removeTag($event)"
[label]="T.F.TASK_REPEAT.D_EDIT.TAG_LABEL|translate" [label]="T.F.TASK_REPEAT.D_EDIT.TAG_LABEL | translate"
[model]="repeatCfg.tagIds" [model]="repeatCfg.tagIds"
[suggestions]="(tagSuggestions$|async)" [suggestions]="tagSuggestions$ | async"
></chip-list-input> ></chip-list-input>
<!-- <collapsible [title]="T.F.TASK_REPEAT.D_EDIT.ADVANCED_CFG|translate">--> <!-- <collapsible [title]="T.F.TASK_REPEAT.D_EDIT.ADVANCED_CFG|translate">-->
<formly-form <formly-form
(modelChange)="repeatCfg=$event" (modelChange)="repeatCfg = $event"
[form]="formGroup2" [form]="formGroup2"
[fields]="TASK_REPEAT_CFG_ADVANCED_FORM_CFG" [fields]="TASK_REPEAT_CFG_ADVANCED_FORM_CFG"
[model]="repeatCfg" [model]="repeatCfg"
@ -50,19 +53,19 @@
mat-button mat-button
type="button" type="button"
> >
{{T.G.CANCEL|translate}} {{ T.G.CANCEL | translate }}
</button> </button>
@if (isEdit) { @if (isEdit) {
<button <button
(click)="remove()" (click)="remove()"
color="primary" color="primary"
mat-stroked-button mat-stroked-button
type="button" type="button"
> >
<mat-icon>delete_forever</mat-icon> <mat-icon>delete_forever</mat-icon>
{{T.G.REMOVE|translate}} {{ T.G.REMOVE | translate }}
</button> </button>
} }
<button <button
@ -72,7 +75,7 @@
type="submit" type="submit"
> >
<mat-icon>save</mat-icon> <mat-icon>save</mat-icon>
{{T.G.SAVE|translate}} {{ T.G.SAVE | translate }}
</button> </button>
</mat-dialog-actions> </mat-dialog-actions>
</form> </form>

View file

@ -1,8 +1,9 @@
@let shortSyntaxTags = (shortSyntaxTags$|async); @let activatedIssueTask = @let shortSyntaxTags = shortSyntaxTags$ | async;
(activatedIssueTask$|async); @let inputVal = (inputVal$|async)||''; @let activatedIssueTask = activatedIssueTask$ | async;
@let inputVal = (inputVal$ | async) || '';
<form <form
(submit)="$event.preventDefault();addTask()" (submit)="$event.preventDefault(); addTask()"
@blendInOut @blendInOut
[class.isElevated]="isElevated()" [class.isElevated]="isElevated()"
[class.mat-elevation-z3]="!isElevated()" [class.mat-elevation-z3]="!isElevated()"
@ -12,10 +13,10 @@
#origin="matAutocompleteOrigin" #origin="matAutocompleteOrigin"
> >
<div class="input-wrapper"> <div class="input-wrapper">
@if ((isLoading())) { @if (isLoading()) {
<div class="spinner"> <div class="spinner">
<mat-spinner diameter="50"></mat-spinner> <mat-spinner diameter="50"></mat-spinner>
</div> </div>
} }
<input <input
@ -25,108 +26,132 @@
[formControl]="taskSuggestionsCtrl" [formControl]="taskSuggestionsCtrl"
[matAutocomplete]="autoEl" [matAutocomplete]="autoEl"
[matAutocompleteConnectedTo]="origin" [matAutocompleteConnectedTo]="origin"
[mentionConfig]="mentionConfig$|async" [mentionConfig]="mentionConfig$ | async"
spellcheck="false" spellcheck="false"
[placeholder]="(doubleEnterCount() > 0) [placeholder]="
? (T.F.TASK.ADD_TASK_BAR.START|translate) doubleEnterCount() > 0
: isAddToBottom() ? (T.F.TASK.ADD_TASK_BAR.START | translate)
? isAddToBacklog() : isAddToBottom()
? (T.F.TASK.ADD_TASK_BAR.ADD_TASK_TO_BOTTOM_OF_BACKLOG|translate) ? isAddToBacklog()
: (T.F.TASK.ADD_TASK_BAR.ADD_TASK_TO_BOTTOM_OF_TODAY|translate) ? (T.F.TASK.ADD_TASK_BAR.ADD_TASK_TO_BOTTOM_OF_BACKLOG | translate)
: isAddToBacklog() : (T.F.TASK.ADD_TASK_BAR.ADD_TASK_TO_BOTTOM_OF_TODAY | translate)
? (T.F.TASK.ADD_TASK_BAR.ADD_TASK_TO_TOP_OF_BACKLOG|translate) : isAddToBacklog()
: (T.F.TASK.ADD_TASK_BAR.ADD_TASK_TO_TOP_OF_TODAY|translate)" ? (T.F.TASK.ADD_TASK_BAR.ADD_TASK_TO_TOP_OF_BACKLOG | translate)
: (T.F.TASK.ADD_TASK_BAR.ADD_TASK_TO_TOP_OF_TODAY | translate)
"
matInput matInput
/> />
<div class="button-controls"> <div class="button-controls">
@if (taskSuggestionsCtrl?.value?.length) { @if (taskSuggestionsCtrl?.value?.length) {
<div class="separator-box"> <div class="separator-box">
<button <button
class="switch-add-to-btn" class="switch-add-to-btn"
(mousedown)="addTask()" (mousedown)="addTask()"
type="submit" type="submit"
mat-icon-button mat-icon-button
> >
@if(activatedIssueTask){ @if (activatedIssueTask) {
<mat-icon>add_box</mat-icon> <mat-icon>add_box</mat-icon>
}@else { } @else {
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
} }
</button> </button>
</div> </div>
} }
<button <button
(click)="toggleIsAddToBottom()" (click)="toggleIsAddToBottom()"
[matTooltip]="T.F.TASK.ADD_TASK_BAR.TOGGLE_ADD_TOP_OR_BOTTOM|translate" [matTooltip]="T.F.TASK.ADD_TASK_BAR.TOGGLE_ADD_TOP_OR_BOTTOM | translate"
matTooltipPosition="above" matTooltipPosition="above"
class="switch-add-to-bot-btn" class="switch-add-to-bot-btn"
mat-icon-button mat-icon-button
type="button" type="button"
> >
@if(isAddToBottom()){ @if (isAddToBottom()) {
<mat-icon>vertical_align_bottom</mat-icon> <mat-icon>vertical_align_bottom</mat-icon>
}@else { } @else {
<mat-icon>vertical_align_top</mat-icon> <mat-icon>vertical_align_top</mat-icon>
} }
</button> </button>
@if (isSearchIssueProvidersAvailable$|async) { @if (isSearchIssueProvidersAvailable$ | async) {
<button <button
(click)="isSearchIssueProviders.set(!isSearchIssueProviders())" (click)="isSearchIssueProviders.set(!isSearchIssueProviders())"
[matTooltip]="'Toggle searching issue providers'" [matTooltip]="'Toggle searching issue providers'"
matTooltipPosition="above" matTooltipPosition="above"
class="switch-add-to-btn" class="switch-add-to-btn"
mat-icon-button mat-icon-button
type="button" type="button"
> >
@if(isSearchIssueProviders()){ @if (isSearchIssueProviders()) {
<mat-icon>youtube_searched_for</mat-icon> <mat-icon>youtube_searched_for</mat-icon>
}@else { } @else {
<mat-icon>search_off</mat-icon> <mat-icon>search_off</mat-icon>
} }
</button> </button>
} @if (isAddToBacklogAvailable$|async) { }
<button @if (isAddToBacklogAvailable$ | async) {
(click)="isAddToBacklog.set(!isAddToBacklog())" <button
[matTooltip]="T.F.TASK.ADD_TASK_BAR.TOGGLE_ADD_TO_BACKLOG_TODAY|translate" (click)="isAddToBacklog.set(!isAddToBacklog())"
matTooltipPosition="above" [matTooltip]="T.F.TASK.ADD_TASK_BAR.TOGGLE_ADD_TO_BACKLOG_TODAY | translate"
class="switch-add-to-btn" matTooltipPosition="above"
mat-icon-button class="switch-add-to-btn"
type="button" mat-icon-button
> type="button"
@if(isAddToBacklog()){ >
<mat-icon>arrow_downward</mat-icon> @if (isAddToBacklog()) {
}@else { <mat-icon>arrow_downward</mat-icon>
<mat-icon>arrow_upward</mat-icon> } @else {
} <mat-icon>arrow_upward</mat-icon>
</button> }
</button>
} }
</div> </div>
</div> </div>
<div class="info-bar"> <div class="info-bar">
@if (inputVal?.length > 0) { @if (!activatedIssueTask && !shortSyntaxTags?.length) { @if (inputVal?.length > 0) {
<div class="info-text">{{ T.F.TASK.ADD_TASK_BAR.CREATE_TASK|translate }}</div> @if (!activatedIssueTask && !shortSyntaxTags?.length) {
} @if (activatedIssueTask) { @if (activatedIssueTask?.issueType) { <div class="info-text">{{ T.F.TASK.ADD_TASK_BAR.CREATE_TASK | translate }}</div>
<div class="info-text add-existing"> }
<mat-icon>playlist_add</mat-icon> @if (activatedIssueTask) {
{{ T.F.TASK.ADD_TASK_BAR.ADD_ISSUE_TASK|translate:{ issueType: @if (activatedIssueTask?.issueType) {
activatedIssueTask.issueType, issueNr: activatedIssueTask.taskIssueId || <div class="info-text add-existing">
activatedIssueTask.issueData?.id } }} <mat-icon>playlist_add</mat-icon>
</div> {{
} @if (activatedIssueTask.issueType=== undefined) { T.F.TASK.ADD_TASK_BAR.ADD_ISSUE_TASK
<div class="info-text add-existing"> | translate
<mat-icon>playlist_add</mat-icon> : {
{{ T.F.TASK.ADD_TASK_BAR.ADD_EXISTING_TASK|translate: { taskTitle: issueType: activatedIssueTask.issueType,
activatedIssueTask.title } }} issueNr:
</div> activatedIssueTask.taskIssueId ||
} } @if (!activatedIssueTask && shortSyntaxTags?.length) { @for (shortSyntaxTag of activatedIssueTask.issueData?.id,
(shortSyntaxTags); track shortSyntaxTag.title || shortSyntaxTag) { }
<tag [tag]="shortSyntaxTag"></tag> }}
} } } @if (inputVal.length === 0) { </div>
<div class="info-text">{{ T.F.TASK.ADD_TASK_BAR.EXAMPLE|translate }}</div> }
@if (activatedIssueTask.issueType === undefined) {
<div class="info-text add-existing">
<mat-icon>playlist_add</mat-icon>
{{
T.F.TASK.ADD_TASK_BAR.ADD_EXISTING_TASK
| translate: { taskTitle: activatedIssueTask.title }
}}
</div>
}
}
@if (!activatedIssueTask && shortSyntaxTags?.length) {
@for (
shortSyntaxTag of shortSyntaxTags;
track shortSyntaxTag.title || shortSyntaxTag
) {
<tag [tag]="shortSyntaxTag"></tag>
}
}
}
@if (inputVal.length === 0) {
<div class="info-text">{{ T.F.TASK.ADD_TASK_BAR.EXAMPLE | translate }}</div>
} }
</div> </div>
@ -138,21 +163,25 @@
(optionSelected)="addTask()" (optionSelected)="addTask()"
[displayWith]="displayWith" [displayWith]="displayWith"
> >
@for (item of (filteredIssueSuggestions$|async); track item.taskId || (item.issueData @for (
&& item.issueData.id)) { item of filteredIssueSuggestions$ | async;
<mat-option [value]="item"> track item.taskId || (item.issueData && item.issueData.id)
@if (item.issueType) { ) {
<mat-icon [svgIcon]="item.issueType|issueIcon"></mat-icon> <mat-option [value]="item">
} @if (!item.issueType && !item.ctx) { @if (item.issueType) {
<mat-icon>library_books</mat-icon> <mat-icon [svgIcon]="item.issueType | issueIcon"></mat-icon>
} @if (item.ctx) { }
<tag @if (!item.issueType && !item.ctx) {
[tag]="item.ctx" <mat-icon>library_books</mat-icon>
[isHideTitle]="isHideTagTitles()" }
></tag> @if (item.ctx) {
} <tag
<span [innerHTML]="item?.titleHighlighted||item?.title"></span> [tag]="item.ctx"
</mat-option> [isHideTitle]="isHideTagTitles()"
></tag>
}
<span [innerHTML]="item?.titleHighlighted || item?.title"></span>
</mat-option>
} }
</mat-autocomplete> </mat-autocomplete>
</form> </form>

View file

@ -1,24 +1,26 @@
<div class="dialog-help-wrapper"> <div class="dialog-help-wrapper">
<h1 mat-dialog-title>{{T.F.TASK.D_TIME_FOR_DAY.TITLE|translate}}</h1> <h1 mat-dialog-title>{{ T.F.TASK.D_TIME_FOR_DAY.TITLE | translate }}</h1>
<form <form
(submit)="$event.preventDefault();submit()" (submit)="$event.preventDefault(); submit()"
name="addForAnotherDayForm" name="addForAnotherDayForm"
> >
<mat-dialog-content> <mat-dialog-content>
<help-section> <help-section>
<div <div
[innerHTML]="T.F.TASK.D_TIME_FOR_DAY.HELP|translate" [innerHTML]="T.F.TASK.D_TIME_FOR_DAY.HELP | translate"
class="side-info" class="side-info"
></div> ></div>
</help-section> </help-section>
<h3 class="mat-caption"> <h3 class="mat-caption">
{{T.F.TASK.D_TIME_FOR_DAY.ADD_ENTRY_FOR|translate:{ date: {{
(newEntry.date|date:'dd-MM-yyyy') || '' } }} T.F.TASK.D_TIME_FOR_DAY.ADD_ENTRY_FOR
| translate: { date: (newEntry.date | date: 'dd-MM-yyyy') || '' }
}}
</h3> </h3>
<mat-form-field> <mat-form-field>
<mat-label>{{T.F.TASK.D_TIME_FOR_DAY.DATE|translate}}</mat-label> <mat-label>{{ T.F.TASK.D_TIME_FOR_DAY.DATE | translate }}</mat-label>
<input <input
[(ngModel)]="newEntry.date" [(ngModel)]="newEntry.date"
[matDatepicker]="myDatepicker" [matDatepicker]="myDatepicker"
@ -27,7 +29,7 @@
required required
type="text" type="text"
/> />
<mat-error>{{T.V.E_DATETIME|translate}}</mat-error> <mat-error>{{ T.V.E_DATETIME | translate }}</mat-error>
<mat-datepicker-toggle <mat-datepicker-toggle
[for]="myDatepicker" [for]="myDatepicker"
matPrefix matPrefix
@ -38,7 +40,7 @@
<div class="wrap-time"> <div class="wrap-time">
<input-duration-slider <input-duration-slider
[(model)]="newEntry.timeSpent" [(model)]="newEntry.timeSpent"
[label]="T.F.TASK.D_TIME_FOR_DAY.TINE_SPENT|translate" [label]="T.F.TASK.D_TIME_FOR_DAY.TINE_SPENT | translate"
> >
</input-duration-slider> </input-duration-slider>
</div> </div>
@ -51,7 +53,7 @@
mat-button mat-button
type="button" type="button"
> >
{{T.G.CANCEL|translate}} {{ T.G.CANCEL | translate }}
</button> </button>
<button <button
@ -60,7 +62,7 @@
type="submit" type="submit"
> >
<mat-icon>save</mat-icon> <mat-icon>save</mat-icon>
{{T.G.SAVE|translate}} {{ T.G.SAVE | translate }}
</button> </button>
</mat-dialog-actions> </mat-dialog-actions>
</form> </form>

View file

@ -1,10 +1,10 @@
<mat-dialog-content> <mat-dialog-content>
<!-- <h1>XXX {{(task$|async)?.id}}</h1>--> <!-- <h1>XXX {{(task$|async)?.id}}</h1>-->
@if (task$|async; as task) { @if (task$ | async; as task) {
<task-detail-panel <task-detail-panel
[task]="task" [task]="task"
[isDialogMode]="true" [isDialogMode]="true"
></task-detail-panel> ></task-detail-panel>
} }
</mat-dialog-content> </mat-dialog-content>

View file

@ -1,15 +1,15 @@
<div class="dialog-help-wrapper"> <div class="dialog-help-wrapper">
<h1 mat-dialog-title>{{T.F.TASK.D_TIME.TITLE|translate}}</h1> <h1 mat-dialog-title>{{ T.F.TASK.D_TIME.TITLE | translate }}</h1>
<form <form
(submit)="$event.preventDefault();submit()" (submit)="$event.preventDefault(); submit()"
class="mat-body" class="mat-body"
name="time-estimate-form" name="time-estimate-form"
> >
<mat-dialog-content> <mat-dialog-content>
<help-section> <help-section>
<div <div
[innerHTML]="T.F.TASK.D_TIME_FOR_DAY.HELP|translate" [innerHTML]="T.F.TASK.D_TIME_FOR_DAY.HELP | translate"
class="side-info" class="side-info"
></div> ></div>
</help-section> </help-section>
@ -17,12 +17,12 @@
<div class="wrap-time"> <div class="wrap-time">
<input-duration-slider <input-duration-slider
[(model)]="timeSpentOnDayCopy[todayStr]" [(model)]="timeSpentOnDayCopy[todayStr]"
[label]="T.F.TASK.D_TIME.TIME_SPENT|translate" [label]="T.F.TASK.D_TIME.TIME_SPENT | translate"
> >
</input-duration-slider> </input-duration-slider>
<input-duration-slider <input-duration-slider
[(model)]="taskCopy.timeEstimate" [(model)]="taskCopy.timeEstimate"
[label]="T.F.TASK.D_TIME.ESTIMATE|translate" [label]="T.F.TASK.D_TIME.ESTIMATE | translate"
> >
</input-duration-slider> </input-duration-slider>
</div> </div>
@ -36,35 +36,37 @@
type="button" type="button"
> >
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
{{T.F.TASK.D_TIME.ADD_FOR_OTHER_DAY|translate}} {{ T.F.TASK.D_TIME.ADD_FOR_OTHER_DAY | translate }}
</button> </button>
@for (strDate of timeSpentOnDayCopy|keys:'reverse':todayStr; track @for (
trackByIndex($index, strDate)) { strDate of timeSpentOnDayCopy | keys: 'reverse' : todayStr;
<div class="other-day"> track trackByIndex($index, strDate)
<mat-form-field> ) {
<mat-label <div class="other-day">
>{{T.F.TASK.D_TIME.TIME_SPENT_ON|translate:{date: strDate} }}</mat-label <mat-form-field>
<mat-label>{{
T.F.TASK.D_TIME.TIME_SPENT_ON | translate: { date: strDate }
}}</mat-label>
<input
[(ngModel)]="timeSpentOnDayCopy[strDate]"
inputDuration="optional"
matInput
name="timeSpentOnDay{{ 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="warn"
mat-icon-button
type="button"
> >
<input <mat-icon>delete_forever</mat-icon>
[(ngModel)]="timeSpentOnDayCopy[strDate]" </button>
inputDuration="optional" </div>
matInput
name="timeSpentOnDay{{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="warn"
mat-icon-button
type="button"
>
<mat-icon>delete_forever</mat-icon>
</button>
</div>
} }
</div> </div>
</mat-dialog-content> </mat-dialog-content>
@ -76,7 +78,7 @@
mat-button mat-button
type="button" type="button"
> >
{{T.G.CANCEL|translate}} {{ T.G.CANCEL | translate }}
</button> </button>
<button <button
@ -86,7 +88,7 @@
type="submit" type="submit"
> >
<mat-icon>save</mat-icon> <mat-icon>save</mat-icon>
{{T.G.SAVE|translate}} {{ T.G.SAVE | translate }}
</button> </button>
</mat-dialog-actions> </mat-dialog-actions>
</form> </form>

View file

@ -1,209 +1,223 @@
@if ((tasks$|async); as tasks) { @if (tasks$ | async; as tasks) {
<h1 mat-dialog-title> <h1 mat-dialog-title>
<mat-icon class="dialog-header-icon">alarm</mat-icon> <mat-icon class="dialog-header-icon">alarm</mat-icon>
<span <span>{{
>{{(isMultiple ? T.F.TASK.D_REMINDER_VIEW.DUE_TASKS : (isMultiple
T.F.TASK.D_REMINDER_VIEW.DUE_TASK)|translate}}</span ? T.F.TASK.D_REMINDER_VIEW.DUE_TASKS
> : T.F.TASK.D_REMINDER_VIEW.DUE_TASK
</h1> ) | translate
<mat-dialog-content> }}</span>
<div </h1>
[@standardList]="tasks.length" <mat-dialog-content>
class="tasks" <div
> [@standardList]="tasks.length"
@for (task of tasks; track trackById($index, task)) { class="tasks"
<div class="task"> >
<div class="title-wrapper"> @for (task of tasks; track trackById($index, task)) {
<div class="title">{{task.title}}</div> <div class="task">
<tag-list <div class="title-wrapper">
[isShowProjectTagAlways]="true" <div class="title">{{ task.title }}</div>
[task]="task" <tag-list
></tag-list> [isShowProjectTagAlways]="true"
</div> [task]="task"
@if (isMultiple) { ></tag-list>
<div class="actions"> </div>
@if (isMultiple) {
<div class="actions">
<button
[disabled]="!(task.projectId || task.parentId || task.tagIds.length > 0)"
(click)="dismiss(task)"
[title]="T.G.DISMISS | translate"
class="hide-xs"
color=""
mat-icon-button
type="button"
>
<mat-icon>alarm_off</mat-icon>
</button>
<button
(dblclick)="snooze(task, 10)"
[matMenuTriggerFor]="snoozeMenu"
[title]="T.F.TASK.D_REMINDER_VIEW.SNOOZE | translate"
color=""
mat-icon-button
type="button"
>
<mat-icon>snooze</mat-icon>
</button>
<button
(click)="addToToday(task)"
[title]="T.F.TASK.D_REMINDER_VIEW.ADD_TO_TODAY | translate"
color=""
mat-icon-button
type="button"
>
<mat-icon>wb_sunny</mat-icon>
</button>
<mat-menu #snoozeMenu="matMenu">
<button
(click)="snooze(task, 10)"
mat-menu-item
>
<mat-icon>snooze</mat-icon>
{{ T.G.MINUTES | translate: { m: 10 } }}
</button>
<button
(click)="snooze(task, 30)"
mat-menu-item
>
<mat-icon>snooze</mat-icon>
{{ T.G.MINUTES | translate: { m: 30 } }}
</button>
<button
(click)="snooze(task, 60)"
mat-menu-item
>
<mat-icon>snooze</mat-icon>
{{ T.G.MINUTES | translate: { m: 60 } }}
</button>
<button
(click)="rescheduleUntilTomorrow(task)"
[disabled]="isDisableControls"
mat-menu-item
>
<mat-icon>schedule</mat-icon>
{{ T.F.TASK.D_REMINDER_VIEW.RESCHEDULE_UNTIL_TOMORROW | translate }}
</button>
<button
[disabled]="
!(task.projectId || task.parentId || task.tagIds.length > 0)
"
(click)="dismiss(task)"
mat-menu-item
>
<mat-icon>alarm_off</mat-icon>
{{ T.G.DISMISS | translate }}
</button>
<button
(click)="editReminder(task)"
mat-menu-item
>
<mat-icon>edit</mat-icon>
{{ T.G.EDIT | translate }}
</button>
</mat-menu>
</div>
}
</div>
}
</div>
</mat-dialog-content>
<mat-dialog-actions align="end">
<div class="wrap-buttons">
<button
(dblclick)="snoozeAll(10)"
[disabled]="isDisableControls"
[matMenuTriggerFor]="snoozeAllMenu"
color="primary"
mat-button
type="button"
>
<mat-icon>snooze</mat-icon>
{{
(isMultiple
? T.F.TASK.D_REMINDER_VIEW.SNOOZE_ALL
: T.F.TASK.D_REMINDER_VIEW.SNOOZE
) | translate
}}
</button>
@if (!isMultiple && (isSingleOnToday$ | async)) {
<button <button
[disabled]="!(task.projectId || task.parentId || task.tagIds.length > 0)" (click)="markAsDone()"
(click)="dismiss(task)" [disabled]="isDisableControls"
[title]="T.G.DISMISS|translate" color="primary"
class="hide-xs" mat-stroked-button
color=""
mat-icon-button
type="button" type="button"
> >
<mat-icon>alarm_off</mat-icon> <mat-icon>check</mat-icon>
{{ T.F.TASK.D_REMINDER_VIEW.DONE | translate }}
</button> </button>
}
@if (!(isSingleOnToday$ | async)) {
<button <button
(dblclick)="snooze(task,10)" (click)="addAllToToday()"
[matMenuTriggerFor]="snoozeMenu" [disabled]="isDisableControls"
[title]="T.F.TASK.D_REMINDER_VIEW.SNOOZE|translate" color="primary"
color="" mat-stroked-button
mat-icon-button
type="button"
>
<mat-icon>snooze</mat-icon>
</button>
<button
(click)="addToToday(task)"
[title]="T.F.TASK.D_REMINDER_VIEW.ADD_TO_TODAY|translate"
color=""
mat-icon-button
type="button" type="button"
> >
<mat-icon>wb_sunny</mat-icon> <mat-icon>wb_sunny</mat-icon>
{{
(isMultiple
? T.F.TASK.D_REMINDER_VIEW.ADD_ALL_TO_TODAY
: T.F.TASK.D_REMINDER_VIEW.ADD_TO_TODAY
) | translate
}}
</button>
}
@if (!isMultiple || (isSingleOnToday$ | async)) {
<button
(click)="play()"
[disabled]="isDisableControls"
color="primary"
mat-stroked-button
type="button"
>
<mat-icon>play_arrow</mat-icon>
{{ T.F.TASK.D_REMINDER_VIEW.START | translate }}
</button> </button>
<mat-menu #snoozeMenu="matMenu">
<button
(click)="snooze(task,10)"
mat-menu-item
>
<mat-icon>snooze</mat-icon>
{{T.G.MINUTES|translate:{m: 10} }}
</button>
<button
(click)="snooze(task,30)"
mat-menu-item
>
<mat-icon>snooze</mat-icon>
{{T.G.MINUTES|translate:{m: 30} }}
</button>
<button
(click)="snooze(task,60)"
mat-menu-item
>
<mat-icon>snooze</mat-icon>
{{T.G.MINUTES|translate:{m: 60} }}
</button>
<button
(click)="rescheduleUntilTomorrow(task)"
[disabled]="isDisableControls"
mat-menu-item
>
<mat-icon>schedule</mat-icon>
{{T.F.TASK.D_REMINDER_VIEW.RESCHEDULE_UNTIL_TOMORROW|translate}}
</button>
<button
[disabled]="!(task.projectId || task.parentId || task.tagIds.length > 0)"
(click)="dismiss(task)"
mat-menu-item
>
<mat-icon>alarm_off</mat-icon>
{{T.G.DISMISS|translate}}
</button>
<button
(click)="editReminder(task)"
mat-menu-item
>
<mat-icon>edit</mat-icon>
{{T.G.EDIT|translate}}
</button>
</mat-menu>
</div>
} }
</div> </div>
} </mat-dialog-actions>
</div> <mat-menu #snoozeAllMenu="matMenu">
</mat-dialog-content>
<mat-dialog-actions align="end">
<div class="wrap-buttons">
<button <button
(dblclick)="snoozeAll(10)" (click)="snoozeAll(10)"
[disabled]="isDisableControls" [disabled]="isDisableControls"
[matMenuTriggerFor]="snoozeAllMenu" mat-menu-item
color="primary"
mat-button
type="button"
> >
<mat-icon>snooze</mat-icon> <mat-icon>snooze</mat-icon>
{{(isMultiple ? T.F.TASK.D_REMINDER_VIEW.SNOOZE_ALL : {{ T.G.MINUTES | translate: { m: 10 } }}
T.F.TASK.D_REMINDER_VIEW.SNOOZE)|translate }}
</button> </button>
@if (!isMultiple && (isSingleOnToday$|async)) {
<button <button
(click)="markAsDone()" (click)="snoozeAll(30)"
[disabled]="isDisableControls" [disabled]="isDisableControls"
color="primary" mat-menu-item
mat-stroked-button
type="button"
> >
<mat-icon>check</mat-icon> <mat-icon>snooze</mat-icon>
{{T.F.TASK.D_REMINDER_VIEW.DONE|translate }} {{ T.G.MINUTES | translate: { m: 30 } }}
</button> </button>
} @if (!(isSingleOnToday$|async)) {
<button <button
(click)="addAllToToday()" (click)="snoozeAll(60)"
[disabled]="isDisableControls" [disabled]="isDisableControls"
color="primary" mat-menu-item
mat-stroked-button
type="button"
> >
<mat-icon>wb_sunny</mat-icon> <mat-icon>snooze</mat-icon>
{{(isMultiple ? T.F.TASK.D_REMINDER_VIEW.ADD_ALL_TO_TODAY : {{ T.G.MINUTES | translate: { m: 60 } }}
T.F.TASK.D_REMINDER_VIEW.ADD_TO_TODAY)|translate }}
</button> </button>
} @if (!isMultiple||(isSingleOnToday$|async)) {
<button <button
(click)="play()" (click)="rescheduleAllUntilTomorrow()"
[disabled]="isDisableControls" [disabled]="isDisableControls"
color="primary" mat-menu-item
mat-stroked-button
type="button"
> >
<mat-icon>play_arrow</mat-icon> <mat-icon>schedule</mat-icon>
{{(T.F.TASK.D_REMINDER_VIEW.START|translate)}} {{ T.F.TASK.D_REMINDER_VIEW.RESCHEDULE_UNTIL_TOMORROW | translate }}
</button> </button>
@if (!isMultiple) {
<button
(click)="editReminder(tasks[0], true)"
mat-menu-item
>
<mat-icon>edit</mat-icon>
{{ T.F.TASK.D_REMINDER_VIEW.RESCHEDULE_EDIT | translate }}
</button>
} }
</div> <button
</mat-dialog-actions> (click)="dismissAll()"
<mat-menu #snoozeAllMenu="matMenu"> [disabled]="isDisableControls"
<button mat-menu-item
(click)="snoozeAll(10)" >
[disabled]="isDisableControls" <mat-icon>alarm_off</mat-icon>
mat-menu-item {{ (isMultiple ? T.F.TASK.D_REMINDER_VIEW.DISMISS_ALL : T.G.DISMISS) | translate }}
> </button>
<mat-icon>snooze</mat-icon> </mat-menu>
{{T.G.MINUTES|translate:{m: 10} }}
</button>
<button
(click)="snoozeAll(30)"
[disabled]="isDisableControls"
mat-menu-item
>
<mat-icon>snooze</mat-icon>
{{T.G.MINUTES|translate:{m: 30} }}
</button>
<button
(click)="snoozeAll(60)"
[disabled]="isDisableControls"
mat-menu-item
>
<mat-icon>snooze</mat-icon>
{{T.G.MINUTES|translate:{m: 60} }}
</button>
<button
(click)="rescheduleAllUntilTomorrow()"
[disabled]="isDisableControls"
mat-menu-item
>
<mat-icon>schedule</mat-icon>
{{T.F.TASK.D_REMINDER_VIEW.RESCHEDULE_UNTIL_TOMORROW|translate}}
</button>
@if (!isMultiple) {
<button
(click)="editReminder(tasks[0], true)"
mat-menu-item
>
<mat-icon>edit</mat-icon>
{{T.F.TASK.D_REMINDER_VIEW.RESCHEDULE_EDIT|translate}}
</button>
}
<button
(click)="dismissAll()"
[disabled]="isDisableControls"
mat-menu-item
>
<mat-icon>alarm_off</mat-icon>
{{(isMultiple ? T.F.TASK.D_REMINDER_VIEW.DISMISS_ALL : T.G.DISMISS)|translate}}
</button>
</mat-menu>
} }

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