mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
Next (#2170)
* feat: add widgets (#2034) * feat: add Taiga UI library (#1992) * feat: add widgets * update patchdb * right resizable sidebar with widgets * feat: add resizing directive * chore: remove unused code * chore: remove unnecessary dep * feat: `ResponsiveCol` add directive for responsive grid * feat: add widgets edit mode and dialogs * feat: add widgets model and modal * chore: fix import * chore: hide mobile widgets behind flag * chore: add dummy widgets * chore: start working on heath widget and implement other comments * feat: health widget * feat: add saving widgets and sidebar params to patch * feat: preemptive UI update for widgets * update health widget with more accurate states and styling (#2127) * feat: `ResponsiveCol` add directive for responsive grid * chore: some changes after merge Co-authored-by: Matt Hill <matthewonthemoon@gmail.com> Co-authored-by: Lucy C <12953208+elvece@users.noreply.github.com> * fix(shared): `ElasticContainer` fix collapsing margin (#2150) * fix(shared): `ElasticContainer` fix collapsing margin * fix toolbar height so titles not chopped --------- Co-authored-by: Matt Hill <matthewonthemoon@gmail.com> * feat: make widgets sidebar width togglable (#2146) * feat: make widgets sidebar width togglable * feat: move widgets under header * chore: fix wide layout * fix(shared): `ResponsiveCol` fix missing grid steps (#2153) * fix widget flag and refactor for non-persistence * default widget flag to false * fix(shared): fix responsive column size (#2159) * fix(shared): fix responsive column size * fix: add responsiveness to all pages * fix responsiveness on more pages * fix: comments * revert some padding changes --------- Co-authored-by: Lucy Cifferello <12953208+elvece@users.noreply.github.com> Co-authored-by: Matt Hill <matthewonthemoon@gmail.com> * chore: add analyzer (#2165) * fix list styling to previous default (#2173) * fix list styling to previous default * dont need important flag --------- Co-authored-by: Alex Inkin <alexander@inkin.ru> Co-authored-by: Lucy C <12953208+elvece@users.noreply.github.com>
This commit is contained in:
committed by
Aiden McClelland
parent
aeb6da111b
commit
e867f31c31
@@ -35,9 +35,17 @@
|
|||||||
"glob": "**/*",
|
"glob": "**/*",
|
||||||
"input": "node_modules/monaco-editor",
|
"input": "node_modules/monaco-editor",
|
||||||
"output": "assets/monaco-editor/"
|
"output": "assets/monaco-editor/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "node_modules/@taiga-ui/icons/src",
|
||||||
|
"output": "assets/taiga-ui/icons"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
|
"node_modules/@taiga-ui/core/styles/taiga-ui-theme.less",
|
||||||
|
"node_modules/@taiga-ui/core/styles/taiga-ui-fonts.less",
|
||||||
|
"node_modules/@taiga-ui/styles/taiga-ui-global.less",
|
||||||
"projects/shared/styles/variables.scss",
|
"projects/shared/styles/variables.scss",
|
||||||
"projects/shared/styles/global.scss",
|
"projects/shared/styles/global.scss",
|
||||||
"projects/shared/styles/shared.scss",
|
"projects/shared/styles/shared.scss",
|
||||||
@@ -155,9 +163,16 @@
|
|||||||
"glob": "**/*.svg",
|
"glob": "**/*.svg",
|
||||||
"input": "node_modules/ionicons/dist/ionicons/svg",
|
"input": "node_modules/ionicons/dist/ionicons/svg",
|
||||||
"output": "./svg"
|
"output": "./svg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "node_modules/@taiga-ui/icons/src",
|
||||||
|
"output": "assets/taiga-ui/icons"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
|
"node_modules/@taiga-ui/core/styles/taiga-ui-theme.less",
|
||||||
|
"node_modules/@taiga-ui/core/styles/taiga-ui-fonts.less",
|
||||||
"projects/shared/styles/variables.scss",
|
"projects/shared/styles/variables.scss",
|
||||||
"projects/shared/styles/global.scss",
|
"projects/shared/styles/global.scss",
|
||||||
"projects/shared/styles/shared.scss",
|
"projects/shared/styles/shared.scss",
|
||||||
@@ -285,9 +300,16 @@
|
|||||||
"glob": "**/*.svg",
|
"glob": "**/*.svg",
|
||||||
"input": "node_modules/ionicons/dist/ionicons/svg",
|
"input": "node_modules/ionicons/dist/ionicons/svg",
|
||||||
"output": "./svg"
|
"output": "./svg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "node_modules/@taiga-ui/icons/src",
|
||||||
|
"output": "assets/taiga-ui/icons"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
|
"node_modules/@taiga-ui/core/styles/taiga-ui-theme.less",
|
||||||
|
"node_modules/@taiga-ui/core/styles/taiga-ui-fonts.less",
|
||||||
"projects/shared/styles/variables.scss",
|
"projects/shared/styles/variables.scss",
|
||||||
"projects/shared/styles/global.scss",
|
"projects/shared/styles/global.scss",
|
||||||
"projects/shared/styles/shared.scss",
|
"projects/shared/styles/shared.scss",
|
||||||
@@ -405,9 +427,16 @@
|
|||||||
"glob": "**/*.svg",
|
"glob": "**/*.svg",
|
||||||
"input": "node_modules/ionicons/dist/ionicons/svg",
|
"input": "node_modules/ionicons/dist/ionicons/svg",
|
||||||
"output": "./svg"
|
"output": "./svg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "node_modules/@taiga-ui/icons/src",
|
||||||
|
"output": "assets/taiga-ui/icons"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
|
"node_modules/@taiga-ui/core/styles/taiga-ui-theme.less",
|
||||||
|
"node_modules/@taiga-ui/core/styles/taiga-ui-fonts.less",
|
||||||
"projects/shared/styles/variables.scss",
|
"projects/shared/styles/variables.scss",
|
||||||
"projects/shared/styles/global.scss",
|
"projects/shared/styles/global.scss",
|
||||||
"projects/shared/styles/shared.scss",
|
"projects/shared/styles/shared.scss",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"useMocks": true,
|
"useMocks": true,
|
||||||
|
"enableWidgets": false,
|
||||||
"packageArch": "aarch64",
|
"packageArch": "aarch64",
|
||||||
"osArch": "raspberrypi",
|
"osArch": "raspberrypi",
|
||||||
"ui": {
|
"ui": {
|
||||||
|
|||||||
1179
frontend/package-lock.json
generated
1179
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -17,9 +17,11 @@
|
|||||||
"build:install-wiz": "ng run install-wizard:build",
|
"build:install-wiz": "ng run install-wizard:build",
|
||||||
"build:setup": "ng run setup-wizard:build",
|
"build:setup": "ng run setup-wizard:build",
|
||||||
"build:ui": "ng run ui:build",
|
"build:ui": "ng run ui:build",
|
||||||
|
"build:ui:stats": "ng run ui:build --stats-json",
|
||||||
"build:all": "npm run build:deps && npm run build:dui && npm run build:setup && npm run build:ui && npm run build:install-wiz",
|
"build:all": "npm run build:deps && npm run build:dui && npm run build:setup && npm run build:ui && npm run build:install-wiz",
|
||||||
"build:shared": "ng build shared",
|
"build:shared": "ng build shared",
|
||||||
"build:marketplace": "npm run build:shared && ng build marketplace",
|
"build:marketplace": "npm run build:shared && ng build marketplace",
|
||||||
|
"analyze:ui": "webpack-bundle-analyzer dist/ui/stats.json",
|
||||||
"publish:shared": "npm run build:shared && npm publish ./dist/shared --access public",
|
"publish:shared": "npm run build:shared && npm publish ./dist/shared --access public",
|
||||||
"publish:marketplace": "npm run build:marketplace && npm publish ./dist/marketplace --access public",
|
"publish:marketplace": "npm run build:marketplace && npm publish ./dist/marketplace --access public",
|
||||||
"start:dui": "npm run-script build-config && ionic serve --project diagnostic-ui --host 0.0.0.0",
|
"start:dui": "npm run-script build-config && ionic serve --project diagnostic-ui --host 0.0.0.0",
|
||||||
@@ -39,12 +41,18 @@
|
|||||||
"@angular/platform-browser-dynamic": "^14.1.0",
|
"@angular/platform-browser-dynamic": "^14.1.0",
|
||||||
"@angular/router": "^14.1.0",
|
"@angular/router": "^14.1.0",
|
||||||
"@ionic/angular": "^6.1.15",
|
"@ionic/angular": "^6.1.15",
|
||||||
|
"@materia-ui/ngx-monaco-editor": "^6.0.0",
|
||||||
"@ng-web-apis/common": "^2.0.0",
|
"@ng-web-apis/common": "^2.0.0",
|
||||||
"@ng-web-apis/mutation-observer": "^2.0.0",
|
"@ng-web-apis/mutation-observer": "^2.0.0",
|
||||||
"@ng-web-apis/resize-observer": "^2.0.0",
|
"@ng-web-apis/resize-observer": "^2.0.0",
|
||||||
"@materia-ui/ngx-monaco-editor": "^6.0.0",
|
|
||||||
"@start9labs/argon2": "^0.1.0",
|
"@start9labs/argon2": "^0.1.0",
|
||||||
"@start9labs/emver": "^0.1.5",
|
"@start9labs/emver": "^0.1.5",
|
||||||
|
"@taiga-ui/addon-charts": "^3.14.0",
|
||||||
|
"@taiga-ui/cdk": "^3.14.0",
|
||||||
|
"@taiga-ui/core": "^3.14.0",
|
||||||
|
"@taiga-ui/icons": "^3.14.0",
|
||||||
|
"@taiga-ui/kit": "^3.14.0",
|
||||||
|
"@taiga-ui/styles": "^3.14.0",
|
||||||
"angular-svg-round-progressbar": "^9.0.0",
|
"angular-svg-round-progressbar": "^9.0.0",
|
||||||
"ansi-to-html": "^0.7.2",
|
"ansi-to-html": "^0.7.2",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
@@ -93,7 +101,8 @@
|
|||||||
"raw-loader": "^4.0.2",
|
"raw-loader": "^4.0.2",
|
||||||
"ts-node": "^10.7.0",
|
"ts-node": "^10.7.0",
|
||||||
"tslint": "^6.1.3",
|
"tslint": "^6.1.3",
|
||||||
"typescript": "^4.6.3"
|
"typescript": "^4.6.3",
|
||||||
|
"webpack-bundle-analyzer": "^4.8.0"
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
<ion-app>
|
<tui-root>
|
||||||
<ion-router-outlet></ion-router-outlet>
|
<ion-app>
|
||||||
</ion-app>
|
<ion-router-outlet></ion-router-outlet>
|
||||||
|
</ion-app>
|
||||||
|
</tui-root>
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
tui-root {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { BrowserModule } from '@angular/platform-browser'
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
|
||||||
import { RouteReuseStrategy } from '@angular/router'
|
import { RouteReuseStrategy } from '@angular/router'
|
||||||
import { IonicModule, IonicRouteStrategy } from '@ionic/angular'
|
import { IonicModule, IonicRouteStrategy } from '@ionic/angular'
|
||||||
|
import { TuiRootModule } from '@taiga-ui/core'
|
||||||
import { AppComponent } from './app.component'
|
import { AppComponent } from './app.component'
|
||||||
import { AppRoutingModule } from './app-routing.module'
|
import { AppRoutingModule } from './app-routing.module'
|
||||||
import { HttpClientModule } from '@angular/common/http'
|
import { HttpClientModule } from '@angular/common/http'
|
||||||
@@ -19,11 +20,12 @@ const {
|
|||||||
declarations: [AppComponent],
|
declarations: [AppComponent],
|
||||||
imports: [
|
imports: [
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
BrowserModule,
|
BrowserAnimationsModule,
|
||||||
IonicModule.forRoot({
|
IonicModule.forRoot({
|
||||||
mode: 'md',
|
mode: 'md',
|
||||||
}),
|
}),
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
|
TuiRootModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
<ion-app>
|
<tui-root>
|
||||||
<ion-router-outlet></ion-router-outlet>
|
<ion-app>
|
||||||
</ion-app>
|
<ion-router-outlet></ion-router-outlet>
|
||||||
|
</ion-app>
|
||||||
|
</tui-root>
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
tui-root {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { BrowserModule } from '@angular/platform-browser'
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
|
||||||
import { RouteReuseStrategy } from '@angular/router'
|
import { RouteReuseStrategy } from '@angular/router'
|
||||||
import { IonicModule, IonicRouteStrategy } from '@ionic/angular'
|
import { IonicModule, IonicRouteStrategy } from '@ionic/angular'
|
||||||
|
import { TuiRootModule } from '@taiga-ui/core'
|
||||||
import { AppComponent } from './app.component'
|
import { AppComponent } from './app.component'
|
||||||
import { AppRoutingModule } from './app-routing.module'
|
import { AppRoutingModule } from './app-routing.module'
|
||||||
import { HttpClientModule } from '@angular/common/http'
|
import { HttpClientModule } from '@angular/common/http'
|
||||||
@@ -19,11 +20,12 @@ const {
|
|||||||
declarations: [AppComponent],
|
declarations: [AppComponent],
|
||||||
imports: [
|
imports: [
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
BrowserModule,
|
BrowserAnimationsModule,
|
||||||
IonicModule.forRoot({
|
IonicModule.forRoot({
|
||||||
mode: 'md',
|
mode: 'md',
|
||||||
}),
|
}),
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
|
TuiRootModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
"@angular/core": ">=13.2.0",
|
"@angular/core": ">=13.2.0",
|
||||||
"@ionic/angular": ">=6.0.0",
|
"@ionic/angular": ">=6.0.0",
|
||||||
"@start9labs/shared": ">=0.3.0",
|
"@start9labs/shared": ">=0.3.0",
|
||||||
|
"@taiga-ui/cdk": ">=3.0.0",
|
||||||
"fuse.js": "^6.4.6"
|
"fuse.js": "^6.4.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<ion-grid>
|
<ion-grid>
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col sizeSm="8" offset-sm="2" sizeLg="6" offset-lg="3">
|
<ion-col responsiveCol class="column" sizeSm="8" sizeLg="6">
|
||||||
<ion-toolbar color="transparent" class="ion-text-left">
|
<ion-toolbar color="transparent" class="ion-text-left">
|
||||||
<ion-searchbar
|
<ion-searchbar
|
||||||
color="dark"
|
color="dark"
|
||||||
|
|||||||
@@ -2,3 +2,7 @@
|
|||||||
display: block;
|
display: block;
|
||||||
padding-bottom: 32px;
|
padding-bottom: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.column {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { FormsModule } from '@angular/forms'
|
import { FormsModule } from '@angular/forms'
|
||||||
import { IonicModule } from '@ionic/angular'
|
import { IonicModule } from '@ionic/angular'
|
||||||
|
import { ResponsiveColModule } from '@start9labs/shared'
|
||||||
|
|
||||||
import { SearchComponent } from './search.component'
|
import { SearchComponent } from './search.component'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [IonicModule, FormsModule],
|
imports: [IonicModule, FormsModule, ResponsiveColModule],
|
||||||
declarations: [SearchComponent],
|
declarations: [SearchComponent],
|
||||||
exports: [SearchComponent],
|
exports: [SearchComponent],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col
|
<ion-col
|
||||||
*ngFor="let pkg of ['', '', '', '']"
|
*ngFor="let pkg of ['', '', '', '']"
|
||||||
|
responsiveCol
|
||||||
sizeXs="12"
|
sizeXs="12"
|
||||||
sizeSm="12"
|
sizeSm="12"
|
||||||
sizeMd="6"
|
sizeMd="6"
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { CommonModule } from '@angular/common'
|
import { CommonModule } from '@angular/common'
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { IonicModule } from '@ionic/angular'
|
import { IonicModule } from '@ionic/angular'
|
||||||
|
import { ResponsiveColModule } from '@start9labs/shared'
|
||||||
|
|
||||||
import { SkeletonComponent } from './skeleton.component'
|
import { SkeletonComponent } from './skeleton.component'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [CommonModule, IonicModule],
|
imports: [CommonModule, IonicModule, ResponsiveColModule],
|
||||||
declarations: [SkeletonComponent],
|
declarations: [SkeletonComponent],
|
||||||
exports: [SkeletonComponent],
|
exports: [SkeletonComponent],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<ion-content>
|
<ion-content class="with-widgets">
|
||||||
<ng-container *ngIf="notes$ | async as notes; else loading">
|
<ng-container *ngIf="notes$ | async as notes; else loading">
|
||||||
<div *ngFor="let note of notes | keyvalue: asIsOrder">
|
<div *ngFor="let note of notes | keyvalue: asIsOrder">
|
||||||
<ion-button
|
<ion-button
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<p class="version">{{ note.key | displayEmver }}</p>
|
<p class="version">{{ note.key | displayEmver }}</p>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<ion-card
|
<ion-card
|
||||||
elementRef
|
tuiElement
|
||||||
#element="elementRef"
|
#element="elementRef"
|
||||||
class="panel"
|
class="panel"
|
||||||
color="light"
|
color="light"
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import {
|
|||||||
EmverPipesModule,
|
EmverPipesModule,
|
||||||
MarkdownPipeModule,
|
MarkdownPipeModule,
|
||||||
TextSpinnerComponentModule,
|
TextSpinnerComponentModule,
|
||||||
ElementModule,
|
|
||||||
} from '@start9labs/shared'
|
} from '@start9labs/shared'
|
||||||
|
import { TuiElementModule } from '@taiga-ui/cdk'
|
||||||
|
|
||||||
import { ReleaseNotesComponent } from './release-notes.component'
|
import { ReleaseNotesComponent } from './release-notes.component'
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ import { ReleaseNotesComponent } from './release-notes.component'
|
|||||||
TextSpinnerComponentModule,
|
TextSpinnerComponentModule,
|
||||||
EmverPipesModule,
|
EmverPipesModule,
|
||||||
MarkdownPipeModule,
|
MarkdownPipeModule,
|
||||||
ElementModule,
|
TuiElementModule,
|
||||||
],
|
],
|
||||||
declarations: [ReleaseNotesComponent],
|
declarations: [ReleaseNotesComponent],
|
||||||
exports: [ReleaseNotesComponent],
|
exports: [ReleaseNotesComponent],
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<ion-item-divider>Additional Info</ion-item-divider>
|
<ion-item-divider>Additional Info</ion-item-divider>
|
||||||
<ion-grid *ngIf="pkg.manifest as manifest">
|
<ion-grid *ngIf="pkg.manifest as manifest">
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col sizeXs="12" sizeMd="6">
|
<ion-col responsiveCol sizeXs="12" sizeMd="6">
|
||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<ion-item
|
<ion-item
|
||||||
*ngIf="manifest['git-hash'] as gitHash; else noHash"
|
*ngIf="manifest['git-hash'] as gitHash; else noHash"
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-item-group>
|
</ion-item-group>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
<ion-col sizeXs="12" sizeMd="6">
|
<ion-col responsiveCol sizeXs="12" sizeMd="6">
|
||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<ion-item
|
<ion-item
|
||||||
[href]="manifest['upstream-repo']"
|
[href]="manifest['upstream-repo']"
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { CommonModule } from '@angular/common'
|
import { CommonModule } from '@angular/common'
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { IonicModule } from '@ionic/angular'
|
import { IonicModule } from '@ionic/angular'
|
||||||
import { MarkdownModule } from '@start9labs/shared'
|
import { MarkdownModule, ResponsiveColModule } from '@start9labs/shared'
|
||||||
|
|
||||||
import { AdditionalComponent } from './additional.component'
|
import { AdditionalComponent } from './additional.component'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [CommonModule, IonicModule, MarkdownModule],
|
imports: [CommonModule, IonicModule, MarkdownModule, ResponsiveColModule],
|
||||||
declarations: [AdditionalComponent],
|
declarations: [AdditionalComponent],
|
||||||
exports: [AdditionalComponent],
|
exports: [AdditionalComponent],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col
|
<ion-col
|
||||||
*ngFor="let dep of pkg.manifest.dependencies | keyvalue"
|
*ngFor="let dep of pkg.manifest.dependencies | keyvalue"
|
||||||
|
responsiveCol
|
||||||
sizeSm="12"
|
sizeSm="12"
|
||||||
sizeMd="6"
|
sizeMd="6"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ import { CommonModule } from '@angular/common'
|
|||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { RouterModule } from '@angular/router'
|
import { RouterModule } from '@angular/router'
|
||||||
import { IonicModule } from '@ionic/angular'
|
import { IonicModule } from '@ionic/angular'
|
||||||
import { EmverPipesModule, SharedPipesModule } from '@start9labs/shared'
|
import {
|
||||||
|
EmverPipesModule,
|
||||||
|
ResponsiveColModule,
|
||||||
|
SharedPipesModule,
|
||||||
|
} from '@start9labs/shared'
|
||||||
|
|
||||||
import { DependenciesComponent } from './dependencies.component'
|
import { DependenciesComponent } from './dependencies.component'
|
||||||
|
|
||||||
@@ -13,6 +17,7 @@ import { DependenciesComponent } from './dependencies.component'
|
|||||||
IonicModule,
|
IonicModule,
|
||||||
SharedPipesModule,
|
SharedPipesModule,
|
||||||
EmverPipesModule,
|
EmverPipesModule,
|
||||||
|
ResponsiveColModule,
|
||||||
],
|
],
|
||||||
declarations: [DependenciesComponent],
|
declarations: [DependenciesComponent],
|
||||||
exports: [DependenciesComponent],
|
exports: [DependenciesComponent],
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
<ion-app>
|
<tui-root>
|
||||||
<ion-router-outlet></ion-router-outlet>
|
<ion-app>
|
||||||
</ion-app>
|
<ion-router-outlet></ion-router-outlet>
|
||||||
|
</ion-app>
|
||||||
|
</tui-root>
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
tui-root {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { BrowserModule } from '@angular/platform-browser'
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
|
||||||
import { RouteReuseStrategy } from '@angular/router'
|
import { RouteReuseStrategy } from '@angular/router'
|
||||||
import { HttpClientModule } from '@angular/common/http'
|
import { HttpClientModule } from '@angular/common/http'
|
||||||
|
import { TuiRootModule } from '@taiga-ui/core'
|
||||||
import { ApiService } from './services/api/api.service'
|
import { ApiService } from './services/api/api.service'
|
||||||
import { MockApiService } from './services/api/mock-api.service'
|
import { MockApiService } from './services/api/mock-api.service'
|
||||||
import { LiveApiService } from './services/api/live-api.service'
|
import { LiveApiService } from './services/api/live-api.service'
|
||||||
@@ -27,7 +28,7 @@ const {
|
|||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [AppComponent],
|
declarations: [AppComponent],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserAnimationsModule,
|
||||||
IonicModule.forRoot({
|
IonicModule.forRoot({
|
||||||
mode: 'md',
|
mode: 'md',
|
||||||
navAnimation: iosTransitionAnimation,
|
navAnimation: iosTransitionAnimation,
|
||||||
@@ -39,6 +40,7 @@ const {
|
|||||||
LoadingPageModule,
|
LoadingPageModule,
|
||||||
RecoverPageModule,
|
RecoverPageModule,
|
||||||
TransferPageModule,
|
TransferPageModule,
|
||||||
|
TuiRootModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { NgModule } from '@angular/core'
|
|||||||
import { CommonModule } from '@angular/common'
|
import { CommonModule } from '@angular/common'
|
||||||
import { IonicModule } from '@ionic/angular'
|
import { IonicModule } from '@ionic/angular'
|
||||||
import { FormsModule } from '@angular/forms'
|
import { FormsModule } from '@angular/forms'
|
||||||
|
import { ResponsiveColModule } from '@start9labs/shared'
|
||||||
|
|
||||||
import { SuccessPage } from './success.page'
|
import { SuccessPage } from './success.page'
|
||||||
import { PasswordPageModule } from '../../modals/password/password.module'
|
import { PasswordPageModule } from '../../modals/password/password.module'
|
||||||
import { SuccessPageRoutingModule } from './success-routing.module'
|
import { SuccessPageRoutingModule } from './success-routing.module'
|
||||||
@@ -14,6 +16,7 @@ import { DownloadDocComponent } from './download-doc/download-doc.component'
|
|||||||
IonicModule,
|
IonicModule,
|
||||||
PasswordPageModule,
|
PasswordPageModule,
|
||||||
SuccessPageRoutingModule,
|
SuccessPageRoutingModule,
|
||||||
|
ResponsiveColModule,
|
||||||
],
|
],
|
||||||
declarations: [SuccessPage, DownloadDocComponent],
|
declarations: [SuccessPage, DownloadDocComponent],
|
||||||
exports: [SuccessPage],
|
exports: [SuccessPage],
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<ng-container *ngIf="isKiosk; else notKiosk">
|
<ng-container *ngIf="isKiosk; else notKiosk">
|
||||||
<ion-card>
|
<ion-card>
|
||||||
<ion-row class="ion-align-items-center">
|
<ion-row class="ion-align-items-center">
|
||||||
<ion-col size-xs="12" class="ion-text-center">
|
<ion-col responsiveCol sizeXs="12" class="ion-text-center">
|
||||||
<div class="inline" style="margin-bottom: 3rem">
|
<div class="inline" style="margin-bottom: 3rem">
|
||||||
<ion-icon
|
<ion-icon
|
||||||
name="checkmark-circle-outline"
|
name="checkmark-circle-outline"
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
<ng-template #notKiosk>
|
<ng-template #notKiosk>
|
||||||
<ion-card>
|
<ion-card>
|
||||||
<ion-row class="ion-align-items-center">
|
<ion-row class="ion-align-items-center">
|
||||||
<ion-col size-xs="12" class="ion-text-center">
|
<ion-col responsiveCol sizeXs="12" class="ion-text-center">
|
||||||
<div style="margin-bottom: 4rem">
|
<div style="margin-bottom: 4rem">
|
||||||
<div class="inline">
|
<div class="inline">
|
||||||
<ion-icon
|
<ion-icon
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
"@ionic/angular": ">=6.0.0",
|
"@ionic/angular": ">=6.0.0",
|
||||||
"@ng-web-apis/mutation-observer": ">=2.0.0",
|
"@ng-web-apis/mutation-observer": ">=2.0.0",
|
||||||
"@ng-web-apis/resize-observer": ">=2.0.0",
|
"@ng-web-apis/resize-observer": ">=2.0.0",
|
||||||
"@start9labs/emver": "^0.1.5"
|
"@start9labs/emver": "^0.1.5",
|
||||||
|
"@taiga-ui/cdk": ">=3.0.0"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
"./assets/": "./assets/"
|
"./assets/": "./assets/"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<div (elasticContainer)="height = $event">
|
<div class="wrapper" (elasticContainer)="height = $event">
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,3 +3,8 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: height 0.25s;
|
transition: height 0.25s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
padding-top: 1px;
|
||||||
|
margin-top: -1px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export class ElasticContainerDirective {
|
|||||||
inject(ResizeObserverService),
|
inject(ResizeObserverService),
|
||||||
inject(MutationObserverService),
|
inject(MutationObserverService),
|
||||||
).pipe(
|
).pipe(
|
||||||
map(() => this.elementRef.nativeElement.clientHeight),
|
map(() => this.elementRef.nativeElement.clientHeight - 1), // Compensate for padding
|
||||||
distinctUntilChanged(),
|
distinctUntilChanged(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import { Directive, ElementRef, Inject } from '@angular/core'
|
|
||||||
|
|
||||||
@Directive({
|
|
||||||
selector: '[elementRef]',
|
|
||||||
exportAs: 'elementRef',
|
|
||||||
})
|
|
||||||
export class ElementDirective<T extends Element> extends ElementRef<T> {
|
|
||||||
constructor(@Inject(ElementRef) { nativeElement }: ElementRef<T>) {
|
|
||||||
super(nativeElement)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { NgModule } from '@angular/core'
|
|
||||||
|
|
||||||
import { ElementDirective } from './element.directive'
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [ElementDirective],
|
|
||||||
exports: [ElementDirective],
|
|
||||||
})
|
|
||||||
export class ElementModule {}
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import {
|
||||||
|
Directive,
|
||||||
|
ElementRef,
|
||||||
|
Inject,
|
||||||
|
InjectionToken,
|
||||||
|
Input,
|
||||||
|
NgZone,
|
||||||
|
} from '@angular/core'
|
||||||
|
import { ResizeObserverService } from '@ng-web-apis/resize-observer'
|
||||||
|
import { distinctUntilChanged, Observable } from 'rxjs'
|
||||||
|
import { map } from 'rxjs/operators'
|
||||||
|
import { tuiZonefree } from '@taiga-ui/cdk'
|
||||||
|
|
||||||
|
export type Step = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not exported:
|
||||||
|
* https://github.com/ionic-team/ionic-framework/blob/main/core/src/utils/media.ts
|
||||||
|
*
|
||||||
|
* export const SIZE_TO_MEDIA: any = {
|
||||||
|
* xs: '(min-width: 0px)',
|
||||||
|
* sm: '(min-width: 576px)',
|
||||||
|
* md: '(min-width: 768px)',
|
||||||
|
* lg: '(min-width: 992px)',
|
||||||
|
* xl: '(min-width: 1200px)',
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
export const BREAKPOINTS = new InjectionToken<readonly [number, Step][]>(
|
||||||
|
'BREAKPOINTS',
|
||||||
|
{
|
||||||
|
factory: () => [
|
||||||
|
[1200, 'xl'],
|
||||||
|
[992, 'lg'],
|
||||||
|
[768, 'md'],
|
||||||
|
[576, 'sm'],
|
||||||
|
[0, 'xs'],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: '[responsiveColViewport]',
|
||||||
|
exportAs: 'viewport',
|
||||||
|
providers: [ResizeObserverService],
|
||||||
|
})
|
||||||
|
export class ResponsiveColViewportDirective extends Observable<Step> {
|
||||||
|
@Input()
|
||||||
|
responsiveColViewport: Observable<Step> | '' = ''
|
||||||
|
|
||||||
|
private readonly stream$ = this.resize$.pipe(
|
||||||
|
map(() => this.elementRef.nativeElement.clientWidth),
|
||||||
|
map(width => this.breakpoints.find(([step]) => width >= step)?.[1] || 'xs'),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
tuiZonefree(this.zone),
|
||||||
|
)
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(BREAKPOINTS)
|
||||||
|
private readonly breakpoints: readonly [number, Step][],
|
||||||
|
private readonly resize$: ResizeObserverService,
|
||||||
|
private readonly elementRef: ElementRef<HTMLElement>,
|
||||||
|
private readonly zone: NgZone,
|
||||||
|
) {
|
||||||
|
super(subscriber =>
|
||||||
|
(this.responsiveColViewport || this.stream$).subscribe(subscriber),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { Directive, OnInit, Optional } from '@angular/core'
|
||||||
|
import { TuiDestroyService } from '@taiga-ui/cdk'
|
||||||
|
import {
|
||||||
|
ResponsiveColViewportDirective,
|
||||||
|
Step,
|
||||||
|
} from './responsive-col-viewport.directive'
|
||||||
|
import { IonCol } from '@ionic/angular'
|
||||||
|
import { takeUntil } from 'rxjs'
|
||||||
|
|
||||||
|
const SIZE: readonly Step[] = ['xl', 'lg', 'md', 'sm', 'xs']
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: 'ion-col[responsiveCol]',
|
||||||
|
providers: [TuiDestroyService],
|
||||||
|
})
|
||||||
|
export class ResponsiveColDirective implements OnInit {
|
||||||
|
readonly size: Record<Step, string | undefined> = {
|
||||||
|
xs: '12',
|
||||||
|
sm: '6',
|
||||||
|
md: '4',
|
||||||
|
lg: '3',
|
||||||
|
xl: '2',
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Optional()
|
||||||
|
viewport$: ResponsiveColViewportDirective | null,
|
||||||
|
destroy$: TuiDestroyService,
|
||||||
|
private readonly col: IonCol,
|
||||||
|
) {
|
||||||
|
viewport$?.pipe(takeUntil(destroy$)).subscribe(size => {
|
||||||
|
const max = this.size[size] || this.findMax(size)
|
||||||
|
|
||||||
|
this.col.sizeLg = max
|
||||||
|
this.col.sizeMd = max
|
||||||
|
this.col.sizeSm = max
|
||||||
|
this.col.sizeXl = max
|
||||||
|
this.col.sizeXs = max
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.size.lg = this.col.sizeLg
|
||||||
|
this.size.md = this.col.sizeMd
|
||||||
|
this.size.sm = this.col.sizeSm
|
||||||
|
this.size.xl = this.col.sizeXl
|
||||||
|
this.size.xs = this.col.sizeXs
|
||||||
|
}
|
||||||
|
|
||||||
|
private findMax(current: Step): string | undefined {
|
||||||
|
const start = SIZE.indexOf(current) - 1
|
||||||
|
const max = SIZE.find((size, i) => i > start && this.size[size]) || current
|
||||||
|
|
||||||
|
return this.size[max]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { NgModule } from '@angular/core'
|
||||||
|
|
||||||
|
import { ResponsiveColViewportDirective } from './responsive-col-viewport.directive'
|
||||||
|
import { ResponsiveColDirective } from './responsive-col.directive'
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [ResponsiveColDirective, ResponsiveColViewportDirective],
|
||||||
|
exports: [ResponsiveColDirective, ResponsiveColViewportDirective],
|
||||||
|
})
|
||||||
|
export class ResponsiveColModule {}
|
||||||
@@ -22,8 +22,9 @@ export * from './components/toast/toast.component'
|
|||||||
export * from './components/toast/toast.module'
|
export * from './components/toast/toast.module'
|
||||||
export * from './components/toast/toast-button.directive'
|
export * from './components/toast/toast-button.directive'
|
||||||
|
|
||||||
export * from './directives/element/element.directive'
|
export * from './directives/responsive-col/responsive-col.directive'
|
||||||
export * from './directives/element/element.module'
|
export * from './directives/responsive-col/responsive-col.module'
|
||||||
|
export * from './directives/responsive-col/responsive-col-viewport.directive'
|
||||||
export * from './directives/safe-links/safe-links.directive'
|
export * from './directives/safe-links/safe-links.directive'
|
||||||
export * from './directives/safe-links/safe-links.module'
|
export * from './directives/safe-links/safe-links.module'
|
||||||
|
|
||||||
@@ -40,7 +41,6 @@ export * from './pipes/shared/trust.pipe'
|
|||||||
export * from './pipes/unit-conversion/unit-conversion.module'
|
export * from './pipes/unit-conversion/unit-conversion.module'
|
||||||
export * from './pipes/unit-conversion/unit-conversion.pipe'
|
export * from './pipes/unit-conversion/unit-conversion.pipe'
|
||||||
|
|
||||||
export * from './services/destroy.service'
|
|
||||||
export * from './services/download-html.service'
|
export * from './services/download-html.service'
|
||||||
export * from './services/emver.service'
|
export * from './services/emver.service'
|
||||||
export * from './services/error-toast.service'
|
export * from './services/error-toast.service'
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import { Injectable, OnDestroy } from '@angular/core'
|
|
||||||
import { ReplaySubject } from 'rxjs'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Observable abstraction over ngOnDestroy to use with takeUntil
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class DestroyService extends ReplaySubject<void> implements OnDestroy {
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.next()
|
|
||||||
this.complete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@ export type WorkspaceConfig = {
|
|||||||
osArch: 'aarch64' | 'x86_64' | 'raspberrypi'
|
osArch: 'aarch64' | 'x86_64' | 'raspberrypi'
|
||||||
gitHash: string
|
gitHash: string
|
||||||
useMocks: boolean
|
useMocks: boolean
|
||||||
|
enableWidgets: boolean
|
||||||
// each key corresponds to a project and values adjust settings for that project, eg: ui, install-wizard, setup-wizard, diagnostic-ui
|
// each key corresponds to a project and values adjust settings for that project, eg: ui, install-wizard, setup-wizard, diagnostic-ui
|
||||||
ui: {
|
ui: {
|
||||||
api: {
|
api: {
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ const routes: Routes = [
|
|||||||
scrollPositionRestoration: 'enabled',
|
scrollPositionRestoration: 'enabled',
|
||||||
preloadingStrategy: PreloadAllModules,
|
preloadingStrategy: PreloadAllModules,
|
||||||
initialNavigation: 'disabled',
|
initialNavigation: 'disabled',
|
||||||
useHash: true,
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
exports: [RouterModule],
|
exports: [RouterModule],
|
||||||
|
|||||||
@@ -1,33 +1,77 @@
|
|||||||
<ion-app appEnter>
|
<tui-root
|
||||||
<ion-content>
|
*ngIf="widgetDrawer$ | async as drawer"
|
||||||
<ion-split-pane
|
tuiMode="onDark"
|
||||||
contentId="main-content"
|
[style.--widgets-width.px]="drawer.open ? drawer.width : 0"
|
||||||
[disabled]="!(authService.isVerified$ | async)"
|
>
|
||||||
(ionSplitPaneVisible)="splitPaneVisible($event)"
|
<ion-app appEnter>
|
||||||
>
|
<ion-content>
|
||||||
<ion-menu contentId="main-content" type="overlay">
|
<ion-split-pane
|
||||||
<ion-content color="light" scrollY="false">
|
contentId="main-content"
|
||||||
<app-menu *ngIf="authService.isVerified$ | async"></app-menu>
|
[disabled]="!(authService.isVerified$ | async)"
|
||||||
</ion-content>
|
(ionSplitPaneVisible)="splitPaneVisible($event)"
|
||||||
</ion-menu>
|
>
|
||||||
<ion-router-outlet
|
<ion-menu
|
||||||
id="main-content"
|
contentId="main-content"
|
||||||
class="container"
|
type="overlay"
|
||||||
[class.container_offline]="
|
side="start"
|
||||||
(authService.isVerified$ | async) && !(connection.connected$ | async)
|
class="left-menu"
|
||||||
"
|
>
|
||||||
></ion-router-outlet>
|
<ion-content color="light" scrollY="false">
|
||||||
</ion-split-pane>
|
<app-menu *ngIf="authService.isVerified$ | async"></app-menu>
|
||||||
|
</ion-content>
|
||||||
|
</ion-menu>
|
||||||
|
|
||||||
<section appPreloader></section>
|
<ion-menu
|
||||||
</ion-content>
|
contentId="main-content"
|
||||||
<ion-footer>
|
type="overlay"
|
||||||
<footer appFooter></footer>
|
side="end"
|
||||||
</ion-footer>
|
class="right-menu container"
|
||||||
<ion-footer
|
[class.container_offline]="
|
||||||
*ngIf="(authService.isVerified$ | async) && !(sidebarOpen$ | async)"
|
(authService.isVerified$ | async) &&
|
||||||
>
|
!(connection.connected$ | async)
|
||||||
<connection-bar></connection-bar>
|
"
|
||||||
</ion-footer>
|
[class.right-menu_hidden]="!drawer.open"
|
||||||
<toast-container></toast-container>
|
[style.--side-width.px]="drawer.width"
|
||||||
</ion-app>
|
>
|
||||||
|
<div class="divider">
|
||||||
|
<button
|
||||||
|
class="widgets-button"
|
||||||
|
[class.widgets-button_collapse]="drawer.width === 600"
|
||||||
|
(click)="onResize(drawer)"
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
<widgets *ngIf="drawer.open" [wide]="drawer.width === 600"></widgets>
|
||||||
|
</ion-menu>
|
||||||
|
|
||||||
|
<ion-router-outlet
|
||||||
|
[responsiveColViewport]="viewport"
|
||||||
|
id="main-content"
|
||||||
|
class="container"
|
||||||
|
[class.container_offline]="
|
||||||
|
(authService.isVerified$ | async) &&
|
||||||
|
!(connection.connected$ | async)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<ion-content
|
||||||
|
#viewport="viewport"
|
||||||
|
responsiveColViewport
|
||||||
|
class="ion-padding with-widgets"
|
||||||
|
style="pointer-events: none; opacity: 0"
|
||||||
|
></ion-content>
|
||||||
|
</ion-router-outlet>
|
||||||
|
</ion-split-pane>
|
||||||
|
|
||||||
|
<section appPreloader></section>
|
||||||
|
</ion-content>
|
||||||
|
<ion-footer>
|
||||||
|
<footer appFooter></footer>
|
||||||
|
</ion-footer>
|
||||||
|
<ion-footer
|
||||||
|
*ngIf="(authService.isVerified$ | async) && !(sidebarOpen$ | async)"
|
||||||
|
>
|
||||||
|
<connection-bar></connection-bar>
|
||||||
|
</ion-footer>
|
||||||
|
<toast-container></toast-container>
|
||||||
|
</ion-app>
|
||||||
|
</tui-root>
|
||||||
|
<tui-theme-night></tui-theme-night>
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-split-pane {
|
tui-root {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-menu {
|
||||||
--side-max-width: 280px;
|
--side-max-width: 280px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12,4 +17,103 @@ ion-split-pane {
|
|||||||
&_offline {
|
&_offline {
|
||||||
filter: saturate(0.75) contrast(0.85);
|
filter: saturate(0.75) contrast(0.85);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@media screen and (max-width: 991.499px) {
|
||||||
|
--widgets-width: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-menu {
|
||||||
|
--side-max-width: 600px;
|
||||||
|
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1000;
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
top: 74px;
|
||||||
|
|
||||||
|
// For some reason *ngIf is broken upon first login
|
||||||
|
&_hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
height: 100%;
|
||||||
|
width: 10px;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
|
||||||
|
background: #e2e2e2;
|
||||||
|
|
||||||
|
z-index: 10;
|
||||||
|
opacity: 0.2;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
|
||||||
|
&:before,
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -78px;
|
||||||
|
left: 10px;
|
||||||
|
width: 60px;
|
||||||
|
height: 50px;
|
||||||
|
border-bottom-left-radius: 14px;
|
||||||
|
box-shadow: -14px 0 0 -1px #e2e2e2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
margin-top: 28px;
|
||||||
|
border-radius: 0;
|
||||||
|
border-top-left-radius: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.widgets-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
font-size: 0;
|
||||||
|
left: 100%;
|
||||||
|
width: 16px;
|
||||||
|
height: 60px;
|
||||||
|
margin-top: -30px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
background: inherit;
|
||||||
|
pointer-events: auto;
|
||||||
|
|
||||||
|
&:before,
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 3px;
|
||||||
|
width: 2px;
|
||||||
|
height: 8px;
|
||||||
|
background: black;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
margin-top: -5px;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&_collapse:before {
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&_collapse:after {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ import { PatchMonitorService } from './services/patch-monitor.service'
|
|||||||
import { ConnectionService } from './services/connection.service'
|
import { ConnectionService } from './services/connection.service'
|
||||||
import { Title } from '@angular/platform-browser'
|
import { Title } from '@angular/platform-browser'
|
||||||
import { ServerNameService } from './services/server-name.service'
|
import { ServerNameService } from './services/server-name.service'
|
||||||
|
import {
|
||||||
|
ClientStorageService,
|
||||||
|
WidgetDrawer,
|
||||||
|
} from './services/client-storage.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
@@ -16,6 +20,7 @@ import { ServerNameService } from './services/server-name.service'
|
|||||||
export class AppComponent implements OnDestroy {
|
export class AppComponent implements OnDestroy {
|
||||||
readonly subscription = merge(this.patchData, this.patchMonitor).subscribe()
|
readonly subscription = merge(this.patchData, this.patchMonitor).subscribe()
|
||||||
readonly sidebarOpen$ = this.splitPane.sidebarOpen$
|
readonly sidebarOpen$ = this.splitPane.sidebarOpen$
|
||||||
|
readonly widgetDrawer$ = this.clientStorageService.widgetDrawer$
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly titleService: Title,
|
private readonly titleService: Title,
|
||||||
@@ -25,6 +30,7 @@ export class AppComponent implements OnDestroy {
|
|||||||
private readonly serverNameService: ServerNameService,
|
private readonly serverNameService: ServerNameService,
|
||||||
readonly authService: AuthService,
|
readonly authService: AuthService,
|
||||||
readonly connection: ConnectionService,
|
readonly connection: ConnectionService,
|
||||||
|
readonly clientStorageService: ClientStorageService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -37,6 +43,13 @@ export class AppComponent implements OnDestroy {
|
|||||||
this.splitPane.sidebarOpen$.next(detail.visible)
|
this.splitPane.sidebarOpen$.next(detail.visible)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onResize(drawer: WidgetDrawer) {
|
||||||
|
this.clientStorageService.updateWidgetDrawer({
|
||||||
|
...drawer,
|
||||||
|
width: drawer.width === 400 ? 600 : 400,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.subscription.unsubscribe()
|
this.subscription.unsubscribe()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
|
import {
|
||||||
|
TuiDialogModule,
|
||||||
|
TuiModeModule,
|
||||||
|
TuiRootModule,
|
||||||
|
TuiThemeNightModule,
|
||||||
|
} from '@taiga-ui/core'
|
||||||
import { HttpClientModule } from '@angular/common/http'
|
import { HttpClientModule } from '@angular/common/http'
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
|
||||||
import { IonicModule } from '@ionic/angular'
|
import { IonicModule } from '@ionic/angular'
|
||||||
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor'
|
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor'
|
||||||
import { MarkdownModule, SharedPipesModule } from '@start9labs/shared'
|
import {
|
||||||
|
MarkdownModule,
|
||||||
|
ResponsiveColModule,
|
||||||
|
SharedPipesModule,
|
||||||
|
} from '@start9labs/shared'
|
||||||
|
|
||||||
import { AppComponent } from './app.component'
|
import { AppComponent } from './app.component'
|
||||||
import { AppRoutingModule } from './app-routing.module'
|
import { AppRoutingModule } from './app-routing.module'
|
||||||
@@ -18,6 +28,7 @@ import { APP_PROVIDERS } from './app.providers'
|
|||||||
import { PatchDbModule } from './services/patch-db/patch-db.module'
|
import { PatchDbModule } from './services/patch-db/patch-db.module'
|
||||||
import { ToastContainerModule } from './components/toast-container/toast-container.module'
|
import { ToastContainerModule } from './components/toast-container/toast-container.module'
|
||||||
import { ConnectionBarComponentModule } from './components/connection-bar/connection-bar.component.module'
|
import { ConnectionBarComponentModule } from './components/connection-bar/connection-bar.component.module'
|
||||||
|
import { WidgetsPageModule } from './pages/widgets/widgets.module'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [AppComponent],
|
declarations: [AppComponent],
|
||||||
@@ -41,6 +52,12 @@ import { ConnectionBarComponentModule } from './components/connection-bar/connec
|
|||||||
PatchDbModule,
|
PatchDbModule,
|
||||||
ToastContainerModule,
|
ToastContainerModule,
|
||||||
ConnectionBarComponentModule,
|
ConnectionBarComponentModule,
|
||||||
|
TuiRootModule,
|
||||||
|
TuiDialogModule,
|
||||||
|
TuiModeModule,
|
||||||
|
TuiThemeNightModule,
|
||||||
|
WidgetsPageModule,
|
||||||
|
ResponsiveColModule,
|
||||||
],
|
],
|
||||||
providers: APP_PROVIDERS,
|
providers: APP_PROVIDERS,
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<backup-drives-header [type]="type"></backup-drives-header>
|
<backup-drives-header [type]="type"></backup-drives-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding with-widgets">
|
||||||
<!-- loading -->
|
<!-- loading -->
|
||||||
<text-spinner
|
<text-spinner
|
||||||
*ngIf="loading; else loaded"
|
*ngIf="loading; else loaded"
|
||||||
|
|||||||
@@ -1,3 +1,16 @@
|
|||||||
|
<ng-container *ngIf="enableWidgets">
|
||||||
|
<ion-button class="widgets" color="dark" (click)="onWidgets()">
|
||||||
|
<ion-icon name="grid-outline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
<ion-button
|
||||||
|
*ngIf="widgetDrawer$ | async as drawer"
|
||||||
|
class="sidebar"
|
||||||
|
color="dark"
|
||||||
|
(click)="onSidebar(drawer)"
|
||||||
|
>
|
||||||
|
<ion-icon name="grid-outline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</ng-container>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<ion-badge
|
<ion-badge
|
||||||
*ngIf="!(sidebarOpen$ | async) && (unreadCount$ | async) as unreadCount"
|
*ngIf="!(sidebarOpen$ | async) && (unreadCount$ | async) as unreadCount"
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ import { NgModule } from '@angular/core'
|
|||||||
import { CommonModule } from '@angular/common'
|
import { CommonModule } from '@angular/common'
|
||||||
import { IonicModule } from '@ionic/angular'
|
import { IonicModule } from '@ionic/angular'
|
||||||
import { BadgeMenuComponent } from './badge-menu.component'
|
import { BadgeMenuComponent } from './badge-menu.component'
|
||||||
|
import { TuiLetModule } from '@taiga-ui/cdk'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
imports: [CommonModule, IonicModule, TuiLetModule],
|
||||||
declarations: [BadgeMenuComponent],
|
declarations: [BadgeMenuComponent],
|
||||||
imports: [CommonModule, IonicModule],
|
|
||||||
exports: [BadgeMenuComponent],
|
exports: [BadgeMenuComponent],
|
||||||
})
|
})
|
||||||
export class BadgeMenuComponentModule {}
|
export class BadgeMenuComponentModule {}
|
||||||
|
|||||||
@@ -1,6 +1,25 @@
|
|||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 992px) {
|
||||||
|
.widgets {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-right: 1vh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.md-badge {
|
.md-badge {
|
||||||
|
|||||||
@@ -2,6 +2,16 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'
|
|||||||
import { SplitPaneTracker } from 'src/app/services/split-pane.service'
|
import { SplitPaneTracker } from 'src/app/services/split-pane.service'
|
||||||
import { PatchDB } from 'patch-db-client'
|
import { PatchDB } from 'patch-db-client'
|
||||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||||
|
import { TuiDialogService } from '@taiga-ui/core'
|
||||||
|
import { WIDGETS_COMPONENT } from '../../pages/widgets/widgets.page'
|
||||||
|
import { WorkspaceConfig } from '@start9labs/shared'
|
||||||
|
import {
|
||||||
|
ClientStorageService,
|
||||||
|
WidgetDrawer,
|
||||||
|
} from 'src/app/services/client-storage.service'
|
||||||
|
|
||||||
|
const { enableWidgets } =
|
||||||
|
require('../../../../../../config.json') as WorkspaceConfig
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'badge-menu-button',
|
selector: 'badge-menu-button',
|
||||||
@@ -10,11 +20,30 @@ import { DataModel } from 'src/app/services/patch-db/data-model'
|
|||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class BadgeMenuComponent {
|
export class BadgeMenuComponent {
|
||||||
unreadCount$ = this.patch.watch$('server-info', 'unread-notification-count')
|
readonly unreadCount$ = this.patch.watch$(
|
||||||
sidebarOpen$ = this.splitPane.sidebarOpen$
|
'server-info',
|
||||||
|
'unread-notification-count',
|
||||||
|
)
|
||||||
|
readonly sidebarOpen$ = this.splitPane.sidebarOpen$
|
||||||
|
readonly widgetDrawer$ = this.clientStorageService.widgetDrawer$
|
||||||
|
|
||||||
|
readonly enableWidgets = enableWidgets
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly splitPane: SplitPaneTracker,
|
private readonly splitPane: SplitPaneTracker,
|
||||||
private readonly patch: PatchDB<DataModel>,
|
private readonly patch: PatchDB<DataModel>,
|
||||||
|
private readonly dialog: TuiDialogService,
|
||||||
|
private readonly clientStorageService: ClientStorageService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
onSidebar(drawer: WidgetDrawer) {
|
||||||
|
this.clientStorageService.updateWidgetDrawer({
|
||||||
|
...drawer,
|
||||||
|
open: !drawer.open,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onWidgets() {
|
||||||
|
this.dialog.open(WIDGETS_COMPONENT, { label: 'Widgets' }).subscribe()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
[scrollEvents]="true"
|
[scrollEvents]="true"
|
||||||
(ionScroll)="handleScroll($event)"
|
(ionScroll)="handleScroll($event)"
|
||||||
(ionScrollEnd)="handleScrollEnd()"
|
(ionScrollEnd)="handleScrollEnd()"
|
||||||
class="ion-padding"
|
class="ion-padding with-widgets"
|
||||||
>
|
>
|
||||||
<ion-infinite-scroll
|
<ion-infinite-scroll
|
||||||
id="scroller"
|
id="scroller"
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
||||||
<ion-footer>
|
<ion-footer class="with-widgets">
|
||||||
<ion-toolbar>
|
<ion-toolbar>
|
||||||
<div class="inline ion-padding-start">
|
<div class="inline ion-padding-start">
|
||||||
<ion-checkbox [(ngModel)]="autoScroll" color="dark"></ion-checkbox>
|
<ion-checkbox [(ngModel)]="autoScroll" color="dark"></ion-checkbox>
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ import { WebSocketSubjectConfig } from 'rxjs/webSocket'
|
|||||||
import {
|
import {
|
||||||
LogsRes,
|
LogsRes,
|
||||||
ServerLogsReq,
|
ServerLogsReq,
|
||||||
DestroyService,
|
|
||||||
ErrorToastService,
|
ErrorToastService,
|
||||||
toLocalIsoString,
|
toLocalIsoString,
|
||||||
Log,
|
Log,
|
||||||
DownloadHTMLService,
|
DownloadHTMLService,
|
||||||
} from '@start9labs/shared'
|
} from '@start9labs/shared'
|
||||||
|
import { TuiDestroyService } from '@taiga-ui/cdk'
|
||||||
import { RR } from 'src/app/services/api/api.types'
|
import { RR } from 'src/app/services/api/api.types'
|
||||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||||
import { ConnectionService } from 'src/app/services/connection.service'
|
import { ConnectionService } from 'src/app/services/connection.service'
|
||||||
@@ -39,7 +39,7 @@ var convert = new Convert({
|
|||||||
selector: 'logs',
|
selector: 'logs',
|
||||||
templateUrl: './logs.component.html',
|
templateUrl: './logs.component.html',
|
||||||
styleUrls: ['./logs.component.scss'],
|
styleUrls: ['./logs.component.scss'],
|
||||||
providers: [DestroyService, DownloadHTMLService],
|
providers: [TuiDestroyService, DownloadHTMLService],
|
||||||
})
|
})
|
||||||
export class LogsComponent {
|
export class LogsComponent {
|
||||||
@ViewChild(IonContent)
|
@ViewChild(IonContent)
|
||||||
@@ -68,7 +68,7 @@ export class LogsComponent {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly errToast: ErrorToastService,
|
private readonly errToast: ErrorToastService,
|
||||||
private readonly destroy$: DestroyService,
|
private readonly destroy$: TuiDestroyService,
|
||||||
private readonly api: ApiService,
|
private readonly api: ApiService,
|
||||||
private readonly loadingCtrl: LoadingController,
|
private readonly loadingCtrl: LoadingController,
|
||||||
private readonly downloadHtml: DownloadHTMLService,
|
private readonly downloadHtml: DownloadHTMLService,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<ion-row class="ion-justify-content-center ion-align-items-center">
|
<ion-row class="ion-justify-content-center ion-align-items-center">
|
||||||
<ion-col
|
<ion-col
|
||||||
*ngFor="let card of cards"
|
*ngFor="let card of cards"
|
||||||
|
responsiveCol
|
||||||
sizeLg="4"
|
sizeLg="4"
|
||||||
sizeSm="6"
|
sizeSm="6"
|
||||||
sizeXs="12"
|
sizeXs="12"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { NgModule } from '@angular/core'
|
|||||||
import { CommonModule } from '@angular/common'
|
import { CommonModule } from '@angular/common'
|
||||||
import { IonicModule } from '@ionic/angular'
|
import { IonicModule } from '@ionic/angular'
|
||||||
import { RouterModule } from '@angular/router'
|
import { RouterModule } from '@angular/router'
|
||||||
|
import { ResponsiveColModule } from '@start9labs/shared'
|
||||||
import { WidgetListComponent } from './widget-list.component'
|
import { WidgetListComponent } from './widget-list.component'
|
||||||
import { AnyLinkModule } from 'src/app/components/any-link/any-link.component.module'
|
import { AnyLinkModule } from 'src/app/components/any-link/any-link.component.module'
|
||||||
import { WidgetCardComponentModule } from '../widget-card/widget-card.component.module'
|
import { WidgetCardComponentModule } from '../widget-card/widget-card.component.module'
|
||||||
@@ -14,6 +15,7 @@ import { WidgetCardComponentModule } from '../widget-card/widget-card.component.
|
|||||||
RouterModule.forChild([]),
|
RouterModule.forChild([]),
|
||||||
AnyLinkModule,
|
AnyLinkModule,
|
||||||
WidgetCardComponentModule,
|
WidgetCardComponentModule,
|
||||||
|
ResponsiveColModule,
|
||||||
],
|
],
|
||||||
exports: [WidgetListComponent],
|
exports: [WidgetListComponent],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding-top">
|
<ion-content class="ion-padding-top with-widgets">
|
||||||
<ion-item-group *ngIf="pkg$ | async as pkg">
|
<ion-item-group *ngIf="pkg$ | async as pkg">
|
||||||
<!-- ** standard actions ** -->
|
<!-- ** standard actions ** -->
|
||||||
<ion-item-divider>Standard Actions</ion-item-divider>
|
<ion-item-divider>Standard Actions</ion-item-divider>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding-top">
|
<ion-content class="ion-padding-top with-widgets">
|
||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<!-- iff ui -->
|
<!-- iff ui -->
|
||||||
<ng-container *ngIf="ui">
|
<ng-container *ngIf="ui">
|
||||||
@@ -18,9 +18,9 @@
|
|||||||
<!-- other interface -->
|
<!-- other interface -->
|
||||||
<ng-container *ngIf="other.length">
|
<ng-container *ngIf="other.length">
|
||||||
<ion-item-divider>Machine Interfaces</ion-item-divider>
|
<ion-item-divider>Machine Interfaces</ion-item-divider>
|
||||||
<div *ngFor="let interface of other" style="margin-bottom: 30px;">
|
<div *ngFor="let interface of other" style="margin-bottom: 30px">
|
||||||
<app-interfaces-item [interface]="interface"></app-interfaces-item>
|
<app-interfaces-item [interface]="interface"></app-interfaces-item>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ion-item-group>
|
</ion-item-group>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { IonicModule } from '@ionic/angular'
|
|||||||
import { AppListPage } from './app-list.page'
|
import { AppListPage } from './app-list.page'
|
||||||
import {
|
import {
|
||||||
EmverPipesModule,
|
EmverPipesModule,
|
||||||
|
ResponsiveColModule,
|
||||||
TextSpinnerComponentModule,
|
TextSpinnerComponentModule,
|
||||||
} from '@start9labs/shared'
|
} from '@start9labs/shared'
|
||||||
import { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
|
import { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
|
||||||
@@ -35,6 +36,7 @@ const routes: Routes = [
|
|||||||
RouterModule.forChild(routes),
|
RouterModule.forChild(routes),
|
||||||
BadgeMenuComponentModule,
|
BadgeMenuComponentModule,
|
||||||
WidgetListComponentModule,
|
WidgetListComponentModule,
|
||||||
|
ResponsiveColModule,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
AppListPage,
|
AppListPage,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding with-widgets">
|
||||||
<!-- loaded -->
|
<!-- loaded -->
|
||||||
<ng-container *ngIf="pkgs$ | async as pkgs; else loading">
|
<ng-container *ngIf="pkgs$ | async as pkgs; else loading">
|
||||||
<ng-container *ngIf="!pkgs.length; else list">
|
<ng-container *ngIf="!pkgs.length; else list">
|
||||||
@@ -20,7 +20,12 @@
|
|||||||
<ng-template #list>
|
<ng-template #list>
|
||||||
<ion-grid>
|
<ion-grid>
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col *ngFor="let pkg of pkgs" sizeSm="12" sizeLg="6">
|
<ion-col
|
||||||
|
*ngFor="let pkg of pkgs"
|
||||||
|
responsiveCol
|
||||||
|
sizeSm="12"
|
||||||
|
sizeMd="6"
|
||||||
|
>
|
||||||
<app-list-pkg
|
<app-list-pkg
|
||||||
*ngIf="pkg | packageInfo | async as info"
|
*ngIf="pkg | packageInfo | async as info"
|
||||||
[pkg]="info"
|
[pkg]="info"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding with-widgets">
|
||||||
<skeleton-list *ngIf="loading"></skeleton-list>
|
<skeleton-list *ngIf="loading"></skeleton-list>
|
||||||
<ion-item-group *ngIf="!loading">
|
<ion-item-group *ngIf="!loading">
|
||||||
<ion-item *ngFor="let metric of metrics | keyvalue : asIsOrder">
|
<ion-item *ngFor="let metric of metrics | keyvalue : asIsOrder">
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding-top">
|
<ion-content class="ion-padding-top with-widgets">
|
||||||
<text-spinner
|
<text-spinner
|
||||||
*ngIf="loading; else loaded"
|
*ngIf="loading; else loaded"
|
||||||
text="Loading Properties"
|
text="Loading Properties"
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ import {
|
|||||||
PackageMainStatus,
|
PackageMainStatus,
|
||||||
} from 'src/app/services/patch-db/data-model'
|
} from 'src/app/services/patch-db/data-model'
|
||||||
import {
|
import {
|
||||||
DestroyService,
|
|
||||||
ErrorToastService,
|
ErrorToastService,
|
||||||
getPkgId,
|
getPkgId,
|
||||||
copyToClipboard,
|
copyToClipboard,
|
||||||
} from '@start9labs/shared'
|
} from '@start9labs/shared'
|
||||||
|
import { TuiDestroyService } from '@taiga-ui/cdk'
|
||||||
import { getValueByPointer } from 'fast-json-patch'
|
import { getValueByPointer } from 'fast-json-patch'
|
||||||
import { map, takeUntil } from 'rxjs/operators'
|
import { map, takeUntil } from 'rxjs/operators'
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ import { map, takeUntil } from 'rxjs/operators'
|
|||||||
selector: 'app-properties',
|
selector: 'app-properties',
|
||||||
templateUrl: './app-properties.page.html',
|
templateUrl: './app-properties.page.html',
|
||||||
styleUrls: ['./app-properties.page.scss'],
|
styleUrls: ['./app-properties.page.scss'],
|
||||||
providers: [DestroyService],
|
providers: [TuiDestroyService],
|
||||||
})
|
})
|
||||||
export class AppPropertiesPage {
|
export class AppPropertiesPage {
|
||||||
loading = true
|
loading = true
|
||||||
@@ -56,7 +56,7 @@ export class AppPropertiesPage {
|
|||||||
private readonly modalCtrl: ModalController,
|
private readonly modalCtrl: ModalController,
|
||||||
private readonly navCtrl: NavController,
|
private readonly navCtrl: NavController,
|
||||||
private readonly patch: PatchDB<DataModel>,
|
private readonly patch: PatchDB<DataModel>,
|
||||||
private readonly destroy$: DestroyService,
|
private readonly destroy$: TuiDestroyService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ionViewDidEnter() {
|
ionViewDidEnter() {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { CommonModule } from '@angular/common'
|
|||||||
import { Routes, RouterModule } from '@angular/router'
|
import { Routes, RouterModule } from '@angular/router'
|
||||||
import { IonicModule } from '@ionic/angular'
|
import { IonicModule } from '@ionic/angular'
|
||||||
import { AppShowPage } from './app-show.page'
|
import { AppShowPage } from './app-show.page'
|
||||||
import { EmverPipesModule } from '@start9labs/shared'
|
import { EmverPipesModule, ResponsiveColModule } from '@start9labs/shared'
|
||||||
import { StatusComponentModule } from 'src/app/components/status/status.component.module'
|
import { StatusComponentModule } from 'src/app/components/status/status.component.module'
|
||||||
import { AppConfigPageModule } from 'src/app/modals/app-config/app-config.module'
|
import { AppConfigPageModule } from 'src/app/modals/app-config/app-config.module'
|
||||||
import { LaunchablePipeModule } from 'src/app/pipes/launchable/launchable.module'
|
import { LaunchablePipeModule } from 'src/app/pipes/launchable/launchable.module'
|
||||||
@@ -55,6 +55,7 @@ const routes: Routes = [
|
|||||||
EmverPipesModule,
|
EmverPipesModule,
|
||||||
LaunchablePipeModule,
|
LaunchablePipeModule,
|
||||||
UiPipeModule,
|
UiPipeModule,
|
||||||
|
ResponsiveColModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AppShowPageModule {}
|
export class AppShowPageModule {}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<app-show-header [pkg]="pkg"></app-show-header>
|
<app-show-header [pkg]="pkg"></app-show-header>
|
||||||
|
|
||||||
<!-- content -->
|
<!-- content -->
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding with-widgets">
|
||||||
<!-- ** installing, updating, restoring ** -->
|
<!-- ** installing, updating, restoring ** -->
|
||||||
<ng-container *ngIf="showProgress(pkg); else installed">
|
<ng-container *ngIf="showProgress(pkg); else installed">
|
||||||
<app-show-progress
|
<app-show-progress
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<ion-item-divider>Additional Info</ion-item-divider>
|
<ion-item-divider>Additional Info</ion-item-divider>
|
||||||
<ion-grid *ngIf="pkg.manifest as manifest">
|
<ion-grid *ngIf="pkg.manifest as manifest">
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col sizeXs="12" sizeMd="6">
|
<ion-col responsiveCol sizeXs="12" sizeMd="6">
|
||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-item-group>
|
</ion-item-group>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
<ion-col sizeXs="12" sizeMd="6">
|
<ion-col responsiveCol sizeXs="12" sizeMd="6">
|
||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<ion-item
|
<ion-item
|
||||||
[href]="manifest['upstream-repo']"
|
[href]="manifest['upstream-repo']"
|
||||||
|
|||||||
@@ -16,14 +16,15 @@ import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
|||||||
import * as yaml from 'js-yaml'
|
import * as yaml from 'js-yaml'
|
||||||
import { v4 } from 'uuid'
|
import { v4 } from 'uuid'
|
||||||
import { DataModel, DevData } from 'src/app/services/patch-db/data-model'
|
import { DataModel, DevData } from 'src/app/services/patch-db/data-model'
|
||||||
import { DestroyService, ErrorToastService } from '@start9labs/shared'
|
import { ErrorToastService } from '@start9labs/shared'
|
||||||
|
import { TuiDestroyService } from '@taiga-ui/cdk'
|
||||||
import { takeUntil } from 'rxjs/operators'
|
import { takeUntil } from 'rxjs/operators'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'developer-list',
|
selector: 'developer-list',
|
||||||
templateUrl: 'developer-list.page.html',
|
templateUrl: 'developer-list.page.html',
|
||||||
styleUrls: ['developer-list.page.scss'],
|
styleUrls: ['developer-list.page.scss'],
|
||||||
providers: [DestroyService],
|
providers: [TuiDestroyService],
|
||||||
})
|
})
|
||||||
export class DeveloperListPage {
|
export class DeveloperListPage {
|
||||||
devData: DevData = {}
|
devData: DevData = {}
|
||||||
@@ -34,7 +35,7 @@ export class DeveloperListPage {
|
|||||||
private readonly loadingCtrl: LoadingController,
|
private readonly loadingCtrl: LoadingController,
|
||||||
private readonly errToast: ErrorToastService,
|
private readonly errToast: ErrorToastService,
|
||||||
private readonly alertCtrl: AlertController,
|
private readonly alertCtrl: AlertController,
|
||||||
private readonly destroy$: DestroyService,
|
private readonly destroy$: TuiDestroyService,
|
||||||
private readonly patch: PatchDB<DataModel>,
|
private readonly patch: PatchDB<DataModel>,
|
||||||
private readonly actionCtrl: ActionSheetController,
|
private readonly actionCtrl: ActionSheetController,
|
||||||
) {}
|
) {}
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ import { CommonModule } from '@angular/common'
|
|||||||
import { FormsModule } from '@angular/forms'
|
import { FormsModule } from '@angular/forms'
|
||||||
import { Routes, RouterModule } from '@angular/router'
|
import { Routes, RouterModule } from '@angular/router'
|
||||||
import { IonicModule } from '@ionic/angular'
|
import { IonicModule } from '@ionic/angular'
|
||||||
import { SharedPipesModule, EmverPipesModule } from '@start9labs/shared'
|
import {
|
||||||
|
SharedPipesModule,
|
||||||
|
EmverPipesModule,
|
||||||
|
ResponsiveColModule,
|
||||||
|
} from '@start9labs/shared'
|
||||||
import {
|
import {
|
||||||
FilterPackagesPipeModule,
|
FilterPackagesPipeModule,
|
||||||
CategoriesModule,
|
CategoriesModule,
|
||||||
@@ -41,6 +45,7 @@ const routes: Routes = [
|
|||||||
SkeletonModule,
|
SkeletonModule,
|
||||||
MarketplaceSettingsPageModule,
|
MarketplaceSettingsPageModule,
|
||||||
StoreIconComponentModule,
|
StoreIconComponentModule,
|
||||||
|
ResponsiveColModule,
|
||||||
],
|
],
|
||||||
declarations: [MarketplaceListPage],
|
declarations: [MarketplaceListPage],
|
||||||
exports: [MarketplaceListPage],
|
exports: [MarketplaceListPage],
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding with-widgets">
|
||||||
<ng-container *ngIf="details$ | async as details">
|
<ng-container *ngIf="details$ | async as details">
|
||||||
<ion-item [color]="details.color">
|
<ion-item [color]="details.color">
|
||||||
<ion-icon slot="start" name="information-circle-outline"></ion-icon>
|
<ion-icon slot="start" name="information-circle-outline"></ion-icon>
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<ion-grid>
|
<ion-grid>
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col size="12">
|
<ion-col>
|
||||||
<div class="heading">
|
<div class="heading">
|
||||||
<store-icon
|
<store-icon
|
||||||
class="icon"
|
class="icon"
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
</ion-col>
|
</ion-col>
|
||||||
</ion-row>
|
</ion-row>
|
||||||
<ion-row class="ion-align-items-center">
|
<ion-row class="ion-align-items-center">
|
||||||
<ion-col size="12">
|
<ion-col>
|
||||||
<ng-container *ngIf="store$ | async as store; else loading">
|
<ng-container *ngIf="store$ | async as store; else loading">
|
||||||
<marketplace-categories
|
<marketplace-categories
|
||||||
[categories]="store.categories"
|
[categories]="store.categories"
|
||||||
@@ -55,6 +55,7 @@
|
|||||||
<ion-row *ngIf="localPkgs$ | async as localPkgs">
|
<ion-row *ngIf="localPkgs$ | async as localPkgs">
|
||||||
<ion-col
|
<ion-col
|
||||||
*ngFor="let pkg of filtered"
|
*ngFor="let pkg of filtered"
|
||||||
|
responsiveCol
|
||||||
sizeXs="12"
|
sizeXs="12"
|
||||||
sizeSm="12"
|
sizeSm="12"
|
||||||
sizeMd="6"
|
sizeMd="6"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<marketplace-show-header></marketplace-show-header>
|
<marketplace-show-header></marketplace-show-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding with-widgets">
|
||||||
<ng-container *ngIf="pkg$ | async as pkg else loading">
|
<ng-container *ngIf="pkg$ | async as pkg else loading">
|
||||||
<ng-container *ngIf="pkg | empty; else show">
|
<ng-container *ngIf="pkg | empty; else show">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content>
|
<ion-content class="with-widgets">
|
||||||
<!-- loading -->
|
<!-- loading -->
|
||||||
<ion-item-group *ngIf="loading; else loaded">
|
<ion-item-group *ngIf="loading; else loaded">
|
||||||
<ion-item-divider>
|
<ion-item-divider>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding-top">
|
<ion-content class="ion-padding-top with-widgets">
|
||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<!-- about -->
|
<!-- about -->
|
||||||
<ion-item class="ion-padding-bottom">
|
<ion-item class="ion-padding-bottom">
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding with-widgets">
|
||||||
<ion-grid *ngIf="pkgs$ | async as pkgs">
|
<ion-grid *ngIf="pkgs$ | async as pkgs">
|
||||||
<ion-row *ngIf="backupProgress$ | async as backupProgress">
|
<ion-row *ngIf="backupProgress$ | async as backupProgress">
|
||||||
<ion-col>
|
<ion-col>
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ import { PatchDB } from 'patch-db-client'
|
|||||||
import { skip, takeUntil } from 'rxjs/operators'
|
import { skip, takeUntil } from 'rxjs/operators'
|
||||||
import { MappedBackupTarget } from 'src/app/types/mapped-backup-target'
|
import { MappedBackupTarget } from 'src/app/types/mapped-backup-target'
|
||||||
import * as argon2 from '@start9labs/argon2'
|
import * as argon2 from '@start9labs/argon2'
|
||||||
|
import { TuiDestroyService } from '@taiga-ui/cdk'
|
||||||
import {
|
import {
|
||||||
CifsBackupTarget,
|
CifsBackupTarget,
|
||||||
DiskBackupTarget,
|
DiskBackupTarget,
|
||||||
} from 'src/app/services/api/api.types'
|
} from 'src/app/services/api/api.types'
|
||||||
import { BackupSelectPage } from 'src/app/modals/backup-select/backup-select.page'
|
import { BackupSelectPage } from 'src/app/modals/backup-select/backup-select.page'
|
||||||
import { EOSService } from 'src/app/services/eos.service'
|
import { EOSService } from 'src/app/services/eos.service'
|
||||||
import { DestroyService } from '@start9labs/shared'
|
|
||||||
import { getServerInfo } from 'src/app/util/get-server-info'
|
import { getServerInfo } from 'src/app/util/get-server-info'
|
||||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ import { DataModel } from 'src/app/services/patch-db/data-model'
|
|||||||
selector: 'server-backup',
|
selector: 'server-backup',
|
||||||
templateUrl: './server-backup.page.html',
|
templateUrl: './server-backup.page.html',
|
||||||
styleUrls: ['./server-backup.page.scss'],
|
styleUrls: ['./server-backup.page.scss'],
|
||||||
providers: [DestroyService],
|
providers: [TuiDestroyService],
|
||||||
})
|
})
|
||||||
export class ServerBackupPage {
|
export class ServerBackupPage {
|
||||||
serviceIds: string[] = []
|
serviceIds: string[] = []
|
||||||
@@ -39,7 +39,7 @@ export class ServerBackupPage {
|
|||||||
private readonly modalCtrl: ModalController,
|
private readonly modalCtrl: ModalController,
|
||||||
private readonly embassyApi: ApiService,
|
private readonly embassyApi: ApiService,
|
||||||
private readonly navCtrl: NavController,
|
private readonly navCtrl: NavController,
|
||||||
private readonly destroy$: DestroyService,
|
private readonly destroy$: TuiDestroyService,
|
||||||
private readonly eosService: EOSService,
|
private readonly eosService: EOSService,
|
||||||
private readonly patch: PatchDB<DataModel>,
|
private readonly patch: PatchDB<DataModel>,
|
||||||
) {}
|
) {}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding with-widgets">
|
||||||
<skeleton-list *ngIf="loading" [groups]="2"></skeleton-list>
|
<skeleton-list *ngIf="loading" [groups]="2"></skeleton-list>
|
||||||
|
|
||||||
<div id="metricSection">
|
<div id="metricSection">
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding with-widgets">
|
||||||
<!-- loading -->
|
<!-- loading -->
|
||||||
<ng-template #loading>
|
<ng-template #loading>
|
||||||
<text-spinner text="Connecting to Embassy"></text-spinner>
|
<text-spinner text="Connecting to Embassy"></text-spinner>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content>
|
<ion-content class="with-widgets">
|
||||||
<ion-item-group *ngIf="server$ | async as server">
|
<ion-item-group *ngIf="server$ | async as server">
|
||||||
<ion-item-divider>embassyOS Info</ion-item-divider>
|
<ion-item-divider>embassyOS Info</ion-item-divider>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding-top">
|
<ion-content class="ion-padding-top with-widgets">
|
||||||
<!-- loading -->
|
<!-- loading -->
|
||||||
<ion-item-group *ngIf="loading; else notLoading">
|
<ion-item-group *ngIf="loading; else notLoading">
|
||||||
<div *ngFor="let entry of ['This Session', 'Other Sessions']">
|
<div *ngFor="let entry of ['This Session', 'Other Sessions']">
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-text-center">
|
<ion-content class="ion-text-center with-widgets">
|
||||||
<!-- file upload -->
|
<!-- file upload -->
|
||||||
<div
|
<div
|
||||||
*ngIf="!toUpload.file; else fileUploaded"
|
*ngIf="!toUpload.file; else fileUploaded"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding-top">
|
<ion-content class="ion-padding-top with-widgets">
|
||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<!-- always -->
|
<!-- always -->
|
||||||
<ion-item>
|
<ion-item>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding-top">
|
<ion-content class="ion-padding-top with-widgets">
|
||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<!-- always -->
|
<!-- always -->
|
||||||
<ion-item>
|
<ion-item>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding with-widgets">
|
||||||
<ion-item-group *ngIf="data$ | async as data">
|
<ion-item-group *ngIf="data$ | async as data">
|
||||||
<ng-container *ngFor="let host of data.hosts">
|
<ng-container *ngFor="let host of data.hosts">
|
||||||
<ion-item-divider class="header">
|
<ion-item-divider class="header">
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<div *ngIf="installed$ | async as installed" class="wrapper">
|
||||||
|
<button
|
||||||
|
*ngFor="let widget of widgets | tuiFilter: filter:installed; empty: empty"
|
||||||
|
class="tui-island tui-island_size_l"
|
||||||
|
(click)="context.completeWith(widget)"
|
||||||
|
>
|
||||||
|
<span class="tui-island__title">{{ widget.meta.name }}</span>
|
||||||
|
</button>
|
||||||
|
<ng-template #empty>No additional widgets found</ng-template>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-island {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
|
||||||
|
import { PatchDB } from 'patch-db-client'
|
||||||
|
import { Widget } from '../../../../services/patch-db/data-model'
|
||||||
|
import {
|
||||||
|
POLYMORPHEUS_CONTEXT,
|
||||||
|
PolymorpheusComponent,
|
||||||
|
} from '@tinkoff/ng-polymorpheus'
|
||||||
|
import { TuiDialogContext } from '@taiga-ui/core'
|
||||||
|
import { BUILT_IN_WIDGETS } from '../widgets'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'add-widget',
|
||||||
|
templateUrl: './add.component.html',
|
||||||
|
styleUrls: ['./add.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class AddWidgetComponent {
|
||||||
|
readonly context = inject<TuiDialogContext<Widget>>(POLYMORPHEUS_CONTEXT)
|
||||||
|
|
||||||
|
readonly installed$ = inject(PatchDB).watch$('ui', 'widgets')
|
||||||
|
|
||||||
|
readonly widgets = BUILT_IN_WIDGETS
|
||||||
|
|
||||||
|
readonly filter = (widget: Widget, installed: readonly Widget[]) =>
|
||||||
|
!installed.find(({ id }) => id === widget.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ADD_WIDGET = new PolymorpheusComponent<
|
||||||
|
AddWidgetComponent,
|
||||||
|
TuiDialogContext<Widget>
|
||||||
|
>(AddWidgetComponent)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { NgModule } from '@angular/core'
|
||||||
|
import { CommonModule } from '@angular/common'
|
||||||
|
import { TuiFilterPipeModule, TuiForModule } from '@taiga-ui/cdk'
|
||||||
|
|
||||||
|
import { AddWidgetComponent } from './add.component'
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [CommonModule, TuiFilterPipeModule, TuiForModule],
|
||||||
|
declarations: [AddWidgetComponent],
|
||||||
|
exports: [AddWidgetComponent],
|
||||||
|
})
|
||||||
|
export class AddWidgetModule {}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<ion-button class="add">Add to quick launch</ion-button>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.add {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component } from '@angular/core'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'widget-favorites',
|
||||||
|
templateUrl: './favorites.component.html',
|
||||||
|
styleUrls: ['./favorites.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class FavoritesComponent {}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { NgModule } from '@angular/core'
|
||||||
|
import { FavoritesComponent } from './favorites.component'
|
||||||
|
import { IonicModule } from '@ionic/angular'
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [IonicModule],
|
||||||
|
declarations: [FavoritesComponent],
|
||||||
|
exports: [FavoritesComponent],
|
||||||
|
})
|
||||||
|
export class FavoritesModule {}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<h2 class="widget-title">Service health overview</h2>
|
||||||
|
<tui-ring-chart
|
||||||
|
*ngIf="data$ | async as data"
|
||||||
|
class="ring-chart"
|
||||||
|
[tuiHintContent]="hint"
|
||||||
|
[value]="data"
|
||||||
|
>
|
||||||
|
<ng-template #hint let-index>
|
||||||
|
{{ labels[index] }}: {{ data[index] }}
|
||||||
|
</ng-template>
|
||||||
|
</tui-ring-chart>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
:host {
|
||||||
|
/* index order must match labels array */
|
||||||
|
--tui-chart-0: var(--ion-color-danger-tint); // error
|
||||||
|
--tui-chart-1: var(--ion-color-success-tint); // healthy
|
||||||
|
--tui-chart-2: var(--ion-color-warning-tint); // needs attention
|
||||||
|
--tui-chart-3: var(--ion-color-step-600); // stopped
|
||||||
|
--tui-chart-4: var(--ion-color-primary-tint); // transitioning
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ring-chart {
|
||||||
|
transform: scale(0.85);
|
||||||
|
margin: 0.6rem auto;
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
|
||||||
|
import { PatchDB } from 'patch-db-client'
|
||||||
|
import { map } from 'rxjs/operators'
|
||||||
|
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||||
|
import { PrimaryStatus } from 'src/app/services/pkg-status-rendering.service'
|
||||||
|
import { getPackageInfo, PkgInfo } from '../../../../util/get-package-info'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'widget-health',
|
||||||
|
templateUrl: './health.component.html',
|
||||||
|
styleUrls: ['./health.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class HealthComponent {
|
||||||
|
readonly labels = [
|
||||||
|
'Error',
|
||||||
|
'Healthy',
|
||||||
|
'Needs Attention',
|
||||||
|
'Stopped',
|
||||||
|
'Transitioning',
|
||||||
|
] as const
|
||||||
|
|
||||||
|
readonly data$ = inject(PatchDB)
|
||||||
|
.watch$('package-data')
|
||||||
|
.pipe(
|
||||||
|
map(data => {
|
||||||
|
const pkgs = Object.values<PackageDataEntry>(data).map(getPackageInfo)
|
||||||
|
const result = this.labels.reduce<Record<string, number>>(
|
||||||
|
(acc, label) => ({
|
||||||
|
...acc,
|
||||||
|
[label]: this.getCount(label, pkgs),
|
||||||
|
}),
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
|
||||||
|
result['Healthy'] =
|
||||||
|
pkgs.length -
|
||||||
|
result['Error'] -
|
||||||
|
result['Needs Attention'] -
|
||||||
|
result['Stopped'] -
|
||||||
|
result['Transitioning']
|
||||||
|
|
||||||
|
return this.labels.map(label => result[label])
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
private getCount(label: string, pkgs: PkgInfo[]): number {
|
||||||
|
switch (label) {
|
||||||
|
case 'Error':
|
||||||
|
return pkgs.filter(
|
||||||
|
a => a.primaryStatus !== PrimaryStatus.Stopped && a.error,
|
||||||
|
).length
|
||||||
|
case 'Needs Attention':
|
||||||
|
return pkgs.filter(a => a.warning).length
|
||||||
|
case 'Stopped':
|
||||||
|
return pkgs.filter(a => a.primaryStatus === PrimaryStatus.Stopped)
|
||||||
|
.length
|
||||||
|
case 'Transitioning':
|
||||||
|
return pkgs.filter(a => a.transitioning).length
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { NgModule } from '@angular/core'
|
||||||
|
import { HealthComponent } from './health.component'
|
||||||
|
import { TuiRingChartModule } from '@taiga-ui/addon-charts'
|
||||||
|
import { TuiHintModule } from '@taiga-ui/core'
|
||||||
|
import { CommonModule } from '@angular/common'
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [CommonModule, TuiRingChartModule, TuiHintModule],
|
||||||
|
declarations: [HealthComponent],
|
||||||
|
exports: [HealthComponent],
|
||||||
|
})
|
||||||
|
export class HealthModule {}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<div class="stats">
|
||||||
|
<div class="stat">
|
||||||
|
<ion-icon class="stat-icon" name="server-outline"></ion-icon>
|
||||||
|
<div>
|
||||||
|
30%
|
||||||
|
<div class="description">Storage</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat">
|
||||||
|
<ion-icon class="stat-icon" name="hardware-chip-outline"></ion-icon>
|
||||||
|
<div>
|
||||||
|
10%
|
||||||
|
<div class="description">CPU</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat">
|
||||||
|
<ion-icon class="stat-icon" name="stats-chart-outline"></ion-icon>
|
||||||
|
<div>
|
||||||
|
10%
|
||||||
|
<div class="description">Memory</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat">
|
||||||
|
<ion-icon class="stat-icon" name="thermometer-outline"></ion-icon>
|
||||||
|
<div>
|
||||||
|
50.6⁰C
|
||||||
|
<div class="description">Temp</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
.stats {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
height: 100%;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&_mobile .stat {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
:host-context(.wrapper_mobile) & {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon {
|
||||||
|
font-size: 32px;
|
||||||
|
margin: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
color: #3a7be0;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component } from '@angular/core'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'widget-metrics',
|
||||||
|
templateUrl: './metrics.component.html',
|
||||||
|
styleUrls: ['./metrics.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class MetricsComponent {}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { NgModule } from '@angular/core'
|
||||||
|
import { IonicModule } from '@ionic/angular'
|
||||||
|
import { MetricsComponent } from './metrics.component'
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [IonicModule],
|
||||||
|
declarations: [MetricsComponent],
|
||||||
|
exports: [MetricsComponent],
|
||||||
|
})
|
||||||
|
export class MetricsModule {}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<iframe
|
||||||
|
class="iframe"
|
||||||
|
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
|
||||||
|
title="YouTube video player"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||||
|
allowfullscreen
|
||||||
|
></iframe>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
:host {
|
||||||
|
border-radius: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iframe {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component } from '@angular/core'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'widget-network',
|
||||||
|
templateUrl: './network.component.html',
|
||||||
|
styleUrls: ['./network.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class NetworkComponent {}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { NgModule } from '@angular/core'
|
||||||
|
import { NetworkComponent } from './network.component'
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [],
|
||||||
|
declarations: [NetworkComponent],
|
||||||
|
exports: [NetworkComponent],
|
||||||
|
})
|
||||||
|
export class NetworkModule {}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
System time and uptime
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user