├── src ├── scss │ ├── main.scss │ ├── mobile.scss │ ├── breakpoints.scss │ ├── date-picker.scss │ ├── themes │ │ └── deepblue.scss │ └── gridster.scss ├── assets │ ├── .gitkeep │ ├── img │ │ ├── bg.jpg │ │ ├── logo.png │ │ ├── map-marker-red.png │ │ ├── icons │ │ │ ├── done-black-18dp.svg │ │ │ ├── check-black-18dp.svg │ │ │ ├── checkbox.svg │ │ │ ├── chevron_left-black-18dp.svg │ │ │ ├── menu.svg │ │ │ ├── check.svg │ │ │ ├── close-black-18dp.svg │ │ │ ├── view-2colums.svg │ │ │ ├── burger-menu-gray.svg │ │ │ ├── undo-black-18dp.svg │ │ │ ├── icon-filter.svg │ │ │ ├── view-3colums.svg │ │ │ ├── top-records.svg │ │ │ ├── search-black-18dp.svg │ │ │ ├── filter_alt-black-18dp.svg │ │ │ ├── palette-icon.svg │ │ │ ├── view-2columns.svg │ │ │ ├── text.svg │ │ │ ├── view-5columns.svg │ │ │ ├── reset.svg │ │ │ ├── icon-reload.svg │ │ │ ├── icon-copy.svg │ │ │ ├── settings-black-24dp.svg │ │ │ ├── icon-check.svg │ │ │ ├── legend-toggle.svg │ │ │ ├── language-24px.svg │ │ │ ├── icon-close.svg │ │ │ ├── close.svg │ │ │ ├── table.svg │ │ │ ├── icon-next.svg │ │ │ ├── icon-next-blue.svg │ │ │ ├── next.svg │ │ │ ├── pen.svg │ │ │ ├── icon-edit.svg │ │ │ ├── view-list.svg │ │ │ ├── view-3columns.svg │ │ │ ├── icon-logout.svg │ │ │ ├── icon-search.svg │ │ │ ├── view-6columns.svg │ │ │ └── icon-settings.svg │ │ ├── widget-icons │ │ │ ├── dashboard-1.svg │ │ │ ├── widget-4.svg │ │ │ ├── folder-1.svg │ │ │ ├── widget-3.svg │ │ │ ├── back-1.svg │ │ │ ├── widget-1.svg │ │ │ └── widget-2.svg │ │ ├── traffic-light │ │ │ ├── green.svg │ │ │ ├── red.svg │ │ │ └── yellow.svg │ │ ├── spinner.svg │ │ ├── smiley │ │ │ ├── smile-red.svg │ │ │ ├── smile-green.svg │ │ │ └── smile-yellow.svg │ │ └── map-pin-icon.svg │ └── fonts │ │ ├── Oxygen-Bold.ttf │ │ ├── Oxygen-Light.ttf │ │ ├── Oxygen-Regular.ttf │ │ ├── RobotoCondensed-Bold.woff2 │ │ ├── RobotoCondensed-Italic.woff2 │ │ ├── RobotoCondensed-Light.woff2 │ │ ├── RobotoCondensed-Regular.woff2 │ │ ├── RobotoCondensed-BoldItalic.woff2 │ │ └── RobotoCondensed-LightItalic.woff2 ├── app │ ├── components │ │ ├── widgets │ │ │ ├── wpivot │ │ │ │ ├── pivot.component.html │ │ │ │ └── pivot.component.scss │ │ │ ├── smiley │ │ │ │ ├── smiley.component.html │ │ │ │ ├── smiley.component.ts │ │ │ │ └── smiley.component.scss │ │ │ ├── traffic-light │ │ │ │ ├── traffic-light.component.html │ │ │ │ ├── traffic-light.component.ts │ │ │ │ └── traffic-light.component.scss │ │ │ ├── map-widget │ │ │ │ └── map-widget.component.html │ │ │ ├── map-widget-old │ │ │ │ ├── map-widget.component.html │ │ │ │ └── map-widget.component.scss │ │ │ ├── light-bar │ │ │ │ ├── light-bar.component.html │ │ │ │ ├── light-bar.component.ts │ │ │ │ └── light-bar.component.scss │ │ │ ├── text │ │ │ │ ├── wtext.component.html │ │ │ │ └── wtext.component.scss │ │ │ ├── charts │ │ │ │ ├── bar-chart.component.ts │ │ │ │ ├── column-chart.component.ts │ │ │ │ ├── area-chart.component.ts │ │ │ │ └── line-chart.component.ts │ │ │ └── base │ │ │ │ ├── widget │ │ │ │ ├── widget.component.scss │ │ │ │ └── widget.component.html │ │ │ │ └── widget-filter │ │ │ │ └── widget-filter.component.html │ │ ├── ui │ │ │ ├── date-picker │ │ │ │ ├── date-picker.component.html │ │ │ │ └── date-picker.component.scss │ │ │ ├── error │ │ │ │ ├── error.component.html │ │ │ │ └── error.component.scss │ │ │ ├── text-area │ │ │ │ ├── text-area.component.html │ │ │ │ ├── text-area.component.scss │ │ │ │ └── text-area.component.ts │ │ │ ├── sidebar │ │ │ │ ├── sidebar.component.html │ │ │ │ └── sidebar.component.scss │ │ │ ├── input │ │ │ │ └── input │ │ │ │ │ ├── input.component.html │ │ │ │ │ ├── input.component.scss │ │ │ │ │ └── input.component.ts │ │ │ ├── language-selector │ │ │ │ ├── language-selector.component.html │ │ │ │ └── language-selector.component.ts │ │ │ ├── search │ │ │ │ └── search-input │ │ │ │ │ ├── search-input.component.html │ │ │ │ │ └── search-input.component.scss │ │ │ ├── about │ │ │ │ ├── about.component.html │ │ │ │ ├── about.component.scss │ │ │ │ └── about.component.ts │ │ │ ├── color-picker │ │ │ │ ├── color-picker.component.html │ │ │ │ └── color-picker.component.scss │ │ │ ├── namespace-selector │ │ │ │ ├── namespace-selector.component.html │ │ │ │ └── namespace-selector.component.ts │ │ │ ├── app-settings │ │ │ │ ├── app-settings.component.scss │ │ │ │ └── app-settings.component.html │ │ │ ├── date-filter │ │ │ │ ├── date-filter.component.html │ │ │ │ └── date-filter.component.scss │ │ │ ├── menu │ │ │ │ ├── menu-settings │ │ │ │ │ ├── menu-settings.component.html │ │ │ │ │ └── menu-settings.component.ts │ │ │ │ └── menu.component.html │ │ │ ├── theme-settings │ │ │ │ ├── theme-settings.component.scss │ │ │ │ └── theme-settings.component.html │ │ │ ├── chart-colors-config │ │ │ │ └── chart-colors-config.component.scss │ │ │ ├── home-editor │ │ │ │ └── home-editor.component.scss │ │ │ ├── share-dashboard │ │ │ │ └── share-dashboard │ │ │ │ │ ├── share-dashboard.component.html │ │ │ │ │ └── share-dashboard.component.scss │ │ │ ├── sidebar-actions │ │ │ │ ├── sidebar-actions.component.html │ │ │ │ └── sidebar-actions.component.ts │ │ │ ├── tabs │ │ │ │ └── tabs.component.html │ │ │ └── modal │ │ │ │ └── modal.component.html │ │ ├── editor │ │ │ ├── widget-editor │ │ │ │ └── widget-editor.component.scss │ │ │ ├── type-and-datasource │ │ │ │ ├── type-and-datasource.component.scss │ │ │ │ └── type-and-datasource.component.html │ │ │ └── datasource-selector-dialog │ │ │ │ ├── datasource-selector-dialog.html │ │ │ │ └── datasource-selector-dialog.scss │ │ └── screens │ │ │ ├── main-screen │ │ │ ├── main-screen.component.scss │ │ │ ├── main-screen.component.html │ │ │ └── main-screen.component.ts │ │ │ └── folder-screen │ │ │ └── folder-screen.component.html │ ├── services │ │ ├── menu.service.ts │ │ ├── widget.service.ts │ │ ├── broadcast.service.ts │ │ ├── variables.service.ts │ │ ├── header.service.ts │ │ ├── lpt.types.ts │ │ └── error.service.ts │ ├── app.component.scss │ ├── directives │ │ ├── focus-next.directive.ts │ │ └── auto-focus.directive.ts │ ├── app.component.html │ └── app.routes.ts ├── environments │ ├── environment.prod.ts │ ├── environment.ts │ └── dsw.ts ├── main.ts ├── addons │ ├── tsconfig.json │ └── htmlViewer.ts ├── test.ts └── manifest.webmanifest ├── screenshot.png ├── dist ├── assets │ ├── img │ │ ├── bg.jpg │ │ ├── logo.png │ │ ├── map-marker-red.png │ │ ├── icons │ │ │ ├── done-black-18dp.svg │ │ │ ├── check-black-18dp.svg │ │ │ ├── checkbox.svg │ │ │ ├── chevron_left-black-18dp.svg │ │ │ ├── menu.svg │ │ │ ├── check.svg │ │ │ ├── close-black-18dp.svg │ │ │ ├── view-2colums.svg │ │ │ ├── burger-menu-gray.svg │ │ │ ├── undo-black-18dp.svg │ │ │ ├── icon-filter.svg │ │ │ ├── view-3colums.svg │ │ │ ├── top-records.svg │ │ │ ├── search-black-18dp.svg │ │ │ ├── filter_alt-black-18dp.svg │ │ │ ├── palette-icon.svg │ │ │ ├── view-2columns.svg │ │ │ ├── text.svg │ │ │ ├── view-5columns.svg │ │ │ ├── reset.svg │ │ │ ├── icon-reload.svg │ │ │ ├── icon-copy.svg │ │ │ ├── settings-black-24dp.svg │ │ │ ├── icon-check.svg │ │ │ ├── legend-toggle.svg │ │ │ ├── language-24px.svg │ │ │ ├── icon-close.svg │ │ │ ├── close.svg │ │ │ ├── table.svg │ │ │ ├── icon-next.svg │ │ │ ├── icon-next-blue.svg │ │ │ ├── next.svg │ │ │ ├── pen.svg │ │ │ ├── icon-edit.svg │ │ │ ├── view-list.svg │ │ │ ├── view-3columns.svg │ │ │ ├── icon-logout.svg │ │ │ ├── icon-search.svg │ │ │ ├── view-6columns.svg │ │ │ └── icon-settings.svg │ │ ├── widget-icons │ │ │ ├── dashboard-1.svg │ │ │ ├── widget-4.svg │ │ │ ├── folder-1.svg │ │ │ ├── widget-3.svg │ │ │ ├── back-1.svg │ │ │ ├── widget-1.svg │ │ │ └── widget-2.svg │ │ ├── traffic-light │ │ │ ├── green.svg │ │ │ ├── red.svg │ │ │ └── yellow.svg │ │ ├── spinner.svg │ │ ├── smiley │ │ │ ├── smile-red.svg │ │ │ ├── smile-green.svg │ │ │ └── smile-yellow.svg │ │ └── map-pin-icon.svg │ └── fonts │ │ ├── Oxygen-Bold.ttf │ │ ├── Oxygen-Light.ttf │ │ ├── Oxygen-Regular.ttf │ │ ├── RobotoCondensed-Bold.woff2 │ │ ├── RobotoCondensed-Italic.woff2 │ │ ├── RobotoCondensed-Light.woff2 │ │ ├── RobotoCondensed-Regular.woff2 │ │ ├── RobotoCondensed-BoldItalic.woff2 │ │ └── RobotoCondensed-LightItalic.woff2 ├── config.json ├── media │ ├── fontawesome-webfont-FMJ3VJ65.eot │ ├── fontawesome-webfont-RJ6LE7IU.ttf │ ├── fontawesome-webfont-5GKVPAEF.woff2 │ └── fontawesome-webfont-Z4ARLA73.woff ├── chunk-N4BXP7J5.js ├── chunk-CBDZIDUZ.js ├── chunk-RU73HBGW.js ├── chunk-QDTU75BJ.js ├── chunk-NHWJ6QQD.js ├── chunk-XEMLRN7T.js ├── chunk-QT4NCOPW.js ├── chunk-HFC6Q7LK.js ├── chunk-23TAPEHU.js ├── chunk-MDOQS4TE.js ├── chunk-G7BOERRR.js ├── chunk-YE4HGH46.js ├── chunk-MG3ERZGY.js ├── chunk-ZMZIHCGB.js ├── manifest.webmanifest └── chunk-NF3Y2YSA.js ├── public └── config.json ├── oauth.json ├── docker-compose.yml ├── .editorconfig ├── tsconfig.app.json ├── proxy.conf.samples-bi.js ├── proxy.conf.local.js ├── proxy.conf.js ├── module.xml ├── iris.script ├── .github ├── sync-zpm-version.js └── workflows │ ├── test-ui.yml │ └── angular-build.yml ├── .gitignore ├── Installer.cls ├── karma.conf.js ├── LICENSE ├── Dockerfile ├── tsconfig.json └── ngsw-config.json /src/scss/main.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/components/widgets/wpivot/pivot.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/components/ui/date-picker/date-picker.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/components/editor/widget-editor/widget-editor.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/components/editor/type-and-datasource/type-and-datasource.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/components/ui/error/error.component.html: -------------------------------------------------------------------------------- 1 | {{error.message}} 2 | -------------------------------------------------------------------------------- /src/scss/mobile.scss: -------------------------------------------------------------------------------- 1 | [desktop-hidden] { 2 | display: initial !important; 3 | } 4 | -------------------------------------------------------------------------------- /src/app/components/widgets/wpivot/pivot.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | height: 100%; 3 | } 4 | -------------------------------------------------------------------------------- /src/app/components/ui/date-picker/date-picker.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | 4 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/screenshot.png -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/app/components/ui/text-area/text-area.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/img/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/src/assets/img/bg.jpg -------------------------------------------------------------------------------- /dist/assets/img/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/assets/img/bg.jpg -------------------------------------------------------------------------------- /src/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/src/assets/img/logo.png -------------------------------------------------------------------------------- /dist/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/assets/img/logo.png -------------------------------------------------------------------------------- /dist/assets/fonts/Oxygen-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/assets/fonts/Oxygen-Bold.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Oxygen-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/src/assets/fonts/Oxygen-Bold.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Oxygen-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/src/assets/fonts/Oxygen-Light.ttf -------------------------------------------------------------------------------- /src/assets/img/map-marker-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/src/assets/img/map-marker-red.png -------------------------------------------------------------------------------- /dist/assets/fonts/Oxygen-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/assets/fonts/Oxygen-Light.ttf -------------------------------------------------------------------------------- /dist/assets/fonts/Oxygen-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/assets/fonts/Oxygen-Regular.ttf -------------------------------------------------------------------------------- /dist/assets/img/map-marker-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/assets/img/map-marker-red.png -------------------------------------------------------------------------------- /src/assets/fonts/Oxygen-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/src/assets/fonts/Oxygen-Regular.ttf -------------------------------------------------------------------------------- /src/app/components/screens/main-screen/main-screen.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | height: 100%; 5 | } 6 | -------------------------------------------------------------------------------- /src/app/components/ui/sidebar/sidebar.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dist/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "namespace": "MDX2JSON", 3 | "endpoints": { 4 | "mdx2json": "MDX2JSON" 5 | }, 6 | "defaultApp": "" 7 | } 8 | -------------------------------------------------------------------------------- /dist/media/fontawesome-webfont-FMJ3VJ65.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/media/fontawesome-webfont-FMJ3VJ65.eot -------------------------------------------------------------------------------- /dist/media/fontawesome-webfont-RJ6LE7IU.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/media/fontawesome-webfont-RJ6LE7IU.ttf -------------------------------------------------------------------------------- /public/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "namespace": "MDX2JSON", 3 | "endpoints": { 4 | "mdx2json": "MDX2JSON" 5 | }, 6 | "defaultApp": "" 7 | } 8 | -------------------------------------------------------------------------------- /src/assets/fonts/RobotoCondensed-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/src/assets/fonts/RobotoCondensed-Bold.woff2 -------------------------------------------------------------------------------- /dist/assets/fonts/RobotoCondensed-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/assets/fonts/RobotoCondensed-Bold.woff2 -------------------------------------------------------------------------------- /dist/assets/fonts/RobotoCondensed-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/assets/fonts/RobotoCondensed-Italic.woff2 -------------------------------------------------------------------------------- /dist/assets/fonts/RobotoCondensed-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/assets/fonts/RobotoCondensed-Light.woff2 -------------------------------------------------------------------------------- /dist/media/fontawesome-webfont-5GKVPAEF.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/media/fontawesome-webfont-5GKVPAEF.woff2 -------------------------------------------------------------------------------- /dist/media/fontawesome-webfont-Z4ARLA73.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/media/fontawesome-webfont-Z4ARLA73.woff -------------------------------------------------------------------------------- /src/assets/fonts/RobotoCondensed-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/src/assets/fonts/RobotoCondensed-Italic.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/RobotoCondensed-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/src/assets/fonts/RobotoCondensed-Light.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/RobotoCondensed-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/src/assets/fonts/RobotoCondensed-Regular.woff2 -------------------------------------------------------------------------------- /dist/assets/fonts/RobotoCondensed-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/assets/fonts/RobotoCondensed-Regular.woff2 -------------------------------------------------------------------------------- /dist/chunk-N4BXP7J5.js: -------------------------------------------------------------------------------- 1 | import{a as e}from"./chunk-YE4HGH46.js";import"./chunk-MG3ERZGY.js";var o=class extends e{decodeBlock(r){return r}};export{o as default}; 2 | -------------------------------------------------------------------------------- /dist/assets/fonts/RobotoCondensed-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/assets/fonts/RobotoCondensed-BoldItalic.woff2 -------------------------------------------------------------------------------- /dist/assets/fonts/RobotoCondensed-LightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/dist/assets/fonts/RobotoCondensed-LightItalic.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/RobotoCondensed-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/src/assets/fonts/RobotoCondensed-BoldItalic.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/RobotoCondensed-LightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intersystems-community/DeepSeeWeb/master/src/assets/fonts/RobotoCondensed-LightItalic.woff2 -------------------------------------------------------------------------------- /dist/chunk-CBDZIDUZ.js: -------------------------------------------------------------------------------- 1 | import{a}from"./chunk-XC5FPF3U.js";import"./chunk-XVF25FWQ.js";import"./chunk-YZADXMU6.js";import"./chunk-ZEAAPN4P.js";import"./chunk-MG3ERZGY.js";export{a as ShareDashboardComponent}; 2 | -------------------------------------------------------------------------------- /dist/chunk-RU73HBGW.js: -------------------------------------------------------------------------------- 1 | import{S as r,ba as o,c as n,oa as s,xa as i}from"./chunk-ZEAAPN4P.js";function c(t){t||(s(c),t=o(i));let u=new n(e=>t.onDestroy(e.next.bind(e)));return e=>e.pipe(r(u))}export{c as a}; 2 | -------------------------------------------------------------------------------- /src/app/components/screens/main-screen/main-screen.component.html: -------------------------------------------------------------------------------- 1 | @if (isFolder) { 2 | 3 | } 4 | @if (!isFolder) { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/app/components/ui/text-area/text-area.component.scss: -------------------------------------------------------------------------------- 1 | @import "breakpoints"; 2 | 3 | textarea { 4 | min-width: 500px; 5 | min-height: 150px; 6 | 7 | @include sm { 8 | min-width: auto; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /dist/chunk-QDTU75BJ.js: -------------------------------------------------------------------------------- 1 | import{a as e}from"./chunk-PZJJYAMS.js";import{a as r}from"./chunk-YE4HGH46.js";import"./chunk-MG3ERZGY.js";var o=class extends r{decodeBlock(t){return e(new Uint8Array(t)).buffer}};export{o as default}; 2 | -------------------------------------------------------------------------------- /dist/assets/img/icons/done-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/icons/done-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/assets/img/icons/check-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/icons/check-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/icons/checkbox.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/icons/checkbox.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/icons/chevron_left-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/icons/chevron_left-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/icons/menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/icons/menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/icons/check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /oauth.json: -------------------------------------------------------------------------------- 1 | { 2 | "auth": { 3 | "socialKeys": { 4 | "github": "c59b1f8a0a798a43513a", 5 | "intersystems": "9M-iTne2oe6ckE4_MZ92TaQCffzzDdf8SNmnD8HAV1U" 6 | }, 7 | "redirect": "localhost/redirect.html", 8 | "proxy": "localhost/oauthproxy" 9 | } 10 | } -------------------------------------------------------------------------------- /src/assets/img/icons/check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/assets/img/icons/close-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/assets/img/icons/view-2colums.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/img/icons/close-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/icons/view-2colums.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /dist/chunk-NHWJ6QQD.js: -------------------------------------------------------------------------------- 1 | import{X as o,za as e}from"./chunk-ZEAAPN4P.js";var s=(()=>{class t{constructor(){this.onEditDashboard=new e,this.onSetTitle=new e}static{this.\u0275fac=function(r){return new(r||t)}}static{this.\u0275prov=o({token:t,factory:t.\u0275fac,providedIn:"root"})}}return t})();export{s as a}; 2 | -------------------------------------------------------------------------------- /src/app/components/ui/input/input/input.component.html: -------------------------------------------------------------------------------- 1 | 8 | @if (chooseButton) { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/app/components/widgets/smiley/smiley.component.html: -------------------------------------------------------------------------------- 1 | @for (d of data; track d) { 2 |
3 | 5 | 6 |
7 | } 8 | 9 | -------------------------------------------------------------------------------- /dist/assets/img/icons/burger-menu-gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/app/components/widgets/traffic-light/traffic-light.component.html: -------------------------------------------------------------------------------- 1 | @for (d of data; track d) { 2 |
3 | 5 | 6 |
7 | } 8 | 9 | -------------------------------------------------------------------------------- /src/assets/img/icons/burger-menu-gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/app/components/ui/language-selector/language-selector.component.html: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /src/app/components/widgets/map-widget/map-widget.component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | -------------------------------------------------------------------------------- /dist/assets/img/icons/undo-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/icons/undo-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/components/ui/search/search-input/search-input.component.html: -------------------------------------------------------------------------------- 1 | 2 | 10 | -------------------------------------------------------------------------------- /dist/assets/img/icons/icon-filter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon-filter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /dist/assets/img/widget-icons/dashboard-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/img/widget-icons/dashboard-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | services: 3 | iris: 4 | build: 5 | context: . 6 | dockerfile: Dockerfile 7 | restart: always 8 | command: --check-caps false 9 | ports: 10 | - "1972:1972" 11 | - "52773:52773" 12 | - "53773:53773" 13 | volumes: 14 | - ./:/home/irisowner/irisdev 15 | -------------------------------------------------------------------------------- /src/app/components/widgets/map-widget-old/map-widget.component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /dist/assets/img/icons/view-3colums.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/app/components/ui/about/about.component.html: -------------------------------------------------------------------------------- 1 | DeepSeeWeb is an Angular UI layer for IRIS BI (DeepSee) dashboards. 2 |
3 | More info at: Github DeepSeeWeb repository 4 | 5 |

Changelog

6 | 7 |
8 | 9 |
10 | -------------------------------------------------------------------------------- /src/assets/img/icons/view-3colums.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/app/components/ui/about/about.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | :host { 4 | font-family: $font; 5 | max-width: 50vw; 6 | 7 | & h2 { 8 | font-size: 18px; 9 | margin-bottom: 20px; 10 | font-weight: normal; 11 | } 12 | } 13 | 14 | 15 | a { 16 | color: var(--cl-accent); 17 | text-decoration: none; 18 | cursor: pointer; 19 | } 20 | -------------------------------------------------------------------------------- /src/app/services/menu.service.ts: -------------------------------------------------------------------------------- 1 | import {EventEmitter, Injectable} from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root' 5 | }) 6 | export class MenuService { 7 | // Triggers dashboard editing mode on/off 8 | public onEditDashboard = new EventEmitter(); 9 | onSetTitle = new EventEmitter(); 10 | 11 | constructor() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /dist/chunk-XEMLRN7T.js: -------------------------------------------------------------------------------- 1 | import{a as l}from"./chunk-YE4HGH46.js";import"./chunk-MG3ERZGY.js";var i=class extends l{decodeBlock(s){let o=new DataView(s),r=[];for(let e=0;e 7 | @if (!isImmediate) { 8 | 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/app/components/ui/namespace-selector/namespace-selector.component.html: -------------------------------------------------------------------------------- 1 | @if (isLoading) { 2 | 3 | } 4 |
    5 | @for (ns of items; track ns) { 6 |
  • 7 | 8 | {{ ns }} 9 |
  • 10 | } 11 |
12 | -------------------------------------------------------------------------------- /src/app/components/ui/app-settings/app-settings.component.scss: -------------------------------------------------------------------------------- 1 | .actions { 2 | display: flex; 3 | justify-content: space-between; 4 | margin-top: 20px; 5 | margin-bottom: 10px; 6 | 7 | & > button { 8 | width: 100%; 9 | 10 | &:first-child { 11 | margin-right: 5px; 12 | } 13 | 14 | &:last-child { 15 | margin-left: 5px; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /dist/assets/img/icons/top-records.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/img/icons/top-records.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [ 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/main.ts" 12 | ], 13 | "include": [ 14 | "src/**/*.d.ts" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | @import "breakpoints"; 2 | 3 | :host { 4 | display: flex; 5 | flex-direction: column; 6 | height: 100%; 7 | } 8 | 9 | .content { 10 | display: flex; 11 | flex: 1 1 100%; 12 | height: 100%; 13 | min-height: 0; 14 | 15 | /* @include sm { 16 | position: absolute; 17 | top: var(--header-height); 18 | bottom: var(--header-height); 19 | }*/ 20 | } 21 | -------------------------------------------------------------------------------- /src/app/components/widgets/light-bar/light-bar.component.html: -------------------------------------------------------------------------------- 1 | @for (d of data; track d) { 2 |
3 |
4 | @for (idx of dots; track idx) { 5 |
6 | } 7 |
8 | 9 |
10 | } 11 | 12 | -------------------------------------------------------------------------------- /dist/assets/img/icons/search-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/assets/img/widget-icons/widget-4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/assets/img/icons/search-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/widget-icons/widget-4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /dist/assets/img/icons/filter_alt-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/icons/filter_alt-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/components/ui/date-filter/date-filter.component.html: -------------------------------------------------------------------------------- 1 |
    2 | @for (f of filters; track f; let idx = $index) { 3 |
  • {{ f.label }} 7 |
  • 8 | } 9 |
10 | 11 | 17 | 18 | -------------------------------------------------------------------------------- /proxy.conf.samples-bi.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "/configs": { 3 | "target": "https://samples-bi-demo.demo.community.intersystems.com/dsw/", 4 | "secure": false, 5 | "logLevel": "debug", 6 | "changeOrigin": true 7 | }, 8 | "/MDX2JSON": { 9 | "target": "https://samples-bi-demo.demo.community.intersystems.com/", 10 | "secure": false, 11 | "logLevel": "debug", 12 | "changeOrigin": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /dist/assets/img/traffic-light/green.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /dist/assets/img/traffic-light/red.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/img/traffic-light/green.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/img/traffic-light/red.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/img/traffic-light/yellow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /dist/assets/img/traffic-light/yellow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/app/components/ui/menu/menu-settings/menu-settings.component.html: -------------------------------------------------------------------------------- 1 |
    2 |
  • 3 | 4 | Application 5 |
  • 6 |
  • 7 | 8 | Theme 9 |
  • 10 |
  • 11 | 12 | Charts 13 |
  • 14 |
15 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import {bootstrapApplication} from '@angular/platform-browser'; 2 | import {appConfig} from './app/app.config'; 3 | import {AppComponent} from './app/app.component'; 4 | import {environment} from './environments/environment'; 5 | import {enableProdMode} from '@angular/core'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | bootstrapApplication(AppComponent, appConfig) 12 | .catch((err) => console.error(err)); 13 | -------------------------------------------------------------------------------- /src/app/components/ui/sidebar/sidebar.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | :host { 4 | display: block; 5 | height: 100%; 6 | width: var(--sidebar-width); 7 | max-width: var(--sidebar-width); 8 | background-color: var(--cl-sidebar-bg); 9 | color: var(--cl-sidebar-txt); 10 | flex: 0 0 var(--sidebar-width); 11 | border-right: 1px solid var(--cl-sidebar-border); 12 | z-index: 3; 13 | 14 | position: relative; 15 | overflow: hidden; 16 | } 17 | -------------------------------------------------------------------------------- /src/app/components/ui/theme-settings/theme-settings.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | table { 4 | font-size: 12px; 5 | 6 | & > thead { 7 | opacity: 0.7; 8 | } 9 | 10 | & td { 11 | width: 50%; 12 | } 13 | } 14 | 15 | .color { 16 | height: 14px; 17 | cursor: pointer; 18 | } 19 | 20 | .input { 21 | height: 14px; 22 | } 23 | 24 | .btn-success { 25 | margin-top: 10px; 26 | } 27 | 28 | dsw-color-picker { 29 | height: 20px; 30 | } 31 | -------------------------------------------------------------------------------- /dist/chunk-QT4NCOPW.js: -------------------------------------------------------------------------------- 1 | import{I as c}from"./chunk-YZADXMU6.js";import{Ea as o,bb as i,ha as r}from"./chunk-ZEAAPN4P.js";var a=(()=>{class t{constructor(s,e){this.el=s,this.us=e}ngAfterViewInit(){this.el.nativeElement.attributes.getNamedItem("dswAutoFocus").value==="desktop"&&this.us.isMobile()||this.el.nativeElement.focus()}static{this.\u0275fac=function(e){return new(e||t)(i(o),i(c))}}static{this.\u0275dir=r({type:t,selectors:[["","dswAutoFocus",""]],standalone:!0})}}return t})();export{a}; 2 | -------------------------------------------------------------------------------- /src/app/components/ui/chart-colors-config/chart-colors-config.component.scss: -------------------------------------------------------------------------------- 1 | 2 | .color-small { 3 | display: inline-block; 4 | width: 32px; 5 | height: 32px; 6 | min-width: 32px; 7 | flex-shrink: 0; 8 | } 9 | 10 | .series-colors { 11 | display: flex; 12 | flex-wrap: wrap; 13 | gap: 8px; 14 | } 15 | 16 | label + .color-small { 17 | margin-left: 0; 18 | } 19 | 20 | .color { 21 | display: inline-flex; 22 | } 23 | 24 | .divider { 25 | margin-bottom: 10px; 26 | } 27 | -------------------------------------------------------------------------------- /src/app/components/ui/color-picker/color-picker.component.scss: -------------------------------------------------------------------------------- 1 | $size: 32px; 2 | 3 | :host { 4 | display: block; 5 | width: 100%; 6 | height: $size; 7 | cursor: pointer; 8 | border: 1px solid rgb(210, 210,210); 9 | } 10 | 11 | chrome-picker { 12 | position: fixed; 13 | transform: translateY($size); 14 | cursor: default; 15 | z-index: 2; 16 | } 17 | 18 | .btn-primary { 19 | width: 100%; 20 | border-radius: 0; 21 | } 22 | 23 | .top { 24 | transform: translateY(-100%); 25 | } 26 | -------------------------------------------------------------------------------- /proxy.conf.local.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "/config.json": { 3 | "target": "http://127.0.0.1:52773/dsw/", 4 | "secure": false, 5 | "logLevel": "debug", 6 | "changeOrigin": true 7 | }, 8 | "/configs": { 9 | "target": "http://127.0.0.1:52773/dsw/", 10 | "secure": false, 11 | "logLevel": "debug", 12 | "changeOrigin": true 13 | }, 14 | "/MDX2JSON": { 15 | "target": "http://127.0.0.1:52773/", 16 | "secure": false, 17 | "logLevel": "debug", 18 | "changeOrigin": true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/app/components/ui/home-editor/home-editor.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | // Upload control 4 | input[type=file] { 5 | &::-webkit-file-upload-button { 6 | // color: red; 7 | } 8 | } 9 | 10 | // Checkbox, must be placed inside label 11 | input[type=checkbox] { 12 | cursor: pointer; 13 | outline: none; 14 | display: inline; 15 | &:focus, &:active { 16 | outline: none; 17 | } 18 | } 19 | 20 | .divider { 21 | display: block; 22 | width: 100%; 23 | clear: both; 24 | } 25 | -------------------------------------------------------------------------------- /src/app/components/widgets/text/wtext.component.html: -------------------------------------------------------------------------------- 1 | @for (item of textData; track item; let idx = $index) { 2 |
3 | 4 | {{ item.value }} 5 | {{ item.deltaNeg }} 6 | {{ item.delta }} 7 | 8 | 9 | 10 |
11 | } 12 | -------------------------------------------------------------------------------- /src/app/services/widget.service.ts: -------------------------------------------------------------------------------- 1 | import {EventEmitter, Injectable} from '@angular/core'; 2 | 3 | import {IWidgetDesc} from "./dsw.types"; 4 | 5 | export interface IButtonToggle { 6 | widget: IWidgetDesc; 7 | name: string; 8 | state: boolean; 9 | } 10 | 11 | @Injectable({ 12 | providedIn: 'root' 13 | }) 14 | export class WidgetService { 15 | 16 | onToggleHeaderButton = new EventEmitter(); 17 | 18 | constructor() { 19 | } 20 | 21 | toggleButton(btn: IButtonToggle) { 22 | this.onToggleHeaderButton.emit(btn); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/assets/img/widget-icons/folder-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/widget-icons/folder-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/icons/palette-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/icons/palette-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /proxy.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "/config.json": { 3 | "target": "https://startup-dev.community.intersystems.com/dsw/", 4 | "secure": false, 5 | "logLevel": "debug", 6 | "changeOrigin": true 7 | }, 8 | "/configs": { 9 | "target": "https://startup-dev.community.intersystems.com/dsw/", 10 | "secure": false, 11 | "logLevel": "debug", 12 | "changeOrigin": true 13 | }, 14 | "/MDX2JSON": { 15 | "target": "https://startup-dev.community.intersystems.com/", 16 | "secure": false, 17 | "logLevel": "debug", 18 | "changeOrigin": true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/app/directives/focus-next.directive.ts: -------------------------------------------------------------------------------- 1 | import {Directive, ElementRef, HostListener} from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[dswFocusNext]', 5 | standalone: true 6 | }) 7 | export class FocusNextDirective { 8 | 9 | constructor(private el: ElementRef) { 10 | } 11 | 12 | @HostListener('keydown.enter', ['$event']) 13 | onReturnPressed(e: KeyboardEvent) { 14 | e.preventDefault(); 15 | const focusEl = document.getElementById(this.el.nativeElement.attributes.dswFocusNext.value); 16 | if (focusEl) { 17 | focusEl.focus(); 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /dist/assets/img/icons/view-2columns.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/app/components/widgets/charts/bar-chart.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {BaseChartClass} from './base-chart.class'; 3 | 4 | @Component({ 5 | selector: 'dsw-bar-chart', 6 | template: '', 7 | standalone: true 8 | }) 9 | export class BarChartComponent extends BaseChartClass implements OnInit { 10 | 11 | ngOnInit(): void { 12 | super.ngOnInit(); 13 | this.widget.isBtnZero = true; 14 | this.widget.isBtnValues = true; 15 | 16 | if (this.widget.type.toLowerCase() === 'barchartstacked') { 17 | this.enableStacking(); 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/assets/img/icons/view-2columns.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/app/components/widgets/charts/column-chart.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {BaseChartClass} from './base-chart.class'; 3 | 4 | @Component({ 5 | selector: 'dsw-column-chart', 6 | template: '', 7 | standalone: true 8 | }) 9 | export class ColumnChartComponent extends BaseChartClass implements OnInit { 10 | 11 | ngOnInit(): void { 12 | super.ngOnInit(); 13 | this.widget.isBtnZero = true; 14 | this.widget.isBtnValues = true; 15 | 16 | if (this.widget.type.toLowerCase() === "columnchartstacked") { 17 | this.enableStacking(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /dist/assets/img/spinner.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/img/spinner.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /dist/assets/img/widget-icons/widget-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/img/widget-icons/widget-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/widget-icons/back-1.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/widget-icons/back-1.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/assets/img/icons/text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/icons/view-5columns.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/assets/img/icons/text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/img/icons/view-5columns.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/assets/img/icons/reset.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /dist/assets/img/icons/reset.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /dist/assets/img/icons/icon-reload.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon-reload.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | @if (hs.visible$ | async) { 2 | 3 | } 4 |
5 | @if (isSidebar) { 6 | 7 | } 8 | 9 |
10 | 11 | 12 | @for (modal of ms.modals(); track $index) { 13 | 14 | } 15 | 16 | 17 | @for (err of es.errors$ | async; track trackError(idx, err); let idx = $index) { 18 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/app/directives/auto-focus.directive.ts: -------------------------------------------------------------------------------- 1 | import {AfterViewInit, Directive, ElementRef} from '@angular/core'; 2 | import {UtilService} from '../services/util.service'; 3 | 4 | @Directive({ 5 | selector: '[dswAutoFocus]', 6 | standalone: true 7 | }) 8 | export class AutoFocusDirective implements AfterViewInit { 9 | 10 | constructor(private el: ElementRef, private us: UtilService) { 11 | } 12 | 13 | ngAfterViewInit() { 14 | if (this.el.nativeElement.attributes.getNamedItem('dswAutoFocus').value === 'desktop') { 15 | // Focus only for desktop and ignore mobile 16 | if (this.us.isMobile()) { 17 | return; 18 | } 19 | } 20 | this.el.nativeElement.focus(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/app/components/ui/error/error.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | :host { 4 | font-family: $font; 5 | cursor: pointer; 6 | position: absolute; 7 | padding: 4px 10px; 8 | height: 32px; 9 | color: white; 10 | background-color: red; 11 | display: flex; 12 | justify-content: flex-start; 13 | align-items: center; 14 | border-radius: 4px; 15 | right: 10px; 16 | white-space: nowrap; 17 | max-width: 50%; 18 | transition: bottom 0.1s linear; 19 | z-index: 100; 20 | // Flex fix to show ellipsis on text 21 | & > span { 22 | min-width: 0; 23 | overflow: hidden; 24 | text-overflow: ellipsis; 25 | } 26 | 27 | &.left { 28 | right: auto; 29 | left: 10px; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /dist/assets/img/icons/icon-copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /dist/assets/img/icons/settings-black-24dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon-copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/img/icons/settings-black-24dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/chunk-HFC6Q7LK.js: -------------------------------------------------------------------------------- 1 | import{a as o}from"./chunk-YE4HGH46.js";import{h as n}from"./chunk-MG3ERZGY.js";var i=class extends o{constructor(){if(super(),typeof createImageBitmap>"u")throw new Error("Cannot decode WebImage as `createImageBitmap` is not available");if(typeof document>"u"&&typeof OffscreenCanvas>"u")throw new Error("Cannot decode WebImage as neither `document` nor `OffscreenCanvas` is not available")}decode(s,r){return n(this,null,function*(){let d=new Blob([r]),e=yield createImageBitmap(d),t;typeof document<"u"?(t=document.createElement("canvas"),t.width=e.width,t.height=e.height):t=new OffscreenCanvas(e.width,e.height);let a=t.getContext("2d");return a.drawImage(e,0,0),a.getImageData(0,0,e.width,e.height).data.buffer})}};export{i as default}; 2 | -------------------------------------------------------------------------------- /src/app/components/ui/text-area/text-area.component.ts: -------------------------------------------------------------------------------- 1 | import {AfterViewInit, Component, ElementRef, Input, ViewChild} from '@angular/core'; 2 | import {FormsModule} from '@angular/forms'; 3 | 4 | @Component({ 5 | selector: 'dsw-text-area', 6 | templateUrl: './text-area.component.html', 7 | styleUrls: ['./text-area.component.scss'], 8 | standalone: true, 9 | imports: [FormsModule] 10 | }) 11 | export class TextAreaComponent implements AfterViewInit { 12 | @Input() value = ''; 13 | @ViewChild('input') input!: ElementRef; 14 | 15 | constructor() { 16 | } 17 | 18 | ngAfterViewInit() { 19 | setTimeout(() => { 20 | this.input.nativeElement.focus(); 21 | this.input.nativeElement.select(); 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /dist/assets/img/icons/icon-check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/app/services/broadcast.service.ts: -------------------------------------------------------------------------------- 1 | import {EventEmitter, Injectable} from '@angular/core'; 2 | import {Subscription} from 'rxjs'; 3 | 4 | interface IBroadcast { 5 | message: string; 6 | value: any; 7 | } 8 | 9 | @Injectable({ 10 | providedIn: 'root' 11 | }) 12 | export class BroadcastService { 13 | 14 | private emitter = new EventEmitter(); 15 | 16 | constructor() { 17 | } 18 | 19 | broadcast(message: string, value?: any) { 20 | this.emitter.emit({message, value}); 21 | } 22 | 23 | subscribe(message: string, callback: (value: any) => void): Subscription { 24 | return this.emitter.subscribe((b: IBroadcast) => { 25 | if (b.message === message) { 26 | callback(b.value); 27 | } 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon-check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/chunk-23TAPEHU.js: -------------------------------------------------------------------------------- 1 | import{X as o,g as i,za as e}from"./chunk-ZEAAPN4P.js";var m=(()=>{class t{constructor(){this.visible$=new i(!1),this.onSearch=new i(""),this.onSearchReset=new e,this.shareDashboardEmitter=new e,this.gotoZenDeepSeeEmitter=new e,this.mobileFilterToggle=new e,this.mobileFilterDialogToggle=new e}resetSearch(){this.onSearchReset.emit()}shareDashboard(){this.shareDashboardEmitter.emit()}gotoZenDeepSee(){this.gotoZenDeepSeeEmitter.emit()}showMobileFilterButton(){this.mobileFilterToggle.emit(!0)}hideMobileFilterButton(){this.mobileFilterToggle.emit(!1)}toggleMobileFilterDialog(){this.mobileFilterDialogToggle.emit()}static{this.\u0275fac=function(r){return new(r||t)}}static{this.\u0275prov=o({token:t,factory:t.\u0275fac,providedIn:"root"})}}return t})();export{m as a}; 2 | -------------------------------------------------------------------------------- /src/app/components/ui/about/about.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, input, OnInit} from '@angular/core'; 2 | import {DataService} from '../../../services/data.service'; 3 | import {DomSanitizer, SafeHtml} from '@angular/platform-browser'; 4 | import markdownit from 'markdown-it'; 5 | 6 | @Component({ 7 | selector: 'dsw-about', 8 | templateUrl: './about.component.html', 9 | styleUrls: ['./about.component.scss'], 10 | standalone: true 11 | }) 12 | export class AboutComponent implements OnInit { 13 | html = input.required(); 14 | protected changelog?: SafeHtml; 15 | 16 | constructor(private ds: DataService, 17 | private san: DomSanitizer) { 18 | } 19 | 20 | ngOnInit() { 21 | this.changelog = markdownit({html: true}).render(this.html()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/app/components/ui/search/search-input/search-input.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | @import "breakpoints"; 3 | 4 | :host { 5 | position: relative; 6 | display: block; 7 | 8 | & > input { 9 | @include reset-input-styles; 10 | } 11 | } 12 | 13 | // Search input 14 | input { 15 | border: none; 16 | color: #606367; 17 | height: 24px; 18 | border-bottom: 1px solid #EBEBEA; 19 | padding-left: 16px; 20 | border-radius: 0; 21 | 22 | &:focus, &:active { 23 | border: none; 24 | border-bottom: 1px solid var(--cl-accent); 25 | outline: none; 26 | } 27 | 28 | &::placeholder { 29 | color: var(--cl-header-txt); 30 | opacity: 0.5; 31 | } 32 | } 33 | 34 | img { 35 | position: absolute; 36 | pointer-events: none; 37 | top: 5px; 38 | } 39 | -------------------------------------------------------------------------------- /src/app/components/ui/share-dashboard/share-dashboard/share-dashboard.component.html: -------------------------------------------------------------------------------- 1 |
2 |

{{ title }}

3 | 4 | 5 | @if (!hideOptions) { 6 | 7 | 8 | 9 | } 10 | 11 |
12 | -------------------------------------------------------------------------------- /module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | dsw 6 | 4.0.27 7 | module 8 | DeepSeeWeb (DSW) is an Angular UI layer for IRIS BI (DeepSee) dashboards 9 | 10 | 11 | MDX2JSON 12 | 3.* 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /dist/chunk-MDOQS4TE.js: -------------------------------------------------------------------------------- 1 | import{X as c,ib as r}from"./chunk-ZEAAPN4P.js";import{h as o}from"./chunk-MG3ERZGY.js";var u=[{label:"OK",default:!0,autoClose:!0}],a=(()=>{class e{#t;constructor(){this.#t=r([]),this.modals=this.#t.asReadonly()}show(t,s){return o(this,null,function*(){if(typeof t=="string"&&(t={message:t}),t.buttons||(t.buttons=JSON.parse(JSON.stringify(u)),s&&t.buttons&&(t.buttons[0].click=s)),t.inputs||(t.inputs={}),t.component&&t.component.then){yield t.component;let n=yield t.component;t.component=n[Object.keys(n)[0]]}this.#t.update(n=>[...n,t])})}close(t){let n=this.#t().indexOf(t);n!==-1&&(this.#t.update(i=>(i.splice(n,1),[...i])),t.onClose&&t.onClose())}static{this.\u0275fac=function(s){return new(s||e)}}static{this.\u0275prov=c({token:e,factory:e.\u0275fac,providedIn:"root"})}}return e})();export{a}; 2 | -------------------------------------------------------------------------------- /iris.script: -------------------------------------------------------------------------------- 1 | // Unexpire passwords to simplify dev mode. Comment these two lines for Production use 2 | zn "%SYS" 3 | Do ##class(Security.Users).UnExpireUserPasswords("*") 4 | 5 | ; enabling callin for Embedded Python 6 | do ##class(Security.Services).Get("%Service_CallIn",.prop) 7 | set prop("Enabled")=1 8 | set prop("AutheEnabled")=48 9 | do ##class(Security.Services).Modify("%Service_CallIn",.prop) 10 | 11 | // create IRISAPP namespace 12 | do $SYSTEM.OBJ.Load("/home/irisowner/irisdev/Installer.cls", "ck") 13 | set sc = ##class(App.Installer).setup() 14 | 15 | // Install samples BI 16 | zn "IRISAPP" 17 | zpm "install samples-bi" 18 | 19 | // load all the code of the project as a ZPM package 20 | zn "IRISAPP" 21 | zpm "load /home/irisowner/irisdev/ -v":1:1 22 | halt 23 | -------------------------------------------------------------------------------- /src/addons/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "forceConsistentCasingInFileNames": false, 4 | "strict": false, 5 | "noImplicitOverride": false, 6 | "noImplicitAny": false, 7 | "noPropertyAccessFromIndexSignature": false, 8 | "noImplicitReturns": false, 9 | "noFallthroughCasesInSwitch": false, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "sourceMap": false, 13 | "declaration": false, 14 | "experimentalDecorators": true, 15 | "moduleResolution": "node", 16 | "resolveJsonModule": true, 17 | "importHelpers": true, 18 | "target": "ES2022", 19 | "module": "CommonJS", 20 | "useDefineForClassFields": false, 21 | "lib": [ 22 | "ES2022", 23 | "dom" 24 | ], 25 | "outDir": "../../dist-addons/", 26 | "types": [] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/app/components/widgets/smiley/smiley.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, HostBinding, Input} from '@angular/core'; 2 | import {WMeterComponent} from '../base/meter-widget.class'; 3 | import {IWidgetDesc} from "../../../services/dsw.types"; 4 | 5 | 6 | @Component({ 7 | selector: 'dsw-wsmiley', 8 | templateUrl: './smiley.component.html', 9 | styleUrls: ['./smiley.component.scss'], 10 | changeDetection: ChangeDetectionStrategy.OnPush, 11 | standalone: true, 12 | imports: [] 13 | }) 14 | export class WSmileyComponent extends WMeterComponent { 15 | @Input() widget: IWidgetDesc = {} as IWidgetDesc; 16 | ; 17 | 18 | @HostBinding('style.grid-template-columns') 19 | get gridColumns() { 20 | return 'repeat(' + (this.data?.length >= 3 ? 3 : (this.data?.length || 0)).toString() + ', 1fr)'; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /dist/assets/img/icons/legend-toggle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/app/components/ui/sidebar-actions/sidebar-actions.component.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | 22 | -------------------------------------------------------------------------------- /src/assets/img/icons/legend-toggle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting() 21 | ); 22 | // Then we find all the tests. 23 | const context = require.context('./', true, /\.spec\.ts$/); 24 | // And load the modules. 25 | context.keys().map(context); 26 | -------------------------------------------------------------------------------- /src/app/components/widgets/traffic-light/traffic-light.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, HostBinding, Input} from '@angular/core'; 2 | import {WMeterComponent} from '../base/meter-widget.class'; 3 | import {IWidgetDesc} from "../../../services/dsw.types"; 4 | 5 | 6 | @Component({ 7 | selector: 'dsw-traffic-light', 8 | templateUrl: './traffic-light.component.html', 9 | styleUrls: ['./traffic-light.component.scss'], 10 | changeDetection: ChangeDetectionStrategy.OnPush, 11 | standalone: true, 12 | imports: [] 13 | }) 14 | export class WTrafficLightComponent extends WMeterComponent { 15 | @Input() widget: IWidgetDesc = {} as IWidgetDesc; 16 | 17 | @HostBinding('style.grid-template-columns') 18 | get gridColumns() { 19 | return 'repeat(' + (this.data?.length >= 3 ? 3 : (this.data?.length || 0)).toString() + ', 1fr)'; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/app/components/widgets/charts/area-chart.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {BaseChartClass} from './base-chart.class'; 3 | 4 | @Component({ 5 | selector: 'dsw-area-chart', 6 | template: '', 7 | standalone: true 8 | }) 9 | export class AreaChartComponent extends BaseChartClass implements OnInit { 10 | 11 | ngOnInit(): void { 12 | super.ngOnInit(); 13 | this.widget.isBtnZero = true; 14 | this.widget.isBtnValues = true; 15 | 16 | const ex = { 17 | plotOptions: { 18 | series: { 19 | colorByPoint: false 20 | }, 21 | area: { 22 | //stacking: 'percent', 23 | stacking: 'normal', 24 | marker: { 25 | enabled: false 26 | } 27 | } 28 | } 29 | }; 30 | this.us.mergeRecursive(this.chartConfig, ex); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /.github/sync-zpm-version.js: -------------------------------------------------------------------------------- 1 | const pkg = require('./../package.json'); 2 | const fs = require('fs'); 3 | const xml2js = require('xml2js'); 4 | const util = require('util'); 5 | 6 | const parser = new xml2js.Parser(); 7 | const xmlBuilder = new xml2js.Builder(); 8 | 9 | const data = fs.readFileSync('./module.xml'); 10 | 11 | 12 | parser.parseString(data, function (err, result) { 13 | const ver = result.Export.Document[0].Module[0].Version[0]; 14 | if (ver === pkg.version) { 15 | console.log('Versiona are equal: ' + pkg.version); 16 | return; 17 | } 18 | result.Export.Document[0].Module[0].Version[0] = pkg.version; 19 | 20 | const xml = xmlBuilder.buildObject(result, {xmldec: { 'version': '1.0', 'encoding': 'UTF-8' }}); 21 | 22 | console.log('Changing version of Module.xml to: ' + pkg.version); 23 | fs.writeFileSync('module.xml', xml); 24 | }); 25 | 26 | -------------------------------------------------------------------------------- /dist/chunk-G7BOERRR.js: -------------------------------------------------------------------------------- 1 | import{X as c,g as i,za as o}from"./chunk-ZEAAPN4P.js";import{h as s}from"./chunk-MG3ERZGY.js";var d=(()=>{class e{constructor(){this.sidebarToggle=new i(void 0),this.onAnimStart=new o,this.onAnimEnd=new o,this.stack=[]}hide(){this.resetComponentStack(),this.sidebarToggle.next(void 0)}showComponent(t){return s(this,null,function*(){if(!t){this.hide();return}if(t.component&&t.component.then){yield t.component;let n=yield t.component;t.component=n[Object.keys(n)[0]]}if(t?.single&&this.stack.find(r=>r.component===t?.component)){this.sidebarToggle.next(t);return}t?.component&&this.stack.push(t),t&&this.sidebarToggle.next(t)})}popComponent(){this.stack.pop();let t=this.stack.pop()||null;this.showComponent(t)}resetComponentStack(){this.stack=[]}static{this.\u0275fac=function(n){return new(n||e)}}static{this.\u0275prov=c({token:e,factory:e.\u0275fac,providedIn:"root"})}}return e})();export{d as a}; 2 | -------------------------------------------------------------------------------- /src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import {Routes} from '@angular/router'; 2 | import {LoginScreenComponent} from './components/screens/login-screen/login-screen.component'; 3 | import {MainScreenComponent} from './components/screens/main-screen/main-screen.component'; 4 | import {NamespaceService} from './services/namespace.service'; 5 | import {ConfigResolver} from './services/config-resolver'; 6 | 7 | export const routes: Routes = [ 8 | {path: '', component: LoginScreenComponent, resolve: {model: NamespaceService}}, 9 | {path: 'login', component: LoginScreenComponent}, 10 | { 11 | path: ':ns', resolve: {model: ConfigResolver}, runGuardsAndResolvers: 'always', children: [ 12 | { 13 | path: '**', 14 | component: MainScreenComponent, 15 | data: {isDashboard: true}, 16 | resolve: {model: ConfigResolver}, 17 | runGuardsAndResolvers: 'always' 18 | } 19 | ] 20 | }, 21 | ]; 22 | -------------------------------------------------------------------------------- /dist/assets/img/icons/language-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/icons/language-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/scss/breakpoints.scss: -------------------------------------------------------------------------------- 1 | // Small tablets and large smartphones (landscape view) 2 | $screen-sm-min: 576px; 3 | 4 | // Small tablets (portrait view) 5 | $screen-md-min: 768px; 6 | 7 | // Tablets and small desktops 8 | $screen-lg-min: 992px; 9 | 10 | // Large tablets and desktops 11 | $screen-xl-min: 1200px; 12 | 13 | // Small devices 14 | @mixin sm { 15 | @media (max-width: #{$screen-sm-min}) { 16 | @content; 17 | } 18 | } 19 | 20 | // Medium devices 21 | @mixin md { 22 | @media (max-width: #{$screen-md-min}) { 23 | @content; 24 | } 25 | } 26 | 27 | // Large devices 28 | @mixin lg { 29 | @media (max-width: #{$screen-lg-min}) { 30 | @content; 31 | } 32 | } 33 | 34 | // Extra large devices 35 | @mixin xl { 36 | @media (max-width: #{$screen-xl-min}) { 37 | @content; 38 | } 39 | } 40 | 41 | @mixin only-sm { 42 | @media (min-width: #{$screen-sm-min}) { 43 | display: none !important; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /dist/assets/img/icons/icon-close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon-close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /tmp 5 | /out-tsc 6 | # Only exists if Bazel was run 7 | /bazel-out 8 | 9 | # dependencies 10 | /node_modules 11 | 12 | # profiling files 13 | chrome-profiler-events*.json 14 | speed-measure-plugin*.json 15 | 16 | # IDEs and editors 17 | /.idea 18 | .project 19 | .classpath 20 | .c9/ 21 | *.launch 22 | .settings/ 23 | *.sublime-workspace 24 | 25 | # IDE - VSCode 26 | .vscode/* 27 | !.vscode/settings.json 28 | !.vscode/tasks.json 29 | !.vscode/launch.json 30 | !.vscode/extensions.json 31 | .history/* 32 | 33 | # misc 34 | .angular 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | 48 | # addons compilation modules 49 | /dist/commonjs 50 | /dist-addons 51 | /e2e/screenshots 52 | -------------------------------------------------------------------------------- /src/assets/img/icons/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | close [#1511] 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /dist/assets/img/icons/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | close [#1511] 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.github/workflows/test-ui.yml: -------------------------------------------------------------------------------- 1 | # on: push 2 | on: 3 | workflow_run: 4 | workflows: ["Build Angular"] 5 | types: 6 | - completed 7 | name: Test UI 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | node-version: [20.14.0] 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: Build the docker 18 | run: | 19 | docker compose build 20 | docker compose up -d 21 | 22 | - name: Check running containers 23 | run: docker ps -a 24 | 25 | - name: Create directory for artifacts 26 | run: mkdir -p ./e2e/screenshots 27 | 28 | - name: Install node modules 29 | run: npm i 30 | 31 | - name: Running test 32 | run: npm test 33 | 34 | - name: Archive artifacts 35 | if: always() 36 | uses: actions/upload-artifact@v4 37 | with: 38 | name: screenshots 39 | path: ./e2e/screenshots 40 | -------------------------------------------------------------------------------- /src/app/components/ui/menu/menu-settings/menu-settings.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {SidebarService} from '../../../../services/sidebar.service'; 3 | 4 | @Component({ 5 | selector: 'dsw-menu-settings', 6 | templateUrl: './menu-settings.component.html', 7 | styleUrls: ['./../menu.component.scss'], 8 | standalone: true 9 | }) 10 | export class MenuSettingsComponent implements OnInit { 11 | 12 | constructor(private sbs: SidebarService) { 13 | } 14 | 15 | ngOnInit(): void { 16 | } 17 | 18 | showThemeSettings() { 19 | this.sbs.showComponent({component: import('./../../theme-settings/theme-settings.component')}); 20 | } 21 | 22 | showAppSettings() { 23 | this.sbs.showComponent({component: import('./../../app-settings/app-settings.component')}); 24 | } 25 | 26 | showChartsSettings() { 27 | this.sbs.showComponent({component: import('../../chart-colors-config/chart-colors-config.component')}); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/app/services/variables.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root' 5 | }) 6 | export class VariablesService { 7 | 8 | items: any[] = []; 9 | widgets: any[] = []; 10 | 11 | constructor() { 12 | } 13 | 14 | /** 15 | * Initialize service 16 | */ 17 | init(result) { 18 | this.items = []; 19 | this.widgets = []; 20 | if (!result.widgets) { 21 | return; 22 | } 23 | for (let i = 0; i < result.widgets.length; i++) { 24 | const w: any = result.widgets[i]; 25 | this.widgets.push(w); 26 | for (let j = 0; j < w.controls.length; j++) { 27 | if (w.controls[j].action.toLowerCase() === 'applyvariable') { 28 | this.items.push(w.controls[j]); 29 | } 30 | } 31 | } 32 | } 33 | 34 | /** 35 | * Clear all variables 36 | */ 37 | clear() { 38 | this.items = []; 39 | } 40 | 41 | isExists(): boolean { 42 | return this.items.length !== 0; 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /dist/assets/img/icons/table.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/img/icons/table.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/widget-icons/widget-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/img/widget-icons/widget-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Installer.cls: -------------------------------------------------------------------------------- 1 | Class App.Installer 2 | { 3 | 4 | XData setup 5 | { 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | } 22 | 23 | ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 3, pInstaller As %Installer.Installer, pLogger As %Installer.AbstractLogger) As %Status [ CodeMode = objectgenerator, Internal ] 24 | { 25 | #; Let XGL document generate code for this method. 26 | Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "setup") 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/app/components/widgets/base/widget/widget.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | :host { 4 | display: flex; 5 | flex-direction: column; 6 | width: 100%; 7 | height: 100%; 8 | min-height: 0; 9 | overflow: hidden; 10 | background-color: var(--cl-widget-bg); 11 | padding: 20px; 12 | } 13 | 14 | .error { 15 | font-family: $font; 16 | position: absolute; 17 | inset: 0; 18 | color: rgb(215 7 2 / 58%); 19 | background-color: transparent; 20 | text-align: center; 21 | background: var(--cl-widget-bg); 22 | display: flex; 23 | align-items: center; 24 | justify-content: center; 25 | padding: 20px; 26 | z-index: 10; 27 | } 28 | 29 | .spinner { 30 | position: absolute; 31 | left: 0; 32 | right: 0; 33 | top: 44px; 34 | bottom: 0; 35 | z-index: 3; 36 | display: flex; 37 | justify-content: center; 38 | align-items: center; 39 | background-color: rgba(255, 255, 255, 0.9); 40 | backdrop-filter: blur(2px); 41 | height: auto; 42 | } 43 | 44 | dsw-widget-filter { 45 | z-index: 4; 46 | } 47 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon-next.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/icons/icon-next.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon-next-blue.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/icons/icon-next-blue.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/icons/next.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/app/components/widgets/smiley/smiley.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | :host { 4 | // display: flex; 5 | display: grid; 6 | width: 100%; 7 | height: 100%; 8 | font-family: $font; 9 | -webkit-user-select: initial; 10 | user-select: initial; 11 | align-items: center; 12 | justify-content: center; 13 | } 14 | 15 | img { 16 | width: 100%; 17 | 18 | max-height: calc(100% - 24px); 19 | max-width: 100%; 20 | /* width: 100%; 21 | height: 100%;*/ 22 | } 23 | 24 | .card { 25 | width: 100%; 26 | height: 100%; 27 | flex: 1 1 100%; 28 | min-width: 0; 29 | min-height: 0; 30 | display: flex; 31 | flex-direction: column; 32 | align-items: center; 33 | justify-content: center; 34 | 35 | & > div { 36 | height: 100%; 37 | } 38 | } 39 | 40 | label { 41 | width: 100%; 42 | font-family: $font; 43 | color: gray; 44 | font-size: 14px; 45 | text-align: center; 46 | height: 24px; 47 | max-height: 24px; 48 | white-space: nowrap; 49 | overflow: hidden; 50 | text-overflow: ellipsis; 51 | } 52 | -------------------------------------------------------------------------------- /src/assets/img/icons/next.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /dist/assets/img/widget-icons/widget-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/img/widget-icons/widget-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/app/components/widgets/traffic-light/traffic-light.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | :host { 4 | // display: flex; 5 | display: grid; 6 | width: 100%; 7 | height: 100%; 8 | font-family: $font; 9 | -webkit-user-select: initial; 10 | user-select: initial; 11 | align-items: center; 12 | justify-content: center; 13 | gap: 20px; 14 | } 15 | 16 | img { 17 | width: 100%; 18 | 19 | max-height: calc(100% - 24px); 20 | max-width: 100%; 21 | /* width: 100%; 22 | height: 100%;*/ 23 | } 24 | 25 | .card { 26 | width: 100%; 27 | height: 100%; 28 | flex: 1 1 100%; 29 | min-width: 0; 30 | min-height: 0; 31 | display: flex; 32 | flex-direction: column; 33 | align-items: center; 34 | justify-content: center; 35 | 36 | & > div { 37 | height: 100%; 38 | } 39 | } 40 | 41 | label { 42 | width: 100%; 43 | font-family: $font; 44 | color: gray; 45 | font-size: 14px; 46 | text-align: center; 47 | height: 24px; 48 | max-height: 24px; 49 | white-space: nowrap; 50 | overflow: hidden; 51 | text-overflow: ellipsis; 52 | } 53 | -------------------------------------------------------------------------------- /src/app/components/ui/app-settings/app-settings.component.html: -------------------------------------------------------------------------------- 1 | Settings 2 |
3 | 4 | 5 | 6 | 9 | 10 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 |
26 |
27 | -------------------------------------------------------------------------------- /src/app/components/widgets/charts/line-chart.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {BaseChartClass} from './base-chart.class'; 3 | 4 | @Component({ 5 | selector: 'dsw-line-chart', 6 | template: '', 7 | standalone: true 8 | }) 9 | export class LineChartComponent extends BaseChartClass implements OnInit { 10 | 11 | ngOnInit() { 12 | super.ngOnInit(); 13 | this.widget.isBtnZero = true; 14 | this.widget.isBtnValues = true; 15 | let ex = {}; 16 | if (this.widget.type.toLowerCase() !== 'combochart') { 17 | ex = { 18 | plotOptions: { 19 | series: { 20 | lineWidth: 3, 21 | marker: { 22 | enabled: false 23 | } 24 | } 25 | }, 26 | }; 27 | } 28 | 29 | if (this.widget.type.toLowerCase() === 'linechartmarkers') { 30 | ex = { 31 | series: { 32 | marker: { 33 | enabled: true 34 | } 35 | } 36 | }; 37 | } 38 | this.us.mergeRecursive(this.chartConfig, ex); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /dist/assets/img/icons/pen.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | pen [#1319] 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/img/icons/pen.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | pen [#1319] 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/app/components/ui/tabs/tabs.component.html: -------------------------------------------------------------------------------- 1 | @for (tab of tabs; track trackByIdentity($index, tab)) { 2 |
9 | 12 | {{ tab.text }} 13 |
14 | } 15 | @if (isMoreButtonVisible) { 16 |
17 | 18 |
19 | } 20 | 21 | @if (isOpened) { 22 | 35 | } 36 | -------------------------------------------------------------------------------- /src/app/components/ui/modal/modal.component.html: -------------------------------------------------------------------------------- 1 | 36 | -------------------------------------------------------------------------------- /src/environments/dsw.ts: -------------------------------------------------------------------------------- 1 | import pkg from './../../package.json'; 2 | 3 | interface IDSWConfig { 4 | addons: string[]; 5 | mobile: boolean; 6 | desktop: boolean; 7 | const: any; 8 | } 9 | 10 | export const dsw: IDSWConfig = { 11 | // TODO: add type for addons 12 | addons: [], 13 | mobile: false, // TODO: add to init = screen.availWidth <= 600; 14 | desktop: true, 15 | const: { 16 | themes: [ 17 | {text: 'Default', file: ''}, 18 | {text: 'Contrast', file: 'contrast.css'} 19 | // {text: 'Metro', file: 'themes/metro.css'}, 20 | // {text: 'Black', file: 'themes/black.css'} 21 | ], 22 | bgColorClasses: ['', 'cl1', 'cl2', 'cl3', 'cl4', 'cl5', 'cl6', 'cl7', 'cl8', 'cl9'], 23 | fontColors: ['fc0', 'fc1', 'fc2', 'fc3', 'fc4', 'fc5'], 24 | icons: ['', 'ico-widget-back', 'ico-widget-folder', 'ico-widget-1', 'ico-widget-dashboard', 'ico-widget-2', 'ico-widget-3', 'ico-widget-4'], 25 | timeout: 60000, 26 | ver: pkg.version, 27 | emptyWidgetClass: 'MDX2JSON.EmptyPortlet'.toLowerCase() 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /src/scss/date-picker.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | // Change selection color 4 | .air-datepicker-cell.-selected- { 5 | --adp-background-color-selected-other-month: var(--cl-accent); 6 | --adp-cell-background-color-selected: var(--cl-accent); 7 | --adp-cell-background-color-in-range: var(--cl-hover); 8 | --adp-cell-border-radius: 40px; 9 | } 10 | 11 | // Change font and color 12 | .air-datepicker { 13 | --adp-color: #1C1D20; 14 | font-family: $font; 15 | --adp-color-current-date: var(--cl-accent); 16 | --adp-width: 224px; 17 | } 18 | 19 | // Day names 20 | .air-datepicker-body--day-name { 21 | --adp-day-name-color: var(--cl-widget-filter-txt); 22 | } 23 | 24 | // Day names background 25 | .air-datepicker-body--day-names { 26 | background-color: #EBEBEA; 27 | padding: 0; 28 | margin: 0; 29 | // margin-bottom: 4px; 30 | 31 | padding-top: 6px; 32 | padding-bottom: 6px; 33 | /* padding-left: 4px; 34 | padding-right: 4px;*/ 35 | } 36 | 37 | .air-datepicker-body--cells.-days- { 38 | /*padding-left: 4px; 39 | padding-right: 4px;*/ 40 | } 41 | 42 | .air-datepicker--content { 43 | padding: 0; 44 | } 45 | -------------------------------------------------------------------------------- /src/scss/themes/deepblue.scss: -------------------------------------------------------------------------------- 1 | @import "../variables"; 2 | 3 | :root { 4 | --cl-main: #2a3f54; 5 | --cl-accent: #0258f6; 6 | 7 | --cl-btn-main: #5c79b8; 8 | --cl-btn-main-txt: #fff; 9 | --cl-btn-main-border: #4c6bae; 10 | --cl-btn-main-hover: #6e8bca; 11 | 12 | --cl-btn-secondary-border: #3f2222; 13 | --cl-btn-secondary-hover: #3f3f3f; 14 | 15 | 16 | --cl-header-bg: var(--cl-main); 17 | --cl-header-border: var(--cl-main); 18 | --cl-header-txt: white; 19 | --cl-header-ico: white; 20 | --cl-sidebar-txt: white; 21 | 22 | --cl-text-widget-font: #000; 23 | --cl-widget-filter-txt: #fff; 24 | --cl-widget-filter-bg: #364d64; 25 | --widget-header-btn-opacity: 1; 26 | --widget-header-btn-filter: invert(1); 27 | --widget-header-btn-active-filter: contrast(0.2) sepia(1) brightness(1.1) hue-rotate(-655deg) contrast(4); 28 | 29 | --cl-header-btn-hover: #445a70; 30 | --cl-header-btn-active: #364d64; 31 | 32 | --cl-sidebar-bg: #364d64; 33 | --menu-item-icon-filter: invert(1); 34 | --icon-filter: invert(1); 35 | 36 | 37 | } 38 | 39 | 40 | //@import "../main"; 41 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/DeepSeeWeb'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 InterSystems Corp. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /src/app/components/ui/date-filter/date-filter.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | :host { 4 | font-family: $font; 5 | font-size: 14px; 6 | color: var(--cl-widget-filter-txt); 7 | display: flex; 8 | align-items: flex-start; 9 | overflow: auto; 10 | 11 | &::-webkit-scrollbar { 12 | width: 5px; 13 | height: 8px; 14 | background-color: #eee; /* or add it to the track */ 15 | } 16 | 17 | &::-webkit-scrollbar-thumb { 18 | background: #aaa; 19 | } 20 | } 21 | 22 | ul { 23 | border-right: 1px solid var(--cl-input-border); 24 | padding: 20px; 25 | margin: 0; 26 | list-style-type: none; 27 | } 28 | 29 | li { 30 | white-space: nowrap; 31 | cursor: pointer; 32 | 33 | &:not(:last-child) { 34 | margin-bottom: 12px; 35 | } 36 | 37 | &.selected { 38 | position: relative; 39 | color: var(--cl-accent); 40 | 41 | &:before { 42 | position: absolute; 43 | left: -20px; 44 | top: 0; 45 | height: 100%; 46 | width: 2px; 47 | content: ""; 48 | background-color: var(--cl-accent); 49 | } 50 | } 51 | } 52 | 53 | dsw-date-picker::ng-deep.air-datepicker { 54 | border: none; 55 | } 56 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG IMAGE=intersystemsdc/irishealth-community:2020.3.0.200.0-zpm 2 | ARG IMAGE=intersystemsdc/iris-community:2020.4.0.547.0-zpm 3 | ARG IMAGE=containers.intersystems.com/intersystems/iris:2021.1.0.215.0 4 | ARG IMAGE=intersystemsdc/iris-community:preview 5 | ARG IMAGE=intersystemsdc/irishealth-community 6 | ARG IMAGE=intersystemsdc/iris-community 7 | FROM $IMAGE 8 | 9 | WORKDIR /home/irisowner/irisdev 10 | 11 | ## install git 12 | ## USER root 13 | ##RUN apt update && apt-get -y install git 14 | ##USER ${ISC_PACKAGE_MGRUSER} 15 | 16 | ARG TESTS=0 17 | ARG MODULE="dc-sample" 18 | ARG NAMESPACE="IRISAPP" 19 | 20 | ## Embedded Python environment 21 | ENV IRISUSERNAME "_SYSTEM" 22 | ENV IRISPASSWORD "SYS" 23 | ENV IRISNAMESPACE $NAMESPACE 24 | ENV PYTHON_PATH=/usr/irissys/bin/ 25 | ENV PATH "/usr/irissys/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/irisowner/bin" 26 | 27 | 28 | RUN --mount=type=bind,src=.,dst=. \ 29 | iris start IRIS && \ 30 | iris session IRIS < iris.script && \ 31 | ([ $TESTS -eq 0 ] || iris session iris -U $NAMESPACE "##class(%ZPM.PackageManager).Shell(\"test $MODULE -v -only\",1,1)") && \ 32 | iris stop IRIS quietly 33 | -------------------------------------------------------------------------------- /src/app/components/ui/share-dashboard/share-dashboard/share-dashboard.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | :host { 4 | z-index: 4; 5 | text-align: left; 6 | padding: 20px; 7 | // background: red; 8 | // background: red; 9 | } 10 | 11 | div { 12 | background: #FFFFFF; 13 | box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1); 14 | border-radius: 10px; 15 | padding: 20px; 16 | } 17 | 18 | p { 19 | font-family: $font; 20 | font-weight: 500; 21 | font-size: 14px; 22 | line-height: 16px; 23 | color: var(--cl-header-txt); 24 | margin-top: 0; 25 | margin-bottom: 20px; 26 | } 27 | 28 | input, textarea { 29 | margin-bottom: 10px; 30 | min-width: 200px; 31 | color: var(--cl-header-txt); 32 | font-size: 12px; 33 | line-height: 14px; 34 | } 35 | 36 | textarea { 37 | min-height: 120px; 38 | 39 | &.small { 40 | min-height: 80px; 41 | } 42 | } 43 | 44 | button { 45 | width: 100%; 46 | } 47 | 48 | input { 49 | min-width: 16px; 50 | width: 16px; 51 | display: inline-block; 52 | margin: 0; 53 | margin-right: 4px; 54 | vertical-align: bottom 55 | } 56 | 57 | label { 58 | display: block; 59 | margin-bottom: 10px; 60 | font-weight: normal; 61 | } 62 | -------------------------------------------------------------------------------- /src/app/services/header.service.ts: -------------------------------------------------------------------------------- 1 | import {EventEmitter, Injectable} from '@angular/core'; 2 | import {BehaviorSubject} from 'rxjs'; 3 | 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class HeaderService { 9 | visible$ = new BehaviorSubject(false); 10 | onSearch = new BehaviorSubject(''); 11 | onSearchReset = new EventEmitter(); 12 | shareDashboardEmitter = new EventEmitter(); 13 | gotoZenDeepSeeEmitter = new EventEmitter(); 14 | mobileFilterToggle = new EventEmitter(); 15 | mobileFilterDialogToggle = new EventEmitter(); 16 | 17 | // onSetTitle = new BehaviorSubject(''); 18 | 19 | constructor() { 20 | 21 | } 22 | 23 | resetSearch() { 24 | this.onSearchReset.emit(); 25 | } 26 | 27 | shareDashboard() { 28 | this.shareDashboardEmitter.emit(); 29 | } 30 | 31 | gotoZenDeepSee() { 32 | this.gotoZenDeepSeeEmitter.emit(); 33 | } 34 | 35 | showMobileFilterButton() { 36 | this.mobileFilterToggle.emit(true); 37 | } 38 | 39 | hideMobileFilterButton() { 40 | this.mobileFilterToggle.emit(false); 41 | } 42 | 43 | toggleMobileFilterDialog() { 44 | this.mobileFilterDialogToggle.emit(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/app/components/widgets/base/widget/widget.component.html: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 22 | 23 | 24 | @if (widgetType && widgetType.class) { 25 | 26 | } 27 | 28 | 29 | @if (model.error) { 30 |
{{ model.error }}
31 | } 32 | 33 | 34 | @if (component?.isSpinner && !model.error) { 35 |
36 | 37 |
38 | } 39 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "outDir": "./dist/out-tsc", 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": false, 9 | "noImplicitAny": false, 10 | "noPropertyAccessFromIndexSignature": false, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "skipLibCheck": true, 14 | "esModuleInterop": true, 15 | "sourceMap": true, 16 | "declaration": false, 17 | "experimentalDecorators": true, 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "importHelpers": true, 21 | "target": "ES2022", 22 | "module": "ES2022", 23 | "useDefineForClassFields": false, 24 | "lib": [ 25 | "ES2022", 26 | "dom" 27 | ] 28 | }, 29 | "angularCompilerOptions": { 30 | "enableI18nLegacyMessageIdFormat": false, 31 | "strictInjectionParameters": true, 32 | "strictInputAccessModifiers": true, 33 | "strictTemplates": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /dist/assets/img/icons/icon-edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon-edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/smiley/smile-red.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/img/smiley/smile-red.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /dist/assets/img/smiley/smile-green.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /dist/chunk-YE4HGH46.js: -------------------------------------------------------------------------------- 1 | import{h}from"./chunk-MG3ERZGY.js";function g(o,n){let e=o.length-n,i=0;do{for(let a=n;a>0;a--)o[i+n]+=o[i],i++;e-=n}while(e>0)}function u(o,n,e){let i=0,a=o.length,l=a/e;for(;a>n;){for(let t=n;t>0;--t)o[i+n]+=o[i],++i;a-=n}let c=o.slice();for(let t=0;t=o.byteLength);++r){let s;if(n===2){switch(a[0]){case 8:s=new Uint8Array(o,r*t*e*c,t*e*c);break;case 16:s=new Uint16Array(o,r*t*e*c,t*e*c/2);break;case 32:s=new Uint32Array(o,r*t*e*c,t*e*c/4);break;default:throw new Error(`Predictor 2 not allowed with ${a[0]} bits per sample.`)}g(s,t,c)}else n===3&&(s=new Uint8Array(o,r*t*e*c,t*e*c),u(s,t,c))}return o}var d=class{decode(n,e){return h(this,null,function*(){let i=yield this.decodeBlock(e),a=n.Predictor||1;if(a!==1){let l=!n.StripOffsets,c=l?n.TileWidth:n.ImageWidth,t=l?n.TileLength:n.RowsPerStrip||n.ImageLength;return f(i,a,c,t,n.BitsPerSample,n.PlanarConfiguration)}return i})}};export{d as a}; 2 | -------------------------------------------------------------------------------- /src/assets/img/smiley/smile-green.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/img/smiley/smile-yellow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /dist/assets/img/smiley/smile-yellow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/img/map-pin-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | location-pin 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /dist/assets/img/map-pin-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | location-pin 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/app/components/ui/language-selector/language-selector.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | import {I18nService} from '../../../services/i18n.service'; 3 | import {SidebarService} from '../../../services/sidebar.service'; 4 | import {StorageService} from '../../../services/storage.service'; 5 | 6 | 7 | @Component({ 8 | selector: 'dsw-language-selector', 9 | templateUrl: './language-selector.component.html', 10 | styleUrls: ['./../menu/menu.component.scss'], 11 | standalone: true, 12 | imports: [] 13 | }) 14 | export class LanguageSelectorComponent { 15 | 16 | languages: string[]; 17 | 18 | constructor(public i18n: I18nService, 19 | private storage: StorageService, 20 | private ss: SidebarService) { 21 | this.languages = this.i18n.getLanguages(); 22 | } 23 | 24 | selectLanguage(lang: any) { 25 | const settings = this.storage.getAppSettings(); 26 | this.i18n.current = lang; 27 | settings.language = lang; 28 | this.storage.setAppSettings(settings); 29 | window.location.reload(); 30 | 31 | this.ss.hide(); 32 | } 33 | 34 | /** 35 | * Returns true if language is selected 36 | * @param lang 37 | */ 38 | isSelected(lang: string) { 39 | return this.i18n.current === lang; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/app/components/ui/input/input/input.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | $border-radius: 4px; 4 | 5 | :host { 6 | position: relative; 7 | display: block; 8 | 9 | &.choose > input { 10 | // padding-right: calc(10px + var(--cl-input-height)); 11 | width: calc(100% - var(--cl-input-height)); 12 | border-radius: $border-radius 0 0 $border-radius; 13 | } 14 | 15 | &.invalid { 16 | & input { 17 | border-color: red; 18 | } 19 | } 20 | } 21 | 22 | input { 23 | font-family: $font; 24 | font-size: 13px; 25 | border-radius: $border-radius; 26 | height: var(--cl-input-height); 27 | text-overflow: ellipsis; 28 | } 29 | 30 | button { 31 | position: absolute; 32 | top: 0; 33 | right: 0; 34 | width: var(--cl-input-height); 35 | height: var(--cl-input-height); 36 | padding: 0; 37 | border: 1px solid var(--cl-input-border); 38 | border-left: none; 39 | background-color: var(--cl-input-bg); 40 | cursor: pointer; 41 | font-family: $font; 42 | color: var(--cl-input-text); 43 | font-size: 16px; 44 | border-radius: 0 $border-radius $border-radius 0; 45 | transition: background-color 0.2s linear; 46 | 47 | &:hover { 48 | background-color: var(--cl-hover); 49 | } 50 | 51 | &:active { 52 | transform: translateY(1px); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/app/components/screens/folder-screen/folder-screen.component.html: -------------------------------------------------------------------------------- 1 | 2 | @for (tile of data$ | async; track tile) { 3 | @let desc = itemDesc[tile.idx]; 4 | 5 | 13 | 14 | @if (desc) { 15 | 16 | } 17 | 18 | @if (!desc && model.icons[tile.icon]; as icon) { 19 |
20 | } 21 | 22 | @if (!tile.hideTitle) { 23 | 26 | } 27 |
28 | } 29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /src/app/components/widgets/light-bar/light-bar.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, HostBinding, Input} from '@angular/core'; 2 | import {IMeterWidgetData, WMeterComponent} from '../base/meter-widget.class'; 3 | import {IWidgetDesc} from "../../../services/dsw.types"; 4 | 5 | 6 | interface ILightbarData extends IMeterWidgetData { 7 | progress: number; 8 | } 9 | 10 | @Component({ 11 | selector: 'dsw-light-bar', 12 | templateUrl: './light-bar.component.html', 13 | styleUrls: ['./light-bar.component.scss'], 14 | changeDetection: ChangeDetectionStrategy.OnPush, 15 | standalone: true, 16 | imports: [] 17 | }) 18 | export class WLightBarComponent extends WMeterComponent { 19 | @Input() widget: IWidgetDesc = {} as IWidgetDesc; 20 | data: ILightbarData[] = []; 21 | dots = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 22 | 23 | @HostBinding('style.grid-template-columns') 24 | get gridColumns() { 25 | return 'repeat(' + (this.data?.length >= 5 ? 2 : 1).toString() + ', 1fr)'; 26 | } 27 | 28 | prepareMeterData(result: any) { 29 | super.prepareMeterData(result); 30 | this.data.forEach(d => { 31 | d.progress = (d.value - d.min) / (d.max - d.min) * 10; 32 | if (isNaN(d.progress)) { 33 | d.progress = 0; 34 | } 35 | }); 36 | console.log(this.data); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /dist/assets/img/icons/view-list.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/img/icons/view-list.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/app/components/widgets/map-widget-old/map-widget.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | ; 4 | :host { 5 | position: relative; 6 | } 7 | 8 | .tooltip { 9 | margin-top: 24px; 10 | z-index: 1000; 11 | position: absolute; 12 | border: solid 1px #000000; 13 | color: #000000; 14 | background-color: #ffffe1; 15 | white-space: nowrap; 16 | font-family: $font; 17 | font-size: 13px; 18 | -moz-box-shadow: 2px 2px 4px #7f7f7f; 19 | box-shadow: 2px 2px 4px #7f7f7f; 20 | padding: 2px 3px; 21 | } 22 | 23 | .map-popup { 24 | transform: translateY(-100%) translateX(-50%); 25 | z-index: 1; 26 | position: absolute; 27 | background-color: var(--cl-widget-filter-bg); 28 | margin-bottom: 0px; 29 | border-color: rgb(176, 176, 176); 30 | padding: 4px; 31 | -webkit-box-shadow: 1px 1px 9px 0px rgba(50, 50, 50, 0.5); 32 | -moz-box-shadow: 1px 1px 9px 0px rgba(50, 50, 50, 0.5); 33 | box-shadow: 1px 1px 9px 0px rgba(50, 50, 50, 0.5); 34 | color: var(--cl-widget-header-txt); 35 | } 36 | 37 | .map-popup:after { 38 | content: " "; 39 | display: block; 40 | width: 0; 41 | height: 0; 42 | border-style: solid; 43 | border-width: 8px 4px 0 4px; 44 | bottom: -8px; 45 | left: calc(50% - 4px); 46 | position: absolute; 47 | border-color: var(--cl-widget-filter-bg) transparent transparent transparent; 48 | } 49 | -------------------------------------------------------------------------------- /src/scss/gridster.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | @import "breakpoints"; 3 | 4 | .no-anim { 5 | -webkit-transition: none !important; 6 | transition: none !important; 7 | } 8 | 9 | //// Gridster without animation 10 | gridster.no-anim-g .gridster-column, 11 | gridster.no-anim-g .gridster-row, 12 | gridster.no-anim-g gridster-item, 13 | gridster.no-anim-g gridster-item.gridster-item-resizing, 14 | gridster.no-anim-g gridster-item.gridster-item-moving { 15 | transition: unset !important; 16 | } 17 | 18 | gridster-item { 19 | transition-property: width, height, transform !important; 20 | } 21 | 22 | // Gridster resize handler 23 | gridster-item:hover .gridster-item-resizable-handler.handle-se { 24 | border-color: transparent transparent var(--cl-accent) !important; 25 | z-index: 10; 26 | } 27 | 28 | // Needed to make greater than LPT zindex, so user can resize widget 29 | .gridster-item:hover .gridster-item-resizable-handler.handle-se { 30 | z-index: 1000; 31 | } 32 | 33 | // Mobile item height 34 | .gridster.mobile gridster-item { 35 | @include sm { 36 | height: $mobile-folder-height !important; // Because gridster uses inline styles 37 | margin-bottom: 0 !important; 38 | } 39 | } 40 | 41 | // Remove padding for mobile 42 | .gridster.mobile { 43 | @include sm { 44 | padding: 0 !important; 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/app/services/lpt.types.ts: -------------------------------------------------------------------------------- 1 | import {IMDXData} from './dsw.types'; 2 | 3 | export interface ILPTConfig { 4 | initialData?: IMDXData; 5 | } 6 | 7 | export interface ILPTControls { 8 | back: () => void; 9 | } 10 | 11 | export interface ILPTView { 12 | displayMessage: (msg: string) => void; 13 | } 14 | 15 | export interface ILPTDataSource { 16 | FILTERS: string; 17 | _convert: (data: IMDXData) => ILPTData; 18 | } 19 | 20 | export interface ILPTDataRow { 21 | 22 | } 23 | 24 | export interface ILPTColumnProp { 25 | 26 | } 27 | 28 | export interface ILPTData { 29 | columnProps: ILPTColumnProp[]; 30 | dataArray: number[]; 31 | dimensions: string[]; 32 | } 33 | 34 | export interface ILPTDataController { 35 | setData: (data: ILPTData) => void; 36 | getData: () => ILPTData; 37 | } 38 | 39 | export interface ILPDDataSourceStack { 40 | BASIC_MDX: string; 41 | } 42 | 43 | export interface ILightPivotTable { 44 | DRILL_LEVEL: number; 45 | CONFIG: ILPTConfig; 46 | CONTROLS: ILPTControls; 47 | pivotView: ILPTView; 48 | dataSource: ILPTDataSource; 49 | dataController: ILPTDataController; 50 | updateSizes: () => void; 51 | changeBasicMDX: (newMdx: string) => void; 52 | isListing: () => boolean; 53 | getActualMDX: () => string; 54 | getSelectedRows: () => number[]; 55 | _dataSourcesStack: ILPDDataSourceStack[]; 56 | } 57 | -------------------------------------------------------------------------------- /dist/chunk-MG3ERZGY.js: -------------------------------------------------------------------------------- 1 | var q=Object.create;var h=Object.defineProperty,r=Object.defineProperties,s=Object.getOwnPropertyDescriptor,t=Object.getOwnPropertyDescriptors,u=Object.getOwnPropertyNames,g=Object.getOwnPropertySymbols,m=Object.getPrototypeOf,k=Object.prototype.hasOwnProperty,n=Object.prototype.propertyIsEnumerable,v=Reflect.get;var l=(a,b,c)=>b in a?h(a,b,{enumerable:!0,configurable:!0,writable:!0,value:c}):a[b]=c,x=(a,b)=>{for(var c in b||={})k.call(b,c)&&l(a,c,b[c]);if(g)for(var c of g(b))n.call(b,c)&&l(a,c,b[c]);return a},y=(a,b)=>r(a,t(b));var z=(a,b)=>{var c={};for(var d in a)k.call(a,d)&&b.indexOf(d)<0&&(c[d]=a[d]);if(a!=null&&g)for(var d of g(a))b.indexOf(d)<0&&n.call(a,d)&&(c[d]=a[d]);return c};var A=(a,b)=>()=>(b||a((b={exports:{}}).exports,b),b.exports),B=(a,b)=>{for(var c in b)h(a,c,{get:b[c],enumerable:!0})},w=(a,b,c,d)=>{if(b&&typeof b=="object"||typeof b=="function")for(let e of u(b))!k.call(a,e)&&e!==c&&h(a,e,{get:()=>b[e],enumerable:!(d=s(b,e))||d.enumerable});return a};var C=(a,b,c)=>(c=a!=null?q(m(a)):{},w(b||!a||!a.__esModule?h(c,"default",{value:a,enumerable:!0}):c,a));var D=(a,b,c)=>v(m(a),c,b);var E=(a,b,c)=>new Promise((d,e)=>{var o=f=>{try{i(c.next(f))}catch(j){e(j)}},p=f=>{try{i(c.throw(f))}catch(j){e(j)}},i=f=>f.done?d(f.value):Promise.resolve(f.value).then(o,p);i((c=c.apply(a,b)).next())});export{x as a,y as b,z as c,A as d,B as e,C as f,D as g,E as h}; 2 | -------------------------------------------------------------------------------- /dist/chunk-ZMZIHCGB.js: -------------------------------------------------------------------------------- 1 | import{a as k}from"./chunk-YE4HGH46.js";import"./chunk-MG3ERZGY.js";var x=9,E=256,b=257,B=12;function C(c,o,r){let i=o%8,n=Math.floor(o/8),h=8-i,g=o+r-(n+1)*8,l=8*(n+2)-(o+r),w=(n+2)*8-o;if(l=Math.max(0,l),n>=c.length)return console.warn("ran off the end of the buffer before finding EOI_CODE (end on input code)"),b;let u=c[n]&2**(8-i)-1;u<<=r-h;let s=u;if(n+1>>l;f<<=Math.max(0,r-w),s+=f}if(g>8&&n+2>>f;s+=t}return s}function p(c,o){for(let r=o.length-1;r>=0;r--)c.push(o[r]);return c}function D(c){let o=new Uint16Array(4093),r=new Uint8Array(4093);for(let e=0;e<=257;e++)o[e]=4096,r[e]=e;let i=258,n=x,h=0;function g(){i=258,n=x}function l(e){let a=C(e,h,n);return h+=n,a}function w(e,a){return r[i]=a,o[i]=e,i++,i-1}function u(e){let a=[];for(let y=e;y!==4096;y=o[y])a.push(r[y]);return a}let s=[];g();let f=new Uint8Array(c),t=l(f),d;for(;t!==b;){if(t===E){for(g(),t=l(f);t===E;)t=l(f);if(t===b)break;if(t>E)throw new Error(`corrupted code at scanline ${t}`);{let e=u(t);p(s,e),d=t}}else if(t=2**n&&(n===B?d=void 0:n++),t=l(f)}return new Uint8Array(s)}var A=class extends k{decodeBlock(o){return D(o,!1).buffer}};export{A as default}; 2 | -------------------------------------------------------------------------------- /src/app/components/editor/type-and-datasource/type-and-datasource.component.html: -------------------------------------------------------------------------------- 1 | 6 | Type & Datasource 7 | 8 | 9 | @if (model) { 10 |
11 | 12 | 21 | 22 | 23 | 30 | 31 | 32 | 42 | 43 | 44 | 46 |
47 | } 48 | -------------------------------------------------------------------------------- /src/app/components/ui/menu/menu.component.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 | @if (!isHome) { 4 |
  • 5 | 6 | {{ 'gotoDeepSee' | i18n }} 7 |
  • 8 | } 9 | 10 | 11 | 15 | 16 |
    17 | 18 | @if (isHome) { 19 |
  • 20 | 21 | Edit dashboard 22 |
  • 23 | } 24 |
  • 25 | 26 | Settings 27 |
  • 28 |
  • 29 | 30 | Namespace 31 |
  • 32 |
  • 33 | 34 | Language 35 |
  • 36 |
  • 37 | 38 | About 39 |
  • 40 |
  • 41 | 42 | Logout 43 |
  • 44 |
45 | v.{{ version }} 46 | -------------------------------------------------------------------------------- /src/app/components/editor/datasource-selector-dialog/datasource-selector-dialog.html: -------------------------------------------------------------------------------- 1 |
2 | 8 | 9 |
10 | 11 | 12 | @for (d of data; track trackByIndex($index, d)) { 13 |
14 | @if (d.children?.length) { 15 | 16 | } 17 | {{ d.name }} 18 |
19 | } 20 |
21 | 22 |
23 | 24 |
25 | 26 |
27 | 28 | 29 | @for (sel of selected; track trackByIndex(idx, sel); let idx = $index) { 30 |
31 | 32 |
33 | } 34 | 35 | 36 | @if (isLoading) { 37 |
38 | 39 |
40 | } 41 | 42 | 43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /src/app/components/screens/main-screen/main-screen.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnDestroy, OnInit} from '@angular/core'; 2 | import {ActivatedRoute} from '@angular/router'; 3 | import {combineLatest, Subscription} from 'rxjs'; 4 | import {HeaderService} from '../../../services/header.service'; 5 | import {DashboardScreenComponent} from '../dashboard-screen/dashboard-screen.component'; 6 | import {FolderScreenComponent} from '../folder-screen/folder-screen.component'; 7 | 8 | @Component({ 9 | selector: 'dsw-main-screen', 10 | templateUrl: './main-screen.component.html', 11 | styleUrls: ['./main-screen.component.scss'], 12 | standalone: true, 13 | imports: [FolderScreenComponent, DashboardScreenComponent] 14 | }) 15 | export class MainScreenComponent implements OnInit, OnDestroy { 16 | isFolder = true; 17 | private subRoutechange: Subscription; 18 | 19 | constructor(private route: ActivatedRoute, private hs: HeaderService) { 20 | this.hs.visible$.next(true); 21 | this.subRoutechange = combineLatest([ 22 | this.route.url, 23 | this.route.params 24 | ]).subscribe(([segments, params]) => { 25 | const path = [params.name, ...segments.map(s => s.path)].join('/'); 26 | this.isFolder = path.indexOf('.dashboard') === -1; 27 | }); 28 | } 29 | 30 | ngOnInit(): void { 31 | } 32 | 33 | ngOnDestroy(): void { 34 | this.subRoutechange.unsubscribe(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /dist/assets/img/icons/view-3columns.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/assets/img/icons/view-3columns.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/app/components/ui/theme-settings/theme-settings.component.html: -------------------------------------------------------------------------------- 1 | Theme settings 2 |
3 | 4 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | @for (v of variables; track trackVariable($index, v)) { 24 | 25 | 26 | 38 | 39 | } 40 | 41 |
NameValue
{{ v.name }} 27 | @if (v.isColor) { 28 | 33 | } 34 | @if (!v.isColor) { 35 | 36 | } 37 |
42 |
43 | 44 |
45 | -------------------------------------------------------------------------------- /ngsw-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/service-worker/config/schema.json", 3 | "index": "/index.html", 4 | "dataGroups": [ 5 | { 6 | "name": "api", 7 | "urls": [ 8 | "/MDX2JSON", 9 | "/MDX2JSON/**", 10 | "/MDX2JSON/*", 11 | "/mdx2json", 12 | "/mdx2json/*", 13 | "/mdx2json/**" 14 | ], 15 | "cacheConfig": { 16 | "maxSize": 0, 17 | "maxAge": "0u", 18 | "strategy": "freshness" 19 | } 20 | } 21 | ], 22 | "assetGroups": [ 23 | { 24 | "name": "app", 25 | "installMode": "prefetch", 26 | "resources": { 27 | "files": [ 28 | "/favicon.ico", 29 | "/index.html", 30 | "/manifest.webmanifest", 31 | "/*.css", 32 | "/*.js" 33 | ] 34 | } 35 | }, 36 | { 37 | "name": "assets", 38 | "installMode": "lazy", 39 | "updateMode": "prefetch", 40 | "resources": { 41 | "files": [ 42 | "/assets/**", 43 | "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)" 44 | ] 45 | } 46 | } 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon-logout.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/assets/img/icons/icon-logout.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dist/manifest.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DeepSeeWeb", 3 | "short_name": "DeepSeeWeb", 4 | "theme_color": "#1976d2", 5 | "background_color": "#fafafa", 6 | "display": "standalone", 7 | "scope": "./", 8 | "start_url": "index.html", 9 | "icons": [ 10 | { 11 | "src": "assets/img/logo.png", 12 | "sizes": "72x72", 13 | "type": "image/png", 14 | "purpose": "any" 15 | }, 16 | { 17 | "src": "assets/img/logo.png", 18 | "sizes": "96x96", 19 | "type": "image/png", 20 | "purpose": "any" 21 | }, 22 | { 23 | "src": "assets/img/logo.png", 24 | "sizes": "128x128", 25 | "type": "image/png", 26 | "purpose": "any" 27 | }, 28 | { 29 | "src": "assets/img/logo.png", 30 | "sizes": "144x144", 31 | "type": "image/png", 32 | "purpose": "any" 33 | }, 34 | { 35 | "src": "assets/img/logo.png", 36 | "sizes": "152x152", 37 | "type": "image/png", 38 | "purpose": "any" 39 | }, 40 | { 41 | "src": "assets/img/logo.png", 42 | "sizes": "192x192", 43 | "type": "image/png", 44 | "purpose": "any" 45 | }, 46 | { 47 | "src": "assets/img/logo.png", 48 | "sizes": "384x384", 49 | "type": "image/png", 50 | "purpose": "any" 51 | }, 52 | { 53 | "src": "assets/img/logo.png", 54 | "sizes": "512x512", 55 | "type": "image/png", 56 | "purpose": "any" 57 | } 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /src/manifest.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DeepSeeWeb", 3 | "short_name": "DeepSeeWeb", 4 | "theme_color": "#1976d2", 5 | "background_color": "#fafafa", 6 | "display": "standalone", 7 | "scope": "./", 8 | "start_url": "index.html", 9 | "icons": [ 10 | { 11 | "src": "assets/img/logo.png", 12 | "sizes": "72x72", 13 | "type": "image/png", 14 | "purpose": "any" 15 | }, 16 | { 17 | "src": "assets/img/logo.png", 18 | "sizes": "96x96", 19 | "type": "image/png", 20 | "purpose": "any" 21 | }, 22 | { 23 | "src": "assets/img/logo.png", 24 | "sizes": "128x128", 25 | "type": "image/png", 26 | "purpose": "any" 27 | }, 28 | { 29 | "src": "assets/img/logo.png", 30 | "sizes": "144x144", 31 | "type": "image/png", 32 | "purpose": "any" 33 | }, 34 | { 35 | "src": "assets/img/logo.png", 36 | "sizes": "152x152", 37 | "type": "image/png", 38 | "purpose": "any" 39 | }, 40 | { 41 | "src": "assets/img/logo.png", 42 | "sizes": "192x192", 43 | "type": "image/png", 44 | "purpose": "any" 45 | }, 46 | { 47 | "src": "assets/img/logo.png", 48 | "sizes": "384x384", 49 | "type": "image/png", 50 | "purpose": "any" 51 | }, 52 | { 53 | "src": "assets/img/logo.png", 54 | "sizes": "512x512", 55 | "type": "image/png", 56 | "purpose": "any" 57 | } 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /src/app/components/widgets/text/wtext.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | :host { 4 | display: flex; 5 | //flex-direction: column; 6 | flex-display: row; 7 | width: 100%; 8 | height: 100%; 9 | font-family: $font; 10 | -webkit-user-select: initial; 11 | user-select: initial; 12 | 13 | // No background for labels on tiles 14 | &.inline label { 15 | background-color: transparent; 16 | background-image: none; 17 | } 18 | } 19 | 20 | .item { 21 | display: flex; 22 | flex-direction: column; 23 | height: 100%; 24 | min-height: 0; 25 | } 26 | 27 | label { 28 | display: block; 29 | flex-shrink: 0; 30 | height: 16px; 31 | background-image: linear-gradient(to bottom, #f5f5f5 0, #e8e8e8 100%); 32 | width: 100%; 33 | text-align: center; 34 | font-family: monospace; 35 | white-space: nowrap; 36 | overflow: hidden; 37 | text-overflow: ellipsis; 38 | } 39 | 40 | .item2 { 41 | display: flex; 42 | flex-direction: column; 43 | flex: 1 1 100%; 44 | justify-content: center; 45 | align-items: center; 46 | margin: 10px; 47 | background-color: #fafafa; 48 | padding: 10px; 49 | min-height: 0; 50 | min-width: 0; 51 | 52 | &.clickable { 53 | cursor: pointer; 54 | } 55 | 56 | & > label { 57 | height: auto; 58 | background: transparent; 59 | color: gray; 60 | font-size: 19px; 61 | } 62 | 63 | & > svg { 64 | height: 50%; 65 | width: 100%; 66 | display: block; 67 | } 68 | } 69 | 70 | .text-widget { 71 | height: 100%; 72 | } 73 | -------------------------------------------------------------------------------- /dist/chunk-NF3Y2YSA.js: -------------------------------------------------------------------------------- 1 | import{F as c,J as f}from"./chunk-YZADXMU6.js";import{X as o,aa as n,g as r,za as l}from"./chunk-ZEAAPN4P.js";var p=(()=>{class e{constructor(){this.emitter=new l}broadcast(t,s){this.emitter.emit({message:t,value:s})}subscribe(t,s){return this.emitter.subscribe(i=>{i.message===t&&s(i.value)})}static{this.\u0275fac=function(s){return new(s||e)}}static{this.\u0275prov=o({token:e,factory:e.\u0275fac,providedIn:"root"})}}return e})();var v=(()=>{class e{constructor(t){this.ss=t,this.current=new r(""),this.dashboard=new r(null),this.widgets=[],this.allWidgets=[]}setWidgets(t){this.widgets=t}getWidgets(){return this.widgets}getWidgetsWithoutEmpty(t=[]){return this.widgets.filter(s=>s.type!==c.const.emptyWidgetClass&&!t.includes(s.name))}setAllWidgets(t){this.allWidgets=t}getAllWidgets(){return this.allWidgets}saveWidgetPositionAndSize(t){let s=this.ss.getWidgetsSettings(t.dashboard),i=t.name;s[i]||(s[i]={}),isNaN(t.x)||(s[i].col=t.x),isNaN(t.y)||(s[i].row=t.y),isNaN(t.cols)||(s[i].sizeX=t.cols),isNaN(t.rows)||(s[i].sizeY=t.rows),this.ss.setWidgetsSettings(s,t.dashboard)}generateDisplayInfo(t){if(t.displayInfo)return;let s=1,i=1,a=this.dashboard.value;a&&(s=Math.floor(12/a.displayInfo.gridCols),s<1&&(s=1),i<1&&(i=1));let h={topCol:Math.floor((t.x||0)/s),leftRow:Math.floor((t.y||0)/i),colWidth:Math.floor((t.cols||1)/s),rowHeight:Math.floor(t.rows||1)};t.displayInfo=h}static{this.\u0275fac=function(s){return new(s||e)(n(f))}}static{this.\u0275prov=o({token:e,factory:e.\u0275fac,providedIn:"root"})}}return e})();export{p as a,v as b}; 2 | -------------------------------------------------------------------------------- /dist/assets/img/icons/icon-search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon-search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/app/components/widgets/base/widget-filter/widget-filter.component.html: -------------------------------------------------------------------------------- 1 | 2 | @for (v of widget().pvItems; track v) { 3 | 4 | 5 | 6 | 7 | } 8 | 9 | 10 | @for (chooser of widget().dsItems; track chooser) { 11 | 12 | 13 | @if (chooser.field === 'select') { 14 | 19 | } 20 | @if (chooser.field === 'input') { 21 | 23 | } 24 | 25 | } 26 | 27 | 28 | @for (action of widget().acItems; track action) { 29 | 30 | 31 | 32 | } 33 | 34 | 35 | @for (flt of filters(); track flt) { 36 | 37 | 38 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /dist/assets/img/icons/view-6columns.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/assets/img/icons/view-6columns.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.github/workflows/angular-build.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | name: Build Angular 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | strategy: 7 | matrix: 8 | node-version: [20.14.0] 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | with: 13 | #persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token 14 | fetch-depth: 0 # otherwise, you will failed to push refs to dest repo 15 | 16 | - name: Cache node modules 17 | uses: actions/cache@v3 18 | with: 19 | path: ~/.npm 20 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 21 | restore-keys: | 22 | ${{ runner.os }}-node- 23 | - name: Node ${{ matrix.node-version }} 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | 28 | - name: Installing modules (npm i) 29 | run: | 30 | npm i 31 | 32 | - name: Updating version for ZPM 33 | run: | 34 | node ./.github/sync-zpm-version 35 | 36 | - name: Building DSW and addons 37 | run: | 38 | npm run build:addons 39 | npm run build 40 | 41 | - name: Deploying dist to master 42 | continue-on-error: true 43 | run: | 44 | git config --local user.email "action@github.com" 45 | git config --local user.name "GitHub Action" 46 | git add ./dist/* 47 | git add ./module.xml 48 | git commit -am "Automated commit of dist" 49 | git push 50 | 51 | -------------------------------------------------------------------------------- /src/app/components/ui/input/input/input.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, EventEmitter, forwardRef, HostBinding, Input, Output} from '@angular/core'; 2 | import {ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR} from "@angular/forms"; 3 | 4 | @Component({ 5 | selector: 'dsw-input', 6 | templateUrl: './input.component.html', 7 | styleUrls: ['./input.component.scss'], 8 | providers: [ 9 | { 10 | provide: NG_VALUE_ACCESSOR, 11 | useExisting: forwardRef(() => InputComponent), 12 | multi: true 13 | } 14 | ], 15 | standalone: true, 16 | imports: [FormsModule] 17 | }) 18 | export class InputComponent implements ControlValueAccessor { 19 | @Input() model = ''; 20 | @Input() type = 'text'; 21 | @Input() required = false; 22 | @HostBinding('class.choose') 23 | @Input() chooseButton = false; 24 | @Output() choose = new EventEmitter(); 25 | 26 | constructor() { 27 | } 28 | 29 | @HostBinding('class.invalid') 30 | get isInvalid() { 31 | return this.required && !this.model; 32 | } 33 | 34 | onChange = (_) => { 35 | }; 36 | onTouched = () => { 37 | }; 38 | 39 | writeValue(value: any): void { 40 | this.model = value; 41 | } 42 | 43 | registerOnChange(fn: any): void { 44 | this.onChange = fn; 45 | } 46 | 47 | registerOnTouched(fn: any): void { 48 | this.onTouched = fn; 49 | } 50 | 51 | setDisabledState?(isDisabled: boolean): void { 52 | return; 53 | } 54 | 55 | onSelectButtonClick() { 56 | this.choose.emit(); 57 | } 58 | 59 | onModelChange(txt: any) { 60 | this.writeValue(txt); 61 | this.onChange(txt); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/app/services/error.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {BehaviorSubject} from 'rxjs'; 3 | 4 | const DEFAULT_ERROR_DELAY = 5000; 5 | 6 | export interface IError { 7 | id: number; 8 | message?: string; 9 | delay: number; 10 | isLeft?: boolean; 11 | } 12 | 13 | @Injectable({ 14 | providedIn: 'root' 15 | }) 16 | export class ErrorService { 17 | errors$ = new BehaviorSubject([]); 18 | private lastId = 0; 19 | private errors: IError[] = []; 20 | 21 | constructor() { 22 | } 23 | 24 | /** 25 | * Returns error index 26 | */ 27 | getIndex(error: IError): number { 28 | return this.errors.indexOf(error); 29 | } 30 | 31 | /** 32 | * Closes error 33 | */ 34 | close(error: IError) { 35 | const idx = this.errors.findIndex(e => e === error); 36 | if (idx !== -1) { 37 | this.errors.splice(idx, 1); 38 | this.emit(); 39 | } 40 | } 41 | 42 | /** 43 | * Shows error 44 | */ 45 | show(message: string, isLeft = false, delay: number = DEFAULT_ERROR_DELAY) { 46 | // Generate id 47 | this.lastId++; 48 | 49 | // Add new error 50 | const error = { 51 | id: this.lastId, 52 | message, 53 | delay, 54 | isLeft 55 | }; 56 | this.errors.push(error); 57 | 58 | // Remove error after delay 59 | if (delay !== 0) { 60 | setTimeout(() => { 61 | this.close(error); 62 | }, delay); 63 | } 64 | 65 | // Emit errors array 66 | this.emit(); 67 | } 68 | 69 | /** 70 | * Emit new state of errors array 71 | */ 72 | private emit() { 73 | this.errors$.next([...this.errors]); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/app/components/ui/sidebar-actions/sidebar-actions.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ChangeDetectionStrategy, 3 | ChangeDetectorRef, 4 | Component, 5 | EventEmitter, 6 | Input, 7 | OnDestroy, 8 | OnInit, 9 | Output 10 | } from '@angular/core'; 11 | import {SidebarService} from "../../../services/sidebar.service"; 12 | import {EditorService} from "../../../services/editor.service"; 13 | import {Subscription} from "rxjs"; 14 | import {I18nPipe} from '../../../services/i18n.service'; 15 | 16 | 17 | @Component({ 18 | selector: 'dsw-sidebar-actions', 19 | templateUrl: './sidebar-actions.component.html', 20 | styleUrls: ['./sidebar-actions.component.scss'], 21 | changeDetection: ChangeDetectionStrategy.OnPush, 22 | standalone: true, 23 | imports: [I18nPipe] 24 | }) 25 | export class SidebarActionsComponent implements OnInit, OnDestroy { 26 | @Input() isBack = false; 27 | @Input() isWidgetEditorWarning = false; 28 | @Output() cancel = new EventEmitter(); 29 | @Output() apply = new EventEmitter(); 30 | 31 | isWidgetEditorWarningVisible = false; 32 | private subOnUnsavedChanged?: Subscription; 33 | 34 | constructor(private sbs: SidebarService, 35 | private eds: EditorService, 36 | private cd: ChangeDetectorRef) { 37 | } 38 | 39 | ngOnInit(): void { 40 | this.subOnUnsavedChanged = this.eds.onUnsavedChanged.subscribe(state => { 41 | this.isWidgetEditorWarningVisible = state; 42 | this.cd.detectChanges(); 43 | }); 44 | } 45 | 46 | onCloseClick() { 47 | if (this.isBack) { 48 | this.sbs.popComponent(); 49 | } 50 | this.cancel.emit(); 51 | } 52 | 53 | ngOnDestroy() { 54 | this.subOnUnsavedChanged?.unsubscribe(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/app/components/widgets/light-bar/light-bar.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | :host { 4 | // display: flex; 5 | display: grid; 6 | width: 100%; 7 | height: 100%; 8 | font-family: $font; 9 | -webkit-user-select: initial; 10 | user-select: initial; 11 | align-items: center; 12 | justify-content: center; 13 | gap: 20px; 14 | } 15 | 16 | .holder { 17 | width: 100%; 18 | height: 100%; 19 | flex: 1 1 100%; 20 | min-width: 0; 21 | min-height: 0; 22 | display: flex; 23 | flex-direction: column; 24 | align-items: center; 25 | justify-content: center; 26 | } 27 | 28 | label { 29 | width: 100%; 30 | font-family: $font; 31 | color: gray; 32 | font-size: 14px; 33 | text-align: center; 34 | height: 24px; 35 | max-height: 24px; 36 | white-space: nowrap; 37 | overflow: hidden; 38 | text-overflow: ellipsis; 39 | } 40 | 41 | .bar { 42 | display: flex; 43 | width: 100%; 44 | height: 24px; 45 | // height: calc(100% - 24px); 46 | border: 1px solid var(--cl-accent); 47 | border-radius: 1000px; 48 | padding-left: 3px; 49 | padding-right: 3px; 50 | gap: 4px; 51 | justify-content: space-between; 52 | align-items: center; 53 | } 54 | 55 | .dot { 56 | background: var(--cl-hover); 57 | border-radius: 1000px; 58 | /* flex: 1 1 100%; 59 | max-width: 100%; 60 | max-height: 100%; 61 | aspect-ratio: 1;*/ 62 | width: 100%; 63 | height: 100%; 64 | 65 | max-width: 18px; 66 | max-height: 18px; 67 | 68 | &.filled { 69 | background: var(--cl-accent); 70 | } 71 | } 72 | 73 | 74 | .bar.high > .dot:last-child { 75 | background-color: rgba(224, 125, 134, 1); 76 | } 77 | 78 | .bar.low > .dot:first-child { 79 | background-color: #175ab8; 80 | } 81 | -------------------------------------------------------------------------------- /dist/assets/img/icons/icon-settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon-settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/addons/htmlViewer.ts: -------------------------------------------------------------------------------- 1 | import {Component, inject, OnDestroy, OnInit} from '@angular/core'; 2 | import {Subscription} from 'rxjs'; 3 | import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser'; 4 | import {BaseWidget} from "../app/components/widgets/base-widget.class"; 5 | import {IAddonInfo} from "../app/services/dsw.types"; 6 | 7 | @Component({ 8 | standalone: true, 9 | template: ` 10 | ` 11 | }) 12 | export class HtmlViewer extends BaseWidget implements OnInit, OnDestroy { 13 | static AddonInfo: IAddonInfo = { 14 | // Version of addon system, should be specified manually as number, not reference 15 | // version always should be equal to BaseWidget.CURRENT_ADDON_VERSION 16 | // used to compare unsupported addons when breaking changes are made into BaseWidget 17 | // Note: do not use reference to BaseWidget.CURRENT_ADDON_VERSIO here! 18 | // specify number MANUALLY 19 | version: 1, 20 | // Widget type 21 | // 'custom' for all non-standard widgets 22 | // 'chart' for highcharts widget 23 | type: 'custom' 24 | }; 25 | isSpinner = false; 26 | url: SafeResourceUrl; 27 | private san = inject(DomSanitizer); 28 | private subOnFilter: Subscription; 29 | 30 | 31 | ngOnInit(): void { 32 | this.url = this.san.bypassSecurityTrustResourceUrl(this.getUrl()); 33 | 34 | this.subOnFilter = this.fs.onApplyFilter.subscribe(flt => { 35 | this.url = this.san.bypassSecurityTrustResourceUrl(this.getUrl().replace('$$$FILTERS', encodeURIComponent(flt.value))); 36 | }); 37 | } 38 | 39 | getUrl(): string { 40 | return this.widget?.properties?.Data || ''; 41 | } 42 | 43 | ngOnDestroy() { 44 | this.subOnFilter.unsubscribe(); 45 | super.ngOnDestroy(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/app/components/ui/namespace-selector/namespace-selector.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, ChangeDetectorRef, Component} from '@angular/core'; 2 | import {SidebarService} from '../../../services/sidebar.service'; 3 | import {CURRENT_NAMESPACE, NamespaceService} from '../../../services/namespace.service'; 4 | import {Router} from '@angular/router'; 5 | import {DataService} from '../../../services/data.service'; 6 | 7 | @Component({ 8 | selector: 'dsw-namespace-selector', 9 | templateUrl: './namespace-selector.component.html', 10 | styleUrls: ['./../menu/menu.component.scss'], 11 | standalone: true, 12 | imports: [], 13 | changeDetection: ChangeDetectionStrategy.OnPush 14 | }) 15 | export class NamespaceSelectorComponent { 16 | 17 | items: string[] = []; 18 | isLoading = true; 19 | 20 | constructor(private ss: SidebarService, 21 | private ns: NamespaceService, 22 | private ds: DataService, 23 | private cdr: ChangeDetectorRef, 24 | private router: Router) { 25 | this.requestData(); 26 | } 27 | 28 | /** 29 | * Select namespace callback 30 | */ 31 | selectNamespace(ns: string) { 32 | this.ns.setCurrent(ns); 33 | void this.router.navigateByUrl(ns); 34 | this.ss.hide(); 35 | } 36 | 37 | /** 38 | * Returs true if namespace selected 39 | */ 40 | isSelected(ns: string) { 41 | return ns.toLowerCase() === CURRENT_NAMESPACE.toLowerCase(); 42 | } 43 | 44 | private requestData() { 45 | this.ds.getSettings(CURRENT_NAMESPACE) 46 | .then((settings: any) => { 47 | this.ns.setNamespaces(settings.Mappings.Mapped); 48 | }) 49 | .finally(() => { 50 | this.isLoading = false; 51 | this.items = this.ns.getNamespaces(); 52 | this.cdr.detectChanges(); 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/app/components/editor/datasource-selector-dialog/datasource-selector-dialog.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | :host { 4 | display: flex; 5 | flex-direction: column; 6 | height: 100%; 7 | overflow: hidden; 8 | } 9 | 10 | .header { 11 | flex-shrink: 0; 12 | } 13 | 14 | .table { 15 | position: relative; 16 | flex: 1 1 100%; 17 | min-width: 800px; 18 | min-height: 0; 19 | display: flex; 20 | white-space: nowrap; 21 | overflow: hidden; 22 | 23 | & > div { 24 | flex-shrink: 0; 25 | flex-grow: 1; 26 | flex-basis: 25%; 27 | border-right: 1px solid var(--cl-input-border); 28 | overflow: auto; 29 | min-width: 25%; 30 | width: 25%; 31 | @include dsw-scrollbar-v; 32 | 33 | &:first-child { 34 | position: sticky; 35 | left: 0; 36 | z-index: 2; 37 | background: white; 38 | } 39 | } 40 | } 41 | 42 | .row { 43 | user-select: none; 44 | padding: 5px 4px; 45 | cursor: pointer; 46 | align-items: center; 47 | color: var(--cl-widget-filter-txt); 48 | max-width: 25em; 49 | overflow: hidden; 50 | white-space: nowrap; 51 | text-overflow: ellipsis; 52 | position: relative; 53 | // padding-right: 20px; 54 | 55 | &:hover { 56 | background-color: var(--cl-hover); 57 | color: var(--cl-header-txt); 58 | } 59 | 60 | &.selected { 61 | color: var(--cl-accent); 62 | background-color: var(--cl-sidebar-bg); 63 | } 64 | 65 | & > img { 66 | height: 18px; 67 | vertical-align: text-top; 68 | margin-right: 2px; 69 | } 70 | 71 | /* &:after { 72 | position: absolute; 73 | right: 0; 74 | content: "»"; 75 | }*/ 76 | } 77 | 78 | /* 79 | .no-data { 80 | display: flex; 81 | align-items: center; 82 | justify-content: center; 83 | color: var(--cl-txt); 84 | min-height: 400px; 85 | } 86 | */ 87 | --------------------------------------------------------------------------------