Merge pull request #53 from liosha84/50-cleare-jambotron-ui-project-1
Add new components for AI and tutorials, update routing, and enhance …
This commit is contained in:
@@ -50,3 +50,4 @@ out/
|
|||||||
|
|
||||||
/.idea/
|
/.idea/
|
||||||
|
|
||||||
|
/uploads/
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ dependencies {
|
|||||||
implementation("org.flywaydb:flyway-database-postgresql:10.4.1")
|
implementation("org.flywaydb:flyway-database-postgresql:10.4.1")
|
||||||
|
|
||||||
implementation 'org.springframework.ai:spring-ai-zhipuai-spring-boot-starter:1.0.0-M6'
|
implementation 'org.springframework.ai:spring-ai-zhipuai-spring-boot-starter:1.0.0-M6'
|
||||||
|
implementation 'org.springframework:spring-mock:2.0.8'
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'io.spring.dependency-management'
|
apply plugin: 'io.spring.dependency-management'
|
||||||
|
|||||||
@@ -38,10 +38,34 @@
|
|||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"@angular/material/prebuilt-themes/azure-blue.css",
|
"@angular/material/prebuilt-themes/azure-blue.css",
|
||||||
"src/styles.scss"
|
"src/styles.scss",
|
||||||
|
"node_modules/prismjs/themes/prism-okaidia.css",
|
||||||
|
"node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css",
|
||||||
|
"node_modules/prismjs/plugins/line-highlight/prism-line-highlight.css",
|
||||||
|
"node_modules/prismjs/plugins/command-line/prism-command-line.css",
|
||||||
|
|
||||||
|
"node_modules/bootstrap/dist/css/bootstrap.css",
|
||||||
|
"node_modules/bootstrap-markdown/css/bootstrap-markdown.min.css",
|
||||||
|
"node_modules/font-awesome/css/font-awesome.css"
|
||||||
|
|
||||||
|
|
||||||
],
|
],
|
||||||
"scripts": [
|
"scripts": [
|
||||||
"node_modules/viewerjs/dist/viewer.min.js"
|
"node_modules/viewerjs/dist/viewer.min.js",
|
||||||
|
"node_modules/prismjs/prism.js",
|
||||||
|
"node_modules/prismjs/components/prism-csharp.min.js",
|
||||||
|
"node_modules/prismjs/components/prism-css.min.js",
|
||||||
|
"node_modules/prismjs/components/prism-javascript.min.js",
|
||||||
|
"node_modules/prismjs/components/prism-typescript.min.js",
|
||||||
|
"node_modules/prismjs/components/prism-java.js",
|
||||||
|
"node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js",
|
||||||
|
"node_modules/prismjs/plugins/line-highlight/prism-line-highlight.js",
|
||||||
|
"node_modules/prismjs/plugins/command-line/prism-command-line.js",
|
||||||
|
|
||||||
|
|
||||||
|
"node_modules/jquery/dist/jquery.js",
|
||||||
|
"node_modules/bootstrap-markdown/js/bootstrap-markdown.js"
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
+202
@@ -24,8 +24,12 @@
|
|||||||
"@ng-bootstrap/ng-bootstrap": "19.0.0",
|
"@ng-bootstrap/ng-bootstrap": "19.0.0",
|
||||||
"@popperjs/core": "2.11.8",
|
"@popperjs/core": "2.11.8",
|
||||||
"@primeng/themes": "^19.1.3",
|
"@primeng/themes": "^19.1.3",
|
||||||
|
"angular-markdown-editor": "^3.1.1",
|
||||||
"bootstrap": "5.3.6",
|
"bootstrap": "5.3.6",
|
||||||
|
"cropperjs": "^2.0.1",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
|
"ngx-filesaver": "^20.0.0",
|
||||||
"ngx-markdown": "^20.0.0",
|
"ngx-markdown": "^20.0.0",
|
||||||
"ngx-scrollbar": "18.0.0",
|
"ngx-scrollbar": "18.0.0",
|
||||||
"primeng": "^19.1.3",
|
"primeng": "^19.1.3",
|
||||||
@@ -40,6 +44,7 @@
|
|||||||
"@angular/cli": "^20.0.2",
|
"@angular/cli": "^20.0.2",
|
||||||
"@angular/compiler-cli": "^20.0.0",
|
"@angular/compiler-cli": "^20.0.0",
|
||||||
"@types/express": "^5.0.1",
|
"@types/express": "^5.0.1",
|
||||||
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/jasmine": "~5.1.0",
|
"@types/jasmine": "~5.1.0",
|
||||||
"@types/node": "^20.17.19",
|
"@types/node": "^20.17.19",
|
||||||
"jasmine-core": "~5.7.0",
|
"jasmine-core": "~5.7.0",
|
||||||
@@ -2683,6 +2688,126 @@
|
|||||||
"node": ">=0.1.90"
|
"node": ">=0.1.90"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@cropper/element": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element/-/element-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-Jn1hR7XWzWQM/QfXRGMGzdkJ2gG/UcLdQPZQ7OKs0JiFfRzKpzu4u/nYrXHeH3MM2iOslLqh2kqYju6mjZLMJQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/utils": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-canvas": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-canvas/-/element-canvas-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-OKxq/O0HL9W2JegOsc2zh1NRpERZcLM5+M8aQ/eXdmMcfi1lzosPftag3Irp6pTsVpwV6B6ypIxKESzJ4ci9Fw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.0.1",
|
||||||
|
"@cropper/utils": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-crosshair": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-crosshair/-/element-crosshair-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-bS5msU9cTU/jf1/kDw+QJmEM9/rw8IgOdpolR85iMVUCR8sRcLa0wgom42MBHcpBYB6hvL5YfiOeXZ7lHIYMpw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.0.1",
|
||||||
|
"@cropper/utils": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-grid": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-grid/-/element-grid-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-ayqCvYQJ+GVT31HhFpttzHabW1T/LsIwLJY5PLTMG0cEZLw/E8ihg8mxctjZbo852D7oEePbz6/2SeuCb1018Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.0.1",
|
||||||
|
"@cropper/utils": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-handle": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-handle/-/element-handle-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-fdifyyPIaR9S2eQ7qPHuM8fX8uToAfBsi8vQlR9EM+oJkDNil0uO4rWyArLWEtlr0/q7U0OvsufcuJ7ffqfmpg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.0.1",
|
||||||
|
"@cropper/utils": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-image": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-image/-/element-image-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-gPj5Sl2T8Cno198Cz3F3TDfcYoALW3yJ3fV6PHXmhMnX8sBkL7J441do7Vwkg0mEd2CogCtTLAf+p7ljdV0kgA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.0.1",
|
||||||
|
"@cropper/element-canvas": "^2.0.1",
|
||||||
|
"@cropper/utils": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-selection": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-selection/-/element-selection-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-atv+Aeq2N2eWawelIRPGh1kYFdNrpb0QkUPPheGxz1ImfxpLdcHO9gb9T5noQijizUW2G0pNvts4ZaITQ0I71Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.0.1",
|
||||||
|
"@cropper/element-canvas": "^2.0.1",
|
||||||
|
"@cropper/element-image": "^2.0.1",
|
||||||
|
"@cropper/utils": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-shade": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-shade/-/element-shade-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-YIYgJ690NdFQ6wJLRFh/EySNVxGFKArncQ4FrsJ3yHU+ShgtOKz4FpjFLpqJRJB9swoVbD3WKTimGyzXrwjZrQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.0.1",
|
||||||
|
"@cropper/element-canvas": "^2.0.1",
|
||||||
|
"@cropper/element-selection": "^2.0.1",
|
||||||
|
"@cropper/utils": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-viewer": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-viewer/-/element-viewer-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-HDj25l08pWi/AO6El/OqfQHBpBC4Lh5NEnQN1SOldsmxEwt27Ubv6ndDsF8LkTK7XPwjjZRpyQPyfig4w8L2JQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.0.1",
|
||||||
|
"@cropper/element-canvas": "^2.0.1",
|
||||||
|
"@cropper/element-image": "^2.0.1",
|
||||||
|
"@cropper/element-selection": "^2.0.1",
|
||||||
|
"@cropper/utils": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/elements": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/elements/-/elements-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-paFbBLXTKXNngn1yDi2ZIf+FO1pIEQXyBntmqOjuxqtG73KuEKv633wsJPFpj958bgcfSakgBbF80j+3nHbPug==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.0.1",
|
||||||
|
"@cropper/element-canvas": "^2.0.1",
|
||||||
|
"@cropper/element-crosshair": "^2.0.1",
|
||||||
|
"@cropper/element-grid": "^2.0.1",
|
||||||
|
"@cropper/element-handle": "^2.0.1",
|
||||||
|
"@cropper/element-image": "^2.0.1",
|
||||||
|
"@cropper/element-selection": "^2.0.1",
|
||||||
|
"@cropper/element-shade": "^2.0.1",
|
||||||
|
"@cropper/element-viewer": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/utils": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/utils/-/utils-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-A9RnAFmgNF5aZk5q2VZnFnHtXWu1kPyEN0LVsX8wJ2LBRu2nyETKwz+ZXVsVWliktToCaYojHKrS+6/HODyEZA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@discoveryjs/json-ext": {
|
"node_modules/@discoveryjs/json-ext": {
|
||||||
"version": "0.6.3",
|
"version": "0.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz",
|
||||||
@@ -5822,6 +5947,13 @@
|
|||||||
"@types/send": "*"
|
"@types/send": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/file-saver": {
|
||||||
|
"version": "2.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.7.tgz",
|
||||||
|
"integrity": "sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/geojson": {
|
"node_modules/@types/geojson": {
|
||||||
"version": "7946.0.16",
|
"version": "7946.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
|
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
|
||||||
@@ -6286,6 +6418,27 @@
|
|||||||
"ajv": "^8.8.2"
|
"ajv": "^8.8.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/angular-markdown-editor": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/angular-markdown-editor/-/angular-markdown-editor-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-0Ho8HZaR95guBwZHDPw9k4Ac2zKW4hr1kl676uaoBsMZ82YHcl3VNb2TTwwui5qtcUWYmdXA++2DmZInj2GIlA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"bootstrap": ">=4.6.2",
|
||||||
|
"bootstrap-markdown": "github:refactory-id/bootstrap-markdown",
|
||||||
|
"font-awesome": "^4.7.0",
|
||||||
|
"jquery": "^3.7.0",
|
||||||
|
"tslib": "^2.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17.0",
|
||||||
|
"npm": ">=6.14.13"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "ko_fi",
|
||||||
|
"url": "https://ko-fi.com/ghiscoding"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ansi-colors": {
|
"node_modules/ansi-colors": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
|
||||||
@@ -6623,6 +6776,11 @@
|
|||||||
"@popperjs/core": "^2.11.8"
|
"@popperjs/core": "^2.11.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bootstrap-markdown": {
|
||||||
|
"version": "2.10.0",
|
||||||
|
"resolved": "git+ssh://git@github.com/refactory-id/bootstrap-markdown.git#a496d34b9bd34451c8315a850472f794c8df7d53",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.12",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||||
@@ -7558,6 +7716,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cropperjs": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-hiJwk2SCPZqxMA7aR3byzLpYUqOrQo+ihMk8k/WRm/xe/LX8wNzAIzMwEB/NEGJYA6sbewxW9TUlrRUYi/2Ipg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/elements": "^2.0.1",
|
||||||
|
"@cropper/utils": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||||
@@ -9091,6 +9259,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/file-saver": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
@@ -9176,6 +9350,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/font-awesome": {
|
||||||
|
"version": "4.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz",
|
||||||
|
"integrity": "sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==",
|
||||||
|
"license": "(OFL-1.1 AND MIT)",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/foreground-child": {
|
"node_modules/foreground-child": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
|
||||||
@@ -10307,6 +10490,12 @@
|
|||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jquery": {
|
||||||
|
"version": "3.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
|
||||||
|
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/js-tokens": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
@@ -12015,6 +12204,19 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/ngx-filesaver": {
|
||||||
|
"version": "20.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ngx-filesaver/-/ngx-filesaver-20.0.0.tgz",
|
||||||
|
"integrity": "sha512-84vRFGko1BmpyerAmLLggjx5ZiHvaWadJKlb2n0hOZlnzlTNZeI3zHKY9vqtIRkxCX70vWHTB8JwV5VvvkB2uQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/file-saver": "^2.0.0",
|
||||||
|
"file-saver": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ngx-markdown": {
|
"node_modules/ngx-markdown": {
|
||||||
"version": "20.0.0",
|
"version": "20.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-20.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-20.0.0.tgz",
|
||||||
|
|||||||
@@ -29,8 +29,12 @@
|
|||||||
"@ng-bootstrap/ng-bootstrap": "19.0.0",
|
"@ng-bootstrap/ng-bootstrap": "19.0.0",
|
||||||
"@popperjs/core": "2.11.8",
|
"@popperjs/core": "2.11.8",
|
||||||
"@primeng/themes": "^19.1.3",
|
"@primeng/themes": "^19.1.3",
|
||||||
|
"angular-markdown-editor": "^3.1.1",
|
||||||
"bootstrap": "5.3.6",
|
"bootstrap": "5.3.6",
|
||||||
|
"cropperjs": "^2.0.1",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
|
"ngx-filesaver": "^20.0.0",
|
||||||
"ngx-markdown": "^20.0.0",
|
"ngx-markdown": "^20.0.0",
|
||||||
"ngx-scrollbar": "18.0.0",
|
"ngx-scrollbar": "18.0.0",
|
||||||
"primeng": "^19.1.3",
|
"primeng": "^19.1.3",
|
||||||
@@ -45,6 +49,7 @@
|
|||||||
"@angular/cli": "^20.0.2",
|
"@angular/cli": "^20.0.2",
|
||||||
"@angular/compiler-cli": "^20.0.0",
|
"@angular/compiler-cli": "^20.0.0",
|
||||||
"@types/express": "^5.0.1",
|
"@types/express": "^5.0.1",
|
||||||
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/jasmine": "~5.1.0",
|
"@types/jasmine": "~5.1.0",
|
||||||
"@types/node": "^20.17.19",
|
"@types/node": "^20.17.19",
|
||||||
"jasmine-core": "~5.7.0",
|
"jasmine-core": "~5.7.0",
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
|
|
||||||
import { provideServerRendering, withRoutes } from '@angular/ssr';
|
|
||||||
import { appConfig } from './app.config';
|
|
||||||
import { serverRoutes } from './app.routes.server';
|
|
||||||
|
|
||||||
const serverConfig: ApplicationConfig = {
|
|
||||||
providers: [
|
|
||||||
provideServerRendering(withRoutes(serverRoutes))
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
export const config = mergeApplicationConfig(appConfig, serverConfig);
|
|
||||||
@@ -14,10 +14,6 @@ import Aura from '@primeng/themes/aura';
|
|||||||
import {provideAnimations} from '@angular/platform-browser/animations';
|
import {provideAnimations} from '@angular/platform-browser/animations';
|
||||||
import {provideMarkdown} from 'ngx-markdown';
|
import {provideMarkdown} from 'ngx-markdown';
|
||||||
|
|
||||||
import 'prismjs';
|
|
||||||
import 'prismjs/components/prism-typescript.min.js';
|
|
||||||
import 'prismjs/plugins/line-numbers/prism-line-numbers.js';
|
|
||||||
import 'prismjs/plugins/line-highlight/prism-line-highlight.js';
|
|
||||||
import {authInterceptorProviders} from './helpers/auth.interceptor';
|
import {authInterceptorProviders} from './helpers/auth.interceptor';
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
<app-spinner></app-spinner>
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
|
|||||||
@@ -7,15 +7,16 @@ import { BrowserAnimationsModule }
|
|||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import {HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi} from '@angular/common/http';
|
import {HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi} from '@angular/common/http';
|
||||||
|
|
||||||
import {MainComponent} from './main-module/main.component/main.component';
|
import {MainComponent} from './modules/main-module/main.component/main.component';
|
||||||
import {authInterceptorProviders} from './helpers/auth.interceptor';
|
import {authInterceptorProviders} from './helpers/auth.interceptor';
|
||||||
import {AdminComponent} from './admin-module/admin.component/admin.component';
|
import {AdminComponent} from './modules/admin-module/admin.component/admin.component';
|
||||||
import {AdminWelcomeComponent} from './admin-module/admin-welcome.component/admin-welcome.component';
|
import {AdminWelcomeComponent} from './modules/admin-module/admin-welcome.component/admin-welcome.component';
|
||||||
import {SettingsComponent} from './admin-module/settings.component/settings.component';
|
import {SettingsComponent} from './modules/admin-module/settings.component/settings.component';
|
||||||
import {SystemComponent} from './admin-module/system.component/system.component';
|
import {SystemComponent} from './modules/admin-module/system.component/system.component';
|
||||||
import {AppRoutingModule} from './app.routes';
|
import {AppRoutingModule} from './app.routes';
|
||||||
import {App} from './app';
|
import {App} from './app';
|
||||||
import {CustomHttpInterceptor} from './helpers/custom-http-interceptor';
|
import {CustomHttpInterceptor} from './helpers/custom-http-interceptor';
|
||||||
|
import {AngularMarkdownEditorModule} from 'angular-markdown-editor';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -32,7 +33,7 @@ import {CustomHttpInterceptor} from './helpers/custom-http-interceptor';
|
|||||||
AdminWelcomeComponent,
|
AdminWelcomeComponent,
|
||||||
SettingsComponent,
|
SettingsComponent,
|
||||||
SystemComponent,
|
SystemComponent,
|
||||||
|
AngularMarkdownEditorModule.forRoot({ iconlibrary: 'fa' })
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
authInterceptorProviders,provideHttpClient(withInterceptorsFromDi()),{
|
authInterceptorProviders,provideHttpClient(withInterceptorsFromDi()),{
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
import { RenderMode, ServerRoute } from '@angular/ssr';
|
|
||||||
|
|
||||||
export const serverRoutes: ServerRoute[] = [
|
|
||||||
{
|
|
||||||
path: '**',
|
|
||||||
renderMode: RenderMode.Prerender
|
|
||||||
}
|
|
||||||
];
|
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
import {RouterModule, Routes} from '@angular/router';
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
|
import {environment} from '../environments/environment';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
redirectTo: 'main/generate-image',
|
redirectTo: environment.default_page,
|
||||||
pathMatch: 'full'
|
pathMatch: 'full'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'main',
|
path: 'main',
|
||||||
loadChildren: () =>
|
loadChildren: () =>
|
||||||
import('./main-module/main.module').then((m) => m.MainModule),
|
import('./modules/main-module/main.module').then((m) => m.MainModule),
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import { Component } from '@angular/core';
|
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
|
import {SpinnerComponent} from './components/spinner/spinner.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: './app.html',
|
templateUrl: './app.html',
|
||||||
imports: [
|
imports: [
|
||||||
RouterOutlet
|
RouterOutlet,
|
||||||
|
SpinnerComponent
|
||||||
],
|
],
|
||||||
styleUrl: './app.scss'
|
styleUrl: './app.scss',
|
||||||
|
schemas:[CUSTOM_ELEMENTS_SCHEMA]
|
||||||
})
|
})
|
||||||
export class App {
|
export class App {
|
||||||
protected title = 'jambotron-ui';
|
protected title = 'jambotron-ui';
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
import {ChangeDetectionStrategy, Component, EventEmitter, Inject, inject, Output, signal} from '@angular/core';
|
|
||||||
import {MatButtonModule} from "@angular/material/button";
|
|
||||||
import {
|
|
||||||
MAT_DIALOG_DATA,
|
|
||||||
MatDialogActions,
|
|
||||||
MatDialogClose,
|
|
||||||
MatDialogContent,
|
|
||||||
MatDialogRef,
|
|
||||||
MatDialogTitle
|
|
||||||
} from "@angular/material/dialog";
|
|
||||||
|
|
||||||
|
|
||||||
import {MatFormField, MatLabel, MatSuffix} from "@angular/material/form-field";
|
|
||||||
import {MatInput} from "@angular/material/input";
|
|
||||||
import {FormsModule} from "@angular/forms";
|
|
||||||
import {MatIcon} from "@angular/material/icon";
|
|
||||||
import {DialogLoginData} from '../../main-module/main.component/main.component';
|
|
||||||
import {MatSnackBar} from '@angular/material/snack-bar';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-dialog',
|
|
||||||
imports: [MatButtonModule, MatLabel, MatDialogActions, MatDialogClose, MatDialogTitle, MatDialogContent, MatFormField, MatInput, FormsModule, MatIcon, MatSuffix],
|
|
||||||
|
|
||||||
templateUrl: './dialog.component.html',
|
|
||||||
styleUrl: './dialog.component.scss',
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
|
||||||
})
|
|
||||||
export class DialogComponent {
|
|
||||||
readonly dialogRef = inject(MatDialogRef<DialogComponent>);
|
|
||||||
hide = signal(true);
|
|
||||||
|
|
||||||
@Output() loginClicked = new EventEmitter<any>();
|
|
||||||
@Output() signupClicked = new EventEmitter<any>();
|
|
||||||
|
|
||||||
private _snackBar = inject(MatSnackBar);
|
|
||||||
durationInSeconds = 5;
|
|
||||||
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
@Inject(MAT_DIALOG_DATA) public data:DialogLoginData) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
openLoginFailedSnackBar(errorMessage : string = "Login failed.") {
|
|
||||||
this._snackBar.open(errorMessage , "", {
|
|
||||||
duration: this.durationInSeconds * 1000,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onNoClick() {
|
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
clickEvent(event: MouseEvent) {
|
|
||||||
this.hide.set(!this.hide());
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
login() {
|
|
||||||
this.loginClicked.emit(this.data);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
signup() {
|
|
||||||
this.signupClicked.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+1
-13
@@ -5,7 +5,7 @@ import {MatCard, MatCardActions, MatCardContent, MatCardHeader} from '@angular/m
|
|||||||
import {MatFormField, MatInput, MatLabel} from '@angular/material/input';
|
import {MatFormField, MatInput, MatLabel} from '@angular/material/input';
|
||||||
import {AsyncPipe} from '@angular/common';
|
import {AsyncPipe} from '@angular/common';
|
||||||
import {Image} from '../../models/image';
|
import {Image} from '../../models/image';
|
||||||
import {ZhipuaiImageService} from '../../services/zhipuai-image.service';
|
import {ZhipuaiImageService} from '../../modules/ai-module/zhipuai-image.service';
|
||||||
import {MatProgressSpinner} from '@angular/material/progress-spinner';
|
import {MatProgressSpinner} from '@angular/material/progress-spinner';
|
||||||
import {SpinnerService} from '../../services/spinner.service';
|
import {SpinnerService} from '../../services/spinner.service';
|
||||||
|
|
||||||
@@ -50,11 +50,6 @@ export class GenerateImageComponent implements OnInit {
|
|||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
||||||
const img = this.renderer.selectRootElement('img');
|
|
||||||
this.viewer = new Viewer(img, {
|
|
||||||
inline: true,
|
|
||||||
});
|
|
||||||
this.viewer.zoomTo(1);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,11 +72,4 @@ export class GenerateImageComponent implements OnInit {
|
|||||||
this.viewer.update();
|
this.viewer.update();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomPlus(){
|
|
||||||
this.viewer.zoomTo(5);
|
|
||||||
}
|
|
||||||
zoomMinus(){
|
|
||||||
this.viewer.zoomTo(-5);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
<p>dfsdgdsgsdg</p>
|
|
||||||
|
|
||||||
<p>dfsdgdsgsdg</p>
|
|
||||||
<p>dfsdgdsgsdg</p>
|
|
||||||
<p>dfsdgdsgsdg</p>
|
|
||||||
<p>dfsdgdsgsdg</p>
|
|
||||||
<p>dfsdgdsgsdg</p><p>dfsdgdsgsdg</p>
|
|
||||||
<p>dfsdgdsgsdg</p>
|
|
||||||
<p>dfsdgdsgsdg</p>
|
|
||||||
<p>dfsdgdsgsdg</p>
|
|
||||||
<p>dfsdgdsgsdg</p>
|
|
||||||
<p>dfsdgdsgsdg</p><p>dfsdgdsgsdg</p>
|
|
||||||
<p>dfsdgdsgsdg</p>
|
|
||||||
<p>dfsdgdsgsdg</p>
|
|
||||||
<p>dfsdgdsgsdg</p>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<mat-card appearance="outlined">
|
|
||||||
<mat-card-header>
|
|
||||||
<mat-card-title>Add tutorial</mat-card-title>
|
|
||||||
</mat-card-header>
|
|
||||||
<mat-card-content *ngIf="!submitted">
|
|
||||||
<mat-form-field class="example-full-width">
|
|
||||||
<mat-label>Title</mat-label>
|
|
||||||
<input matInput [(ngModel)]="query">
|
|
||||||
</mat-form-field>
|
|
||||||
<!– <kendo-editor [(ngModel)]="tutorial.description" ></kendo-editor>–>
|
|
||||||
|
|
||||||
</mat-card-content>
|
|
||||||
<mat-card-actions>
|
|
||||||
<button matButton (click)="generateImage()" >Save</button>
|
|
||||||
<div>
|
|
||||||
<h4>Tutorial was submitted successfully!</h4>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</mat-card-actions>
|
|
||||||
</mat-card>
|
|
||||||
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<angular-image-viewer [src]="images" [(config)]="config" [(index)]="imageIndexOne"
|
|
||||||
[screenHeightOccupied]='0' (customImageEvent)="handleEvent($event)" >
|
|
||||||
</angular-image-viewer>
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
|
||||||
import {MatFormField, MatInput, MatLabel} from '@angular/material/input';
|
|
||||||
import {AngularImageViewerModule, CustomImageEvent, ImageViewerConfig} from '@hreimer/angular-image-viewer';
|
|
||||||
|
|
||||||
import {ZhipuaiImageService} from '../../services/zhipuai-image.service';
|
|
||||||
import {MatButton} from '@angular/material/button';
|
|
||||||
|
|
||||||
|
|
||||||
import {FormsModule} from '@angular/forms';
|
|
||||||
import {CommonModule} from '@angular/common';
|
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
|
||||||
import {MatCard, MatCardActions, MatCardContent, MatCardHeader} from '@angular/material/card';
|
|
||||||
import {Image} from '../../models/image';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-home.component',
|
|
||||||
imports: [
|
|
||||||
|
|
||||||
AngularImageViewerModule,
|
|
||||||
FormsModule
|
|
||||||
],
|
|
||||||
templateUrl: './home.component.html',
|
|
||||||
styleUrl: './home.component.scss',
|
|
||||||
schemas :[CUSTOM_ELEMENTS_SCHEMA]
|
|
||||||
})
|
|
||||||
|
|
||||||
export class HomeComponent {
|
|
||||||
|
|
||||||
query : string = '';
|
|
||||||
|
|
||||||
images = [];
|
|
||||||
image: Image = {
|
|
||||||
url: ''
|
|
||||||
};
|
|
||||||
imageIndexOne = 0;
|
|
||||||
|
|
||||||
config: ImageViewerConfig = { customBtns: [{ name: 'print', icon: {
|
|
||||||
classes: 'fas fa-paperclip',
|
|
||||||
text: 'link'
|
|
||||||
} }, { name: 'link', icon: {
|
|
||||||
classes: 'fas fa-paperclip',
|
|
||||||
text: 'link'
|
|
||||||
} }] };
|
|
||||||
|
|
||||||
submitted: boolean = false;
|
|
||||||
|
|
||||||
constructor(private zhipuaiImageService: ZhipuaiImageService) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEvent(event: CustomImageEvent) {
|
|
||||||
console.log(`${event.name} has been click on img ${event.imageIndex + 1}`);
|
|
||||||
|
|
||||||
switch (event.name) {
|
|
||||||
case 'print':
|
|
||||||
console.log('run print logic');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
generateImage(){
|
|
||||||
this.zhipuaiImageService.generate(this.query).subscribe(
|
|
||||||
data => {
|
|
||||||
this.image = data;
|
|
||||||
// @ts-ignore
|
|
||||||
this.images = [this.image.url];
|
|
||||||
|
|
||||||
|
|
||||||
console.log(data);
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
<div class="col-md-12">
|
|
||||||
<div class="card card-container">
|
|
||||||
<img
|
|
||||||
id="profile-img"
|
|
||||||
src="//ssl.gstatic.com/accounts/ui/avatar_2x.png"
|
|
||||||
class="profile-img-card"
|
|
||||||
/>
|
|
||||||
<form
|
|
||||||
*ngIf="!isLoggedIn"
|
|
||||||
name="form"
|
|
||||||
(ngSubmit)="f.form.valid && onSubmit()"
|
|
||||||
#f="ngForm"
|
|
||||||
novalidate
|
|
||||||
>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="username">Username</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="form-control"
|
|
||||||
id="username"
|
|
||||||
[(ngModel)]="form.username"
|
|
||||||
required
|
|
||||||
#username="ngModel"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
class="alert alert-danger"
|
|
||||||
role="alert"
|
|
||||||
*ngIf="username.errors && f.submitted"
|
|
||||||
>
|
|
||||||
Username is required!
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="password">Password</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
class="form-control"
|
|
||||||
id="password"
|
|
||||||
[(ngModel)]="form.password"
|
|
||||||
required
|
|
||||||
minlength="6"
|
|
||||||
#password="ngModel"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
class="alert alert-danger"
|
|
||||||
role="alert"
|
|
||||||
*ngIf="password.errors && f.submitted"
|
|
||||||
>
|
|
||||||
<div *ngIf="password.errors['required']">Password is required</div>
|
|
||||||
<div *ngIf="password.errors['minlength']">
|
|
||||||
Password must be at least 6 characters
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<button class="btn btn-primary btn-block">
|
|
||||||
Login
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div
|
|
||||||
class="alert alert-danger"
|
|
||||||
role="alert"
|
|
||||||
*ngIf="f.submitted && isLoginFailed"
|
|
||||||
>
|
|
||||||
Login failed: {{ errorMessage }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="alert alert-success" *ngIf="isLoggedIn">
|
|
||||||
Logged in as {{ roles }}.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
|
|
||||||
import {FormsModule} from "@angular/forms";
|
|
||||||
import {NgIf} from "@angular/common";
|
|
||||||
import {AuthService} from '../../services/auth.service';
|
|
||||||
import {TokenStorageService} from '../../services/token-storage.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-login',
|
|
||||||
templateUrl: './login.component.html',
|
|
||||||
imports: [
|
|
||||||
FormsModule,
|
|
||||||
NgIf
|
|
||||||
],
|
|
||||||
styleUrls: ['./login.component.scss']
|
|
||||||
})
|
|
||||||
export class LoginComponent implements OnInit {
|
|
||||||
|
|
||||||
form: any = {
|
|
||||||
username: null,
|
|
||||||
password: null
|
|
||||||
};
|
|
||||||
isLoggedIn = false;
|
|
||||||
isLoginFailed = false;
|
|
||||||
errorMessage = '';
|
|
||||||
roles: string[] = [];
|
|
||||||
|
|
||||||
constructor(private authService: AuthService, private tokenStorage: TokenStorageService) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
if (this.tokenStorage.getToken()) {
|
|
||||||
this.isLoggedIn = true;
|
|
||||||
this.roles = this.tokenStorage.getUser().roles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit(): void {
|
|
||||||
const { username, password } = this.form;
|
|
||||||
|
|
||||||
this.authService.login(username, password).subscribe(
|
|
||||||
data => {
|
|
||||||
this.tokenStorage.saveToken(data.accessToken);
|
|
||||||
this.tokenStorage.saveUser(data);
|
|
||||||
|
|
||||||
this.isLoginFailed = false;
|
|
||||||
this.isLoggedIn = true;
|
|
||||||
this.roles = this.tokenStorage.getUser().roles;
|
|
||||||
this.reloadPage();
|
|
||||||
},
|
|
||||||
err => {
|
|
||||||
this.errorMessage = err.error.message;
|
|
||||||
this.isLoginFailed = true;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
reloadPage(): void {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<div class="container" *ngIf="currentUser; else loggedOut">
|
|
||||||
<header class="jumbotron">
|
|
||||||
<h3>
|
|
||||||
<strong>{{ currentUser.username }}</strong> Profile
|
|
||||||
</h3>
|
|
||||||
</header>
|
|
||||||
<p>
|
|
||||||
<strong>Token:</strong>
|
|
||||||
{{ currentUser.accessToken.substring(0, 20) }} ...
|
|
||||||
{{ currentUser.accessToken.substr(currentUser.accessToken.length - 20) }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Email:</strong>
|
|
||||||
{{ currentUser.email }}
|
|
||||||
</p>
|
|
||||||
<strong>Roles:</strong>
|
|
||||||
<ul>
|
|
||||||
<li *ngFor="let role of currentUser.roles">
|
|
||||||
{{ role }}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ng-template #loggedOut>
|
|
||||||
Please login.
|
|
||||||
</ng-template>
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import {TokenStorageService} from '../../services/token-storage.service';
|
|
||||||
import {NgForOf, NgIf} from '@angular/common';
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-profile',
|
|
||||||
templateUrl: './profile.component.html',
|
|
||||||
imports: [
|
|
||||||
NgForOf,
|
|
||||||
NgIf
|
|
||||||
],
|
|
||||||
styleUrls: ['./profile.component.scss']
|
|
||||||
})
|
|
||||||
export class ProfileComponent implements OnInit {
|
|
||||||
currentUser: any;
|
|
||||||
|
|
||||||
constructor(private token: TokenStorageService) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.currentUser = this.token.getUser();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
<div class="col-md-12">
|
|
||||||
<div id="register">
|
|
||||||
<img id="foto"
|
|
||||||
id="profile-img"
|
|
||||||
src="//ssl.gstatic.com/accounts/ui/avatar_2x.png"
|
|
||||||
class="profile-img-card"
|
|
||||||
/>
|
|
||||||
<form
|
|
||||||
*ngIf="!isSuccessful"
|
|
||||||
name="form"
|
|
||||||
(ngSubmit)="f.form.valid && onSubmit()"
|
|
||||||
#f="ngForm"
|
|
||||||
novalidate
|
|
||||||
>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="username">Username</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="form-control"
|
|
||||||
id="username"
|
|
||||||
[(ngModel)]="form.username"
|
|
||||||
[ngModelOptions]="{standalone: true}"
|
|
||||||
required
|
|
||||||
minlength="3"
|
|
||||||
maxlength="20"
|
|
||||||
#username="ngModel"
|
|
||||||
/>
|
|
||||||
<div class="alert-danger" *ngIf="username.errors && f.submitted">
|
|
||||||
<div *ngIf="username.errors['required']">Username is required</div>
|
|
||||||
<div *ngIf="username.errors['minlength']">
|
|
||||||
Username must be at least 3 characters
|
|
||||||
</div>
|
|
||||||
<div *ngIf="username.errors['maxlength']">
|
|
||||||
Username must be at most 20 characters
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="email">Email</label>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
class="form-control"
|
|
||||||
id="email"
|
|
||||||
[(ngModel)]="form.email"
|
|
||||||
[ngModelOptions]="{standalone: true}"
|
|
||||||
required
|
|
||||||
email
|
|
||||||
#email="ngModel"
|
|
||||||
/>
|
|
||||||
<div class="alert-danger" *ngIf="email.errors && f.submitted">
|
|
||||||
<div *ngIf="email.errors['required']">Email is required</div>
|
|
||||||
<div *ngIf="email.errors['email']">
|
|
||||||
Email must be a valid email address
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="password">Password</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
class="form-control"
|
|
||||||
id="password"
|
|
||||||
[(ngModel)]="form.password"
|
|
||||||
[ngModelOptions]="{standalone: true}"
|
|
||||||
required
|
|
||||||
minlength="6"
|
|
||||||
#password="ngModel"
|
|
||||||
/>
|
|
||||||
<div class="alert-danger" *ngIf="password.errors && f.submitted">
|
|
||||||
<div *ngIf="password.errors['required']">Password is required</div>
|
|
||||||
<div *ngIf="password.errors['minlength']">
|
|
||||||
Password must be at least 6 characters
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<button class="btn btn-primary btn-block">Sign Up</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="alert alert-warning" *ngIf="f.submitted && isSignUpFailed">
|
|
||||||
Signup failed!<br />{{ errorMessage }}
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="alert alert-success" *ngIf="isSuccessful">
|
|
||||||
Your registration is successful!
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { RegisterComponent } from './register.component';
|
|
||||||
|
|
||||||
describe('RegisterComponent', () => {
|
|
||||||
let component: RegisterComponent;
|
|
||||||
let fixture: ComponentFixture<RegisterComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ RegisterComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(RegisterComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import {AuthService} from '../../services/auth.service';
|
|
||||||
import {FormsModule} from '@angular/forms';
|
|
||||||
import {NgIf} from '@angular/common';
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-register',
|
|
||||||
templateUrl: './register.component.html',
|
|
||||||
imports: [
|
|
||||||
FormsModule,
|
|
||||||
NgIf
|
|
||||||
],
|
|
||||||
styleUrls: ['./register.component.scss']
|
|
||||||
})
|
|
||||||
export class RegisterComponent implements OnInit {
|
|
||||||
form: any = {
|
|
||||||
username: null,
|
|
||||||
email: null,
|
|
||||||
password: null
|
|
||||||
};
|
|
||||||
isSuccessful = false;
|
|
||||||
isSignUpFailed = false;
|
|
||||||
errorMessage = '';
|
|
||||||
|
|
||||||
constructor(private authService: AuthService) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit(): void {
|
|
||||||
const { username, email, password } = this.form;
|
|
||||||
|
|
||||||
this.authService.register(username, email, password).subscribe(
|
|
||||||
data => {
|
|
||||||
console.log(data);
|
|
||||||
this.isSuccessful = true;
|
|
||||||
this.isSignUpFailed = false;
|
|
||||||
},
|
|
||||||
err => {
|
|
||||||
this.errorMessage = err.error.message;
|
|
||||||
this.isSignUpFailed = true;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||||
import {Tutorial} from '../../models/tutorial.model';
|
import {Tutorial} from '../../models/tutorial.model';
|
||||||
import {TutorialService} from '../../services/tutorial.service';
|
|
||||||
import {MatCard, MatCardContent, MatCardHeader} from '@angular/material/card';
|
import {MatCard, MatCardContent, MatCardHeader} from '@angular/material/card';
|
||||||
import {MarkdownComponent} from 'ngx-markdown';
|
import {MarkdownComponent} from 'ngx-markdown';
|
||||||
import {authInterceptorProviders} from '../../helpers/auth.interceptor';
|
import {authInterceptorProviders} from '../../helpers/auth.interceptor';
|
||||||
@@ -26,9 +26,9 @@ import {CustomHttpInterceptor} from '../../helpers/custom-http-interceptor';
|
|||||||
})
|
})
|
||||||
export class TutorialsComponent {
|
export class TutorialsComponent {
|
||||||
tutorials?: Tutorial[];
|
tutorials?: Tutorial[];
|
||||||
|
/*
|
||||||
constructor(private tutorialService: TutorialService) {
|
constructor(private tutorialService: TutorialService) {
|
||||||
this.retrieveTutorials();
|
// this.retrieveTutorials();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ngOnInit(): void {
|
// ngOnInit(): void {
|
||||||
@@ -45,5 +45,5 @@ export class TutorialsComponent {
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
import { ColumnResizeDirective } from './column-resize.directive';
|
|
||||||
|
|
||||||
describe('ColumnResizeDirective', () => {
|
|
||||||
it('should create an instance', () => {
|
|
||||||
const directive = new ColumnResizeDirective();
|
|
||||||
expect(directive).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
import {
|
|
||||||
Directive,
|
|
||||||
ElementRef,
|
|
||||||
OnDestroy,
|
|
||||||
OnInit,
|
|
||||||
Renderer2,
|
|
||||||
NgZone,
|
|
||||||
Input,
|
|
||||||
} from '@angular/core';
|
|
||||||
import { Subject, fromEvent, takeUntil } from 'rxjs';
|
|
||||||
|
|
||||||
@Directive({
|
|
||||||
selector: '[appColumnResize]',
|
|
||||||
})
|
|
||||||
export class ColumnResizeDirective implements OnInit, OnDestroy {
|
|
||||||
@Input() resizableTable: HTMLElement | null = null;
|
|
||||||
|
|
||||||
private isResizing = false;
|
|
||||||
private startX!: number;
|
|
||||||
private startWidth!: number;
|
|
||||||
private column: HTMLElement;
|
|
||||||
private table: HTMLElement | null = null;
|
|
||||||
private resizer!: HTMLElement;
|
|
||||||
private destroy$ = new Subject<void>();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private el: ElementRef,
|
|
||||||
private renderer: Renderer2,
|
|
||||||
private zone: NgZone
|
|
||||||
) {
|
|
||||||
this.column = this.el.nativeElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.table = this.resizableTable || this.findParentTable(this.column);
|
|
||||||
|
|
||||||
if (!this.table) {
|
|
||||||
console.error(
|
|
||||||
'Parent table not found. Make sure the directive is applied to a th element within a table.'
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.createResizer();
|
|
||||||
this.initializeResizeListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
private createResizer() {
|
|
||||||
this.resizer = this.renderer.createElement('div');
|
|
||||||
this.renderer.addClass(this.resizer, 'column-resizer');
|
|
||||||
this.renderer.setStyle(this.resizer, 'position', 'absolute');
|
|
||||||
this.renderer.setStyle(this.resizer, 'right', '0');
|
|
||||||
this.renderer.setStyle(this.resizer, 'top', '0');
|
|
||||||
this.renderer.setStyle(this.resizer, 'height', '100%');
|
|
||||||
this.renderer.setStyle(this.resizer, 'width', '5px');
|
|
||||||
this.renderer.setStyle(this.resizer, 'cursor', 'col-resize');
|
|
||||||
this.renderer.appendChild(this.column, this.resizer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private initializeResizeListener() {
|
|
||||||
this.zone.runOutsideAngular(() => {
|
|
||||||
fromEvent(this.resizer, 'mousedown')
|
|
||||||
.pipe(takeUntil(this.destroy$))
|
|
||||||
.subscribe((e: Event) => this.onMouseDown(e as MouseEvent));
|
|
||||||
|
|
||||||
fromEvent(document, 'mousemove')
|
|
||||||
.pipe(takeUntil(this.destroy$))
|
|
||||||
.subscribe((e: Event) => this.onMouseMove(e as MouseEvent));
|
|
||||||
|
|
||||||
fromEvent(document, 'mouseup')
|
|
||||||
.pipe(takeUntil(this.destroy$))
|
|
||||||
.subscribe(() => this.onMouseUp());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private onMouseDown(e: MouseEvent) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.isResizing = true;
|
|
||||||
this.startX = e.pageX;
|
|
||||||
this.startWidth = this.column.offsetWidth;
|
|
||||||
this.renderer.addClass(this.column, 'resizing');
|
|
||||||
if (this.table) {
|
|
||||||
this.renderer.addClass(this.table, 'resizing');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private onMouseMove(e: MouseEvent) {
|
|
||||||
if (!this.isResizing) return;
|
|
||||||
const width = this.startWidth + (e.pageX - this.startX);
|
|
||||||
this.renderer.setStyle(this.column, 'width', `${width}px`);
|
|
||||||
}
|
|
||||||
|
|
||||||
private onMouseUp() {
|
|
||||||
if (!this.isResizing) return;
|
|
||||||
this.isResizing = false;
|
|
||||||
this.renderer.removeClass(this.column, 'resizing');
|
|
||||||
if (this.table) {
|
|
||||||
this.renderer.removeClass(this.table, 'resizing');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private findParentTable(element: HTMLElement): HTMLElement | null {
|
|
||||||
while (element && element.tagName !== 'TABLE') {
|
|
||||||
element = element.parentElement as HTMLElement;
|
|
||||||
if (!element) return null;
|
|
||||||
}
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.destroy$.next();
|
|
||||||
this.destroy$.complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,14 @@ import {environment} from '../environments/environment';
|
|||||||
|
|
||||||
export class GlobalConstants {
|
export class GlobalConstants {
|
||||||
|
|
||||||
|
public static readonly TITLE = (() => {
|
||||||
|
return environment.title;
|
||||||
|
})();
|
||||||
|
|
||||||
|
public static readonly DEFAULT_PAGE = (() => {
|
||||||
|
return environment.default_page;
|
||||||
|
})();
|
||||||
|
|
||||||
public static readonly API_URL = (() => {
|
public static readonly API_URL = (() => {
|
||||||
// ... calculate the value and return it
|
// ... calculate the value and return it
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { FileInfo } from './file-info';
|
||||||
|
|
||||||
|
describe('FileInfo', () => {
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(new FileInfo()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export class FileInfo {
|
||||||
|
name: string | undefined;
|
||||||
|
url: string | undefined;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
export class Image {
|
export class Image {
|
||||||
|
|
||||||
url?:string;
|
url?:string;
|
||||||
b64Json?:boolean;
|
b64string?:string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ export class Tutorial {
|
|||||||
modified?: Date;
|
modified?: Date;
|
||||||
tobepublished?: boolean;
|
tobepublished?: boolean;
|
||||||
isEdit?: boolean;
|
isEdit?: boolean;
|
||||||
|
titleimage?: string;
|
||||||
|
body?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {Observable} from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
import {HttpClient} from '@angular/common/http';
|
import {HttpClient} from '@angular/common/http';
|
||||||
import {User} from '../models/user.model';
|
import {User} from '../../models/user.model';
|
||||||
import {GlobalConstants} from '../global-constants';
|
import {GlobalConstants} from '../../global-constants';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
+2
-5
@@ -11,11 +11,8 @@ import {
|
|||||||
MatHeaderRowDef,
|
MatHeaderRowDef,
|
||||||
MatRow, MatRowDef, MatTable
|
MatRow, MatRowDef, MatTable
|
||||||
} from '@angular/material/table';
|
} from '@angular/material/table';
|
||||||
import {MatIconButton} from '@angular/material/button';
|
import {SystemService} from '../../../services/system.service';
|
||||||
import {MatList, MatListItem} from '@angular/material/list';
|
import {NameValueItem} from '../../../models/name-value-item';
|
||||||
import {Bean} from '../../models/Bean';
|
|
||||||
import {SystemService} from '../../services/system.service';
|
|
||||||
import {NameValueItem} from '../../models/name-value-item';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-settings.component',
|
selector: 'app-settings.component',
|
||||||
+2
-2
@@ -14,8 +14,8 @@ import {
|
|||||||
} from '@angular/material/table';
|
} from '@angular/material/table';
|
||||||
import {MatList, MatListItem} from '@angular/material/list';
|
import {MatList, MatListItem} from '@angular/material/list';
|
||||||
import {MatIconButton} from '@angular/material/button';
|
import {MatIconButton} from '@angular/material/button';
|
||||||
import {SystemService} from '../../services/system.service';
|
import {SystemService} from '../../../services/system.service';
|
||||||
import {Bean} from '../../models/Bean';
|
import {Bean} from '../../../models/Bean';
|
||||||
import {MatIcon} from '@angular/material/icon';
|
import {MatIcon} from '@angular/material/icon';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
+4
-4
@@ -1,8 +1,8 @@
|
|||||||
import {Component, CUSTOM_ELEMENTS_SCHEMA, model} from '@angular/core';
|
import {Component, CUSTOM_ELEMENTS_SCHEMA, model} from '@angular/core';
|
||||||
import {UserService} from '../../services/user.service';
|
import {UserService} from '../../../services/user.service';
|
||||||
import {RolesService} from '../../services/roles.service';
|
import {RolesService} from '../../../services/roles.service';
|
||||||
import {Role} from '../../models/role';
|
import {Role} from '../../../models/role';
|
||||||
import {User} from '../../models/user.model';
|
import {User} from '../../../models/user.model';
|
||||||
import {
|
import {
|
||||||
MatCell,
|
MatCell,
|
||||||
MatCellDef, MatColumnDef,
|
MatCellDef, MatColumnDef,
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<router-outlet></router-outlet>
|
||||||
+6
-6
@@ -1,18 +1,18 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { HomeComponent } from './home.component';
|
import { AiMainComponent } from './ai-main.component';
|
||||||
|
|
||||||
describe('HomeComponent', () => {
|
describe('AiMainComponent', () => {
|
||||||
let component: HomeComponent;
|
let component: AiMainComponent;
|
||||||
let fixture: ComponentFixture<HomeComponent>;
|
let fixture: ComponentFixture<AiMainComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [HomeComponent]
|
imports: [AiMainComponent]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(HomeComponent);
|
fixture = TestBed.createComponent(AiMainComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import {RouterOutlet} from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ai-main.component',
|
||||||
|
imports: [
|
||||||
|
RouterOutlet
|
||||||
|
],
|
||||||
|
templateUrl: './ai-main.component.html',
|
||||||
|
styleUrl: './ai-main.component.scss'
|
||||||
|
})
|
||||||
|
export class AiMainComponent {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<p>ai-welcome.component works!</p>
|
||||||
+6
-8
@@ -1,20 +1,18 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { LoginComponent } from './login.component';
|
import { AiWelcomeComponent } from './ai-welcome.component';
|
||||||
|
|
||||||
describe('LoginComponent', () => {
|
describe('AiWelcomeComponent', () => {
|
||||||
let component: LoginComponent;
|
let component: AiWelcomeComponent;
|
||||||
let fixture: ComponentFixture<LoginComponent>;
|
let fixture: ComponentFixture<AiWelcomeComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ LoginComponent ]
|
imports: [AiWelcomeComponent]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
fixture = TestBed.createComponent(AiWelcomeComponent);
|
||||||
fixture = TestBed.createComponent(LoginComponent);
|
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ai-welcome.component',
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './ai-welcome.component.html',
|
||||||
|
styleUrl: './ai-welcome.component.scss'
|
||||||
|
})
|
||||||
|
export class AiWelcomeComponent {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
import {moderatorRouting} from '../moderator-module/moderator.routing';
|
||||||
|
import {ModeratorComponent} from '../moderator-module/moderator.component/moderator.component';
|
||||||
|
import {CommonModule} from '@angular/common';
|
||||||
|
import {AiWelcomeComponent} from './ai-welcome.component/ai-welcome.component';
|
||||||
|
import {AiMainComponent} from './ai-main.component/ai-main.component';
|
||||||
|
import {aiRouting} from './ai.routing';
|
||||||
|
|
||||||
|
import {MatDialogModule} from "@angular/material/dialog";
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [
|
||||||
|
aiRouting,
|
||||||
|
AiMainComponent,
|
||||||
|
CommonModule,
|
||||||
|
|
||||||
|
MatDialogModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AiModule { }
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
|
import {AiMainComponent} from './ai-main.component/ai-main.component';
|
||||||
|
|
||||||
|
const AI_ROUTES: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: AiMainComponent,
|
||||||
|
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'ai-welcome',
|
||||||
|
loadComponent: () => import('../ai-module/ai-welcome.component/ai-welcome.component').then((c) => c.AiWelcomeComponent),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'generate-image',
|
||||||
|
loadComponent: () => import('../ai-module/generate-image.component/generate-image.component').then((c) => c.GenerateImageComponent)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const aiRouting = RouterModule.forChild(AI_ROUTES);
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
<div class="generate-image-view">
|
||||||
|
<mat-card appearance="outlined">
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title>Generate image</mat-card-title>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-form-field class="example-full-width">
|
||||||
|
<mat-label>Query</mat-label>
|
||||||
|
<input matInput required
|
||||||
|
[(ngModel)]="query">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-card-content>
|
||||||
|
<mat-card-actions>
|
||||||
|
|
||||||
|
@if (spinnerService.visibility | async) {
|
||||||
|
<mat-spinner [diameter]="25" ></mat-spinner>
|
||||||
|
} @else {
|
||||||
|
<button matButton (click)="generateImage()" >Generate</button>
|
||||||
|
}
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
||||||
|
|
||||||
|
@for (image of images; track image) {
|
||||||
|
<mat-card>
|
||||||
|
<mat-card-header>
|
||||||
|
<div class="image-container">
|
||||||
|
<img src="{{image.url}}"
|
||||||
|
alt="" width="100%" height="100%">
|
||||||
|
<mat-toolbar class="image-toolbar">
|
||||||
|
<mat-toolbar-row>
|
||||||
|
<span class="menu-spacer"></span>
|
||||||
|
<!-- <button matMiniFab matTooltip="Dawnload image" aria-label="Download" (click)="downloadImage(image.url)">
|
||||||
|
<mat-icon>download</mat-icon>
|
||||||
|
</button>-->
|
||||||
|
@if (isLoggedIn) {
|
||||||
|
<button matMiniFab matTooltip="Save to server" aria-label="Save" (click)="save(image.url)" >
|
||||||
|
<mat-icon>upload_file</mat-icon>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</mat-toolbar-row>
|
||||||
|
</mat-toolbar>
|
||||||
|
</div>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
.generate-image-view {
|
||||||
|
margin-right: 12px;
|
||||||
|
padding: 20px 22px 18px 22px;
|
||||||
|
margin-top: 81px;
|
||||||
|
margin-left: 12px;
|
||||||
|
background-color: #e7edf3c2;
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
}
|
||||||
|
.image-container .image-toolbar
|
||||||
|
{
|
||||||
|
background-color: rgba(153,153,153,0);
|
||||||
|
|
||||||
|
color: white;
|
||||||
|
position: absolute;
|
||||||
|
left : 50%;
|
||||||
|
top: 5%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
-ms-transform: translate(-50%, -50%);
|
||||||
|
padding: 0px 2px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.image-container .menu-spacer {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container .image-file-name {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-mini-fab{
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
.example-full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { GenerateImageComponent } from './generate-image.component';
|
||||||
|
|
||||||
|
describe('GenerateImageComponent', () => {
|
||||||
|
let component: GenerateImageComponent;
|
||||||
|
let fixture: ComponentFixture<GenerateImageComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [GenerateImageComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(GenerateImageComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
+126
@@ -0,0 +1,126 @@
|
|||||||
|
import {Component, CUSTOM_ELEMENTS_SCHEMA, Inject, inject, Renderer2} from '@angular/core';
|
||||||
|
import {AsyncPipe, DOCUMENT, NgOptimizedImage} from "@angular/common";
|
||||||
|
import {FormsModule} from "@angular/forms";
|
||||||
|
import {MatButton, MatMiniFabButton} from "@angular/material/button";
|
||||||
|
import {
|
||||||
|
MatCard,
|
||||||
|
MatCardActions,
|
||||||
|
MatCardContent,
|
||||||
|
MatCardHeader,
|
||||||
|
MatCardImage,
|
||||||
|
MatCardXlImage
|
||||||
|
} from "@angular/material/card";
|
||||||
|
import {MatFormField, MatInput, MatLabel} from "@angular/material/input";
|
||||||
|
import {Image} from '../../../models/image';
|
||||||
|
import {ZhipuaiImageService} from '../zhipuai-image.service';
|
||||||
|
import {SpinnerService} from '../../../services/spinner.service';
|
||||||
|
import {MatProgressSpinner} from '@angular/material/progress-spinner';
|
||||||
|
|
||||||
|
import {FileUploadService} from '../../../services/file-upload-api.service';
|
||||||
|
import {Observable, Subscription} from 'rxjs';
|
||||||
|
import {HttpClient, HttpResponse} from '@angular/common/http';
|
||||||
|
import {MatToolbar, MatToolbarRow} from '@angular/material/toolbar';
|
||||||
|
import {MatIcon} from '@angular/material/icon';
|
||||||
|
import {MatTooltip} from '@angular/material/tooltip';
|
||||||
|
import {AuthService} from '../../../services/auth.service';
|
||||||
|
import {TokenStorageService} from '../../../services/token-storage.service';
|
||||||
|
import {FileInfo} from '../../../models/file-info';
|
||||||
|
import {UserApiService} from '../../user-module/user-api.service';
|
||||||
|
import {MatProgressBar} from '@angular/material/progress-bar';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-generate-image.component',
|
||||||
|
imports: [
|
||||||
|
AsyncPipe,
|
||||||
|
FormsModule,
|
||||||
|
MatButton,
|
||||||
|
MatCard,
|
||||||
|
MatCardActions,
|
||||||
|
MatCardContent,
|
||||||
|
MatCardHeader,
|
||||||
|
MatFormField,
|
||||||
|
MatInput,
|
||||||
|
MatLabel,
|
||||||
|
MatProgressSpinner,
|
||||||
|
NgOptimizedImage,
|
||||||
|
MatCardXlImage,
|
||||||
|
MatCardImage,
|
||||||
|
MatToolbarRow,
|
||||||
|
MatToolbar,
|
||||||
|
MatIcon,
|
||||||
|
MatMiniFabButton,
|
||||||
|
MatTooltip,
|
||||||
|
MatProgressBar
|
||||||
|
|
||||||
|
|
||||||
|
],
|
||||||
|
templateUrl: './generate-image.component.html',
|
||||||
|
styleUrl: './generate-image.component.scss',
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
})
|
||||||
|
export class GenerateImageComponent {
|
||||||
|
|
||||||
|
isSpinnerVisible = false;
|
||||||
|
|
||||||
|
query : string = '';
|
||||||
|
|
||||||
|
images: Image[] = [];
|
||||||
|
image: Image = {
|
||||||
|
url: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
currentFile?: File;
|
||||||
|
message = '';
|
||||||
|
|
||||||
|
|
||||||
|
isLoggedIn = false;
|
||||||
|
|
||||||
|
private storageService: TokenStorageService = inject(TokenStorageService);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private zhipuaiImageService: ZhipuaiImageService,
|
||||||
|
public spinnerService: SpinnerService,
|
||||||
|
private uploadService: FileUploadService,
|
||||||
|
private userApiService:UserApiService,
|
||||||
|
|
||||||
|
|
||||||
|
) {
|
||||||
|
|
||||||
|
|
||||||
|
this.isLoggedIn = this.storageService.isLoggedIn();
|
||||||
|
}
|
||||||
|
|
||||||
|
generateImage(){
|
||||||
|
this.zhipuaiImageService.generate(this.query).subscribe(
|
||||||
|
data => {
|
||||||
|
|
||||||
|
this.image = data;
|
||||||
|
|
||||||
|
this.images.unshift(this.image);
|
||||||
|
|
||||||
|
// this.output.file = data.;
|
||||||
|
console.log(data);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
save(url: string | undefined) {
|
||||||
|
let requestUrl:string = url?url:"";
|
||||||
|
console.log(requestUrl);
|
||||||
|
this.userApiService.saveZhipuaiImage(requestUrl).subscribe(data =>{
|
||||||
|
console.log(data);
|
||||||
|
},error =>{
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+4
-4
@@ -1,10 +1,10 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {Observable} from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
import {Tutorial} from '../models/tutorial.model';
|
import {Tutorial} from '../../models/tutorial.model';
|
||||||
import {HttpClient} from '@angular/common/http';
|
import {HttpClient} from '@angular/common/http';
|
||||||
import {Image} from '../models/image';
|
import {Image} from '../../models/image';
|
||||||
import {SpinnerService} from './spinner.service';
|
import {SpinnerService} from '../../services/spinner.service';
|
||||||
import {GlobalConstants} from '../global-constants';
|
import {GlobalConstants} from '../../global-constants';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+6
-8
@@ -1,20 +1,18 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { ProfileComponent } from './profile.component';
|
import { DialogLoginComponent } from './dialog-login.component';
|
||||||
|
|
||||||
describe('ProfileComponent', () => {
|
describe('DialogLoginComponent', () => {
|
||||||
let component: ProfileComponent;
|
let component: DialogLoginComponent;
|
||||||
let fixture: ComponentFixture<ProfileComponent>;
|
let fixture: ComponentFixture<DialogLoginComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ ProfileComponent ]
|
imports: [DialogLoginComponent]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
fixture = TestBed.createComponent(DialogLoginComponent);
|
||||||
fixture = TestBed.createComponent(ProfileComponent);
|
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
CUSTOM_ELEMENTS_SCHEMA,
|
||||||
|
EventEmitter, Inject,
|
||||||
|
inject,
|
||||||
|
Output,
|
||||||
|
signal
|
||||||
|
} from '@angular/core';
|
||||||
|
import {FormsModule} from '@angular/forms';
|
||||||
|
import {MatButton, MatIconButton} from '@angular/material/button';
|
||||||
|
import {
|
||||||
|
MAT_DIALOG_DATA,
|
||||||
|
MatDialogActions,
|
||||||
|
MatDialogClose,
|
||||||
|
MatDialogContent,
|
||||||
|
MatDialogRef,
|
||||||
|
MatDialogTitle
|
||||||
|
} from '@angular/material/dialog';
|
||||||
|
import {MatFormField, MatInput, MatLabel, MatSuffix} from '@angular/material/input';
|
||||||
|
import {MatIcon} from '@angular/material/icon';
|
||||||
|
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||||
|
import {DialogLoginData} from '../main.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-dialog-login.component',
|
||||||
|
imports: [
|
||||||
|
FormsModule,
|
||||||
|
MatButton,
|
||||||
|
MatDialogActions,
|
||||||
|
MatDialogClose,
|
||||||
|
MatDialogContent,
|
||||||
|
MatDialogTitle,
|
||||||
|
MatFormField,
|
||||||
|
MatIcon,
|
||||||
|
MatIconButton,
|
||||||
|
MatInput,
|
||||||
|
MatLabel,
|
||||||
|
MatSuffix
|
||||||
|
],
|
||||||
|
templateUrl: './dialog-login.component.html',
|
||||||
|
styleUrl: './dialog-login.component.scss',
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class DialogLoginComponent {
|
||||||
|
readonly dialogRef = inject(MatDialogRef<DialogLoginComponent>);
|
||||||
|
hide = signal(true);
|
||||||
|
|
||||||
|
@Output() loginClicked = new EventEmitter<any>();
|
||||||
|
@Output() signupClicked = new EventEmitter<any>();
|
||||||
|
|
||||||
|
private _snackBar = inject(MatSnackBar);
|
||||||
|
durationInSeconds = 5;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data:DialogLoginData) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
openLoginFailedSnackBar(errorMessage : string = "Login failed.") {
|
||||||
|
this._snackBar.open(errorMessage , "", {
|
||||||
|
duration: this.durationInSeconds * 1000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onNoClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
clickEvent(event: MouseEvent) {
|
||||||
|
this.hide.set(!this.hide());
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
login() {
|
||||||
|
this.loginClicked.emit(this.data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
signup() {
|
||||||
|
this.signupClicked.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -22,7 +22,7 @@ import {
|
|||||||
import {MatFormField, MatInput, MatLabel, MatSuffix} from '@angular/material/input';
|
import {MatFormField, MatInput, MatLabel, MatSuffix} from '@angular/material/input';
|
||||||
import {MatIcon} from '@angular/material/icon';
|
import {MatIcon} from '@angular/material/icon';
|
||||||
import {MatSnackBar} from '@angular/material/snack-bar';
|
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||||
import {DialogSignupData} from '../../main-module/main.component/main.component';
|
import {DialogSignupData} from '../main.component';
|
||||||
import {ErrorStateMatcher} from '@angular/material/core';
|
import {ErrorStateMatcher} from '@angular/material/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
+7
-7
@@ -1,15 +1,13 @@
|
|||||||
<mat-toolbar class="fixed-top">
|
<mat-toolbar class="fixed-top">
|
||||||
<button mat-raised-button routerLink="generate-image">
|
<button mat-button routerLink="">
|
||||||
|
{{title}}
|
||||||
|
</button>
|
||||||
|
<button mat-raised-button routerLink="./ai/generate-image">
|
||||||
Generate Image
|
Generate Image
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button routerLink="tutorials">
|
<button mat-raised-button routerLink="./tutorials/tutorials-all">
|
||||||
Tutorials
|
Tutorials
|
||||||
</button>
|
</button>
|
||||||
@if (isLoggedIn) {
|
|
||||||
<button mat-raised-button routerLink="add-tutorial" >
|
|
||||||
Add tutorial
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
|
|
||||||
<span class="menu-spacer"></span>
|
<span class="menu-spacer"></span>
|
||||||
|
|
||||||
@@ -58,6 +56,8 @@
|
|||||||
</mat-menu>
|
</mat-menu>
|
||||||
}
|
}
|
||||||
</mat-toolbar>
|
</mat-toolbar>
|
||||||
|
|
||||||
|
|
||||||
<div class="router_outlet">
|
<div class="router_outlet">
|
||||||
<router-outlet/>
|
<router-outlet/>
|
||||||
</div>
|
</div>
|
||||||
+5
-1
@@ -16,7 +16,11 @@ mat-toolbar{
|
|||||||
}
|
}
|
||||||
.mat-mdc-raised-button:not(:disabled){
|
.mat-mdc-raised-button:not(:disabled){
|
||||||
color: rgba(24, 255, 255, 0.96);
|
color: rgba(24, 255, 255, 0.96);
|
||||||
background-color: rgba(24,255,255,0.04);
|
background-color: rgba(24, 255, 255, 0);
|
||||||
|
}
|
||||||
|
.mat-mdc-button:not(:disabled){
|
||||||
|
color: rgba(24, 255, 255, 0.96);
|
||||||
|
background-color: rgba(24, 255, 255, 0);
|
||||||
}
|
}
|
||||||
.mat-mdc-mini-fab{
|
.mat-mdc-mini-fab{
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
+12
-18
@@ -1,35 +1,30 @@
|
|||||||
import {Component, CUSTOM_ELEMENTS_SCHEMA, inject, OnInit} from '@angular/core';
|
import {Component, CUSTOM_ELEMENTS_SCHEMA, inject, OnInit} from '@angular/core';
|
||||||
//import {NavigationComponent} from '../navigation/navigation.component';
|
|
||||||
|
|
||||||
import {Router, RouterLink, RouterOutlet} from '@angular/router';
|
import {Router, RouterLink, RouterOutlet} from '@angular/router';
|
||||||
import {MatToolbar} from '@angular/material/toolbar';
|
import {MatToolbar} from '@angular/material/toolbar';
|
||||||
import {MatButton, MatFabButton, MatMiniFabButton} from '@angular/material/button';
|
import {MatButton, MatFabButton, MatMiniFabButton} from '@angular/material/button';
|
||||||
import {IconDirective, IconService} from '@ant-design/icons-angular';
|
|
||||||
import {MatDialog} from '@angular/material/dialog';
|
import {MatDialog} from '@angular/material/dialog';
|
||||||
import {Subscription} from 'rxjs';
|
import {Subscription} from 'rxjs';
|
||||||
import {TokenStorageService} from '../../services/token-storage.service';
|
import {TokenStorageService} from '../../../services/token-storage.service';
|
||||||
import {AuthService} from '../../services/auth.service';
|
import {AuthService} from '../../../services/auth.service';
|
||||||
import {EventBusService} from '../../_shared/event-bus.service';
|
import {EventBusService} from '../../../_shared/event-bus.service';
|
||||||
import {DialogComponent} from '../../components/dialog/dialog.component';
|
|
||||||
|
|
||||||
import {CommonModule} from '@angular/common';
|
import {CommonModule} from '@angular/common';
|
||||||
import {MatIcon} from '@angular/material/icon';
|
import {MatIcon} from '@angular/material/icon';
|
||||||
import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu';
|
import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu';
|
||||||
import {MatTooltip} from '@angular/material/tooltip';
|
import {MatTooltip} from '@angular/material/tooltip';
|
||||||
import {DialogSignupComponent} from '../../components/dialog-signup.component/dialog-signup.component';
|
|
||||||
import {MatLabel} from '@angular/material/input';
|
import {MatLabel} from '@angular/material/input';
|
||||||
import {HttpClient} from '@angular/common/http';
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
|
||||||
import { environment } from '../../../environments/environment';
|
import { environment } from '../../../../environments/environment';
|
||||||
|
import {DialogLoginComponent} from './dialog-login.component/dialog-login.component';
|
||||||
|
import {DialogSignupComponent} from './dialog-signup.component/dialog-signup.component';
|
||||||
|
import {GlobalConstants} from '../../../global-constants';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-main.component',
|
selector: 'app-main.component',
|
||||||
imports: [
|
imports: [
|
||||||
|
|
||||||
MatToolbar,
|
MatToolbar,
|
||||||
MatButton,
|
MatButton,
|
||||||
RouterLink,
|
RouterLink,
|
||||||
|
|
||||||
RouterOutlet,
|
RouterOutlet,
|
||||||
CommonModule,
|
CommonModule,
|
||||||
MatIcon,
|
MatIcon,
|
||||||
@@ -39,13 +34,14 @@ import { environment } from '../../../environments/environment';
|
|||||||
MatMenuItem,
|
MatMenuItem,
|
||||||
MatTooltip,
|
MatTooltip,
|
||||||
MatLabel
|
MatLabel
|
||||||
|
|
||||||
],
|
],
|
||||||
schemas: [ CUSTOM_ELEMENTS_SCHEMA ],
|
schemas: [ CUSTOM_ELEMENTS_SCHEMA ],
|
||||||
templateUrl: './main.component.html',
|
templateUrl: './main.component.html',
|
||||||
styleUrl: './main.component.scss'
|
styleUrl: './main.component.scss'
|
||||||
})
|
})
|
||||||
export class MainComponent implements OnInit{
|
export class MainComponent implements OnInit{
|
||||||
|
title = GlobalConstants.TITLE;
|
||||||
|
|
||||||
// public props
|
// public props
|
||||||
navCollapsed: boolean = false;
|
navCollapsed: boolean = false;
|
||||||
navCollapsedMob: boolean = false;
|
navCollapsedMob: boolean = false;
|
||||||
@@ -76,8 +72,6 @@ export class MainComponent implements OnInit{
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
||||||
|
|
||||||
this.refreshToolbar();
|
this.refreshToolbar();
|
||||||
|
|
||||||
this.eventBusSub = this.eventBusService.on('logout', () => {
|
this.eventBusSub = this.eventBusService.on('logout', () => {
|
||||||
@@ -140,7 +134,7 @@ export class MainComponent implements OnInit{
|
|||||||
this.storageService.clean();
|
this.storageService.clean();
|
||||||
|
|
||||||
//window.location.reload();
|
//window.location.reload();
|
||||||
this.router.navigate([environment.default_page]).then(() => {
|
this.router.navigate([GlobalConstants.DEFAULT_PAGE]).then(() => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
//window.location.reload();
|
//window.location.reload();
|
||||||
@@ -153,7 +147,7 @@ export class MainComponent implements OnInit{
|
|||||||
|
|
||||||
openLoginDialog(enterAnimationDuration: string, exitAnimationDuration: string) {
|
openLoginDialog(enterAnimationDuration: string, exitAnimationDuration: string) {
|
||||||
|
|
||||||
let dialogLoginRef = this.dialog.open(DialogComponent, {
|
let dialogLoginRef = this.dialog.open(DialogLoginComponent, {
|
||||||
width: '350px',
|
width: '350px',
|
||||||
enterAnimationDuration,
|
enterAnimationDuration,
|
||||||
exitAnimationDuration,
|
exitAnimationDuration,
|
||||||
@@ -187,7 +181,7 @@ export class MainComponent implements OnInit{
|
|||||||
dialogLoginRef.close()
|
dialogLoginRef.close()
|
||||||
|
|
||||||
|
|
||||||
this.router.navigate(['main/tutorials']);
|
this.router.navigate([GlobalConstants.DEFAULT_PAGE]);
|
||||||
},
|
},
|
||||||
err => {
|
err => {
|
||||||
dialogLoginRef.componentInstance.openLoginFailedSnackBar(err.error.message);
|
dialogLoginRef.componentInstance.openLoginFailedSnackBar(err.error.message);
|
||||||
+3
-11
@@ -2,14 +2,9 @@ import {RouterModule} from '@angular/router';
|
|||||||
import {MainComponent} from './main.component/main.component';
|
import {MainComponent} from './main.component/main.component';
|
||||||
import {mainRouting} from './main.routing';
|
import {mainRouting} from './main.routing';
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {CommonModule} from '@angular/common';
|
|
||||||
|
|
||||||
import {HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi} from '@angular/common/http';
|
import {HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi} from '@angular/common/http';
|
||||||
import {CustomHttpInterceptor} from '../helpers/custom-http-interceptor';
|
import {CustomHttpInterceptor} from '../../helpers/custom-http-interceptor';
|
||||||
import {AngularImageViewerModule} from '@hreimer/angular-image-viewer';
|
import {authInterceptorProviders} from '../../helpers/auth.interceptor';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
|
||||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
|
||||||
import {authInterceptorProviders} from '../helpers/auth.interceptor';
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -17,10 +12,7 @@ import {authInterceptorProviders} from '../helpers/auth.interceptor';
|
|||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
mainRouting,
|
mainRouting,
|
||||||
MainComponent,
|
MainComponent
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
],
|
],
|
||||||
exports: [RouterModule],
|
exports: [RouterModule],
|
||||||
providers: [authInterceptorProviders,provideHttpClient(withInterceptorsFromDi()),{
|
providers: [authInterceptorProviders,provideHttpClient(withInterceptorsFromDi()),{
|
||||||
+10
-25
@@ -1,16 +1,21 @@
|
|||||||
import {RouterModule, Routes} from '@angular/router';
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
import {HomeComponent} from '../components/home.component/home.component';
|
|
||||||
import {MainComponent} from './main.component/main.component';
|
import {MainComponent} from './main.component/main.component';
|
||||||
import {TutorialsComponent} from '../components/tutorials.component/tutorials.component';
|
|
||||||
import {RegisterComponent} from '../components/register/register.component';
|
|
||||||
import {ProfileComponent} from '../components/profile/profile.component';
|
|
||||||
import {GenerateImageComponent} from '../components/generate-image.component/generate-image.component';
|
|
||||||
|
|
||||||
const MAIN_ROUTES: Routes =[
|
const MAIN_ROUTES: Routes =[
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: MainComponent,
|
component: MainComponent,
|
||||||
children: [
|
children: [
|
||||||
|
{
|
||||||
|
path: 'tutorials',
|
||||||
|
loadChildren: () =>
|
||||||
|
import('../tutorials-module/tutorials.module').then((m) => m.TutorialsModule),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'ai',
|
||||||
|
loadChildren: () =>
|
||||||
|
import('../ai-module/ai.module').then((m) => m.AiModule),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'admin',
|
path: 'admin',
|
||||||
loadChildren: () =>
|
loadChildren: () =>
|
||||||
@@ -25,26 +30,6 @@ const MAIN_ROUTES: Routes =[
|
|||||||
path: 'moderator',
|
path: 'moderator',
|
||||||
loadChildren: () =>
|
loadChildren: () =>
|
||||||
import('../moderator-module/moderator.module').then((m) => m.ModeratorModule),
|
import('../moderator-module/moderator.module').then((m) => m.ModeratorModule),
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'home',
|
|
||||||
component: HomeComponent
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'generate-image',
|
|
||||||
component: GenerateImageComponent
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'tutorials',
|
|
||||||
component: TutorialsComponent
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'register',
|
|
||||||
component : RegisterComponent
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'profile',
|
|
||||||
component : ProfileComponent
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {HttpClient, HttpHeaders} from '@angular/common/http';
|
import {HttpClient} from '@angular/common/http';
|
||||||
import {Observable} from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
import {Tutorial} from '../models/tutorial.model';
|
import {Tutorial} from '../../models/tutorial.model';
|
||||||
import {GlobalConstants} from '../global-constants';
|
import {GlobalConstants} from '../../global-constants';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user