refs #1138 Add translate and es-en files
testing/ogGui-multibranch/pipeline/head There was a failure building this commit Details

oggui/translations
Alvaro Puente Mella 2024-11-15 12:47:00 +01:00
parent 36539a3d9e
commit 701223d1bb
62 changed files with 2410 additions and 989 deletions

View File

@ -7,7 +7,7 @@
"i18n": { "i18n": {
"sourceLocale": "es", "sourceLocale": "es",
"locales": { "locales": {
"en-US": "src/locale/messages.en.json" "en-US": "src/locale/en.json"
} }
}, },
"projectType": "application", "projectType": "application",
@ -41,9 +41,14 @@
], ],
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"assets": [ "assets": [
"src/favicon.ico", "src/favicon.ico",
"src/assets" "src/assets",
], {
"glob": "**/*",
"input": "src/locale",
"output": "/locale"
}
],
"styles": [ "styles": [
"src/custom-theme.scss", "src/custom-theme.scss",
"src/styles.css", "src/styles.css",

View File

@ -18,6 +18,8 @@
"@angular/platform-browser": "^18.0.0", "@angular/platform-browser": "^18.0.0",
"@angular/platform-browser-dynamic": "^18.0.0", "@angular/platform-browser-dynamic": "^18.0.0",
"@angular/router": "^18.0.0", "@angular/router": "^18.0.0",
"@ngx-translate/core": "^16.0.3",
"@ngx-translate/http-loader": "^16.0.0",
"@swimlane/ngx-charts": "^20.5.0", "@swimlane/ngx-charts": "^20.5.0",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"ngx-toastr": "^19.0.0", "ngx-toastr": "^19.0.0",
@ -4975,6 +4977,30 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/@ngx-translate/core": {
"version": "16.0.3",
"resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-16.0.3.tgz",
"integrity": "sha512-UPse66z9tRUmIpeorYodXBQY6O4foUmj9jy9cCuuja7lqdOwRBWPzCWqc+qYIXv5L2QoqZdxgHtqoUz+Q9weSA==",
"dependencies": {
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/common": ">=16",
"@angular/core": ">=16"
}
},
"node_modules/@ngx-translate/http-loader": {
"version": "16.0.0",
"resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-16.0.0.tgz",
"integrity": "sha512-l3okOHGVxZ1Bm55OpakSfXvI2yYmVmhYqgwGU4aIQIRUqpkBCrSDZnmrHTcZfsGJzXKB5E2D2rko9i28gBijmA==",
"dependencies": {
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/common": ">=16",
"@angular/core": ">=16"
}
},
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -6533,9 +6559,9 @@
} }
}, },
"node_modules/body-parser": { "node_modules/body-parser": {
"version": "1.20.2", "version": "1.20.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"bytes": "3.1.2", "bytes": "3.1.2",
@ -6546,7 +6572,7 @@
"http-errors": "2.0.0", "http-errors": "2.0.0",
"iconv-lite": "0.4.24", "iconv-lite": "0.4.24",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"qs": "6.11.0", "qs": "6.13.0",
"raw-body": "2.5.2", "raw-body": "2.5.2",
"type-is": "~1.6.18", "type-is": "~1.6.18",
"unpipe": "1.0.0" "unpipe": "1.0.0"
@ -7221,9 +7247,9 @@
"dev": true "dev": true
}, },
"node_modules/cookie": { "node_modules/cookie": {
"version": "0.4.2", "version": "0.7.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@ -8081,9 +8107,9 @@
} }
}, },
"node_modules/engine.io": { "node_modules/engine.io": {
"version": "6.5.5", "version": "6.6.2",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz",
"integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", "integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/cookie": "^0.4.1", "@types/cookie": "^0.4.1",
@ -8091,7 +8117,7 @@
"@types/node": ">=10.0.0", "@types/node": ">=10.0.0",
"accepts": "~1.3.4", "accepts": "~1.3.4",
"base64id": "2.0.0", "base64id": "2.0.0",
"cookie": "~0.4.1", "cookie": "~0.7.2",
"cors": "~2.8.5", "cors": "~2.8.5",
"debug": "~4.3.1", "debug": "~4.3.1",
"engine.io-parser": "~5.2.1", "engine.io-parser": "~5.2.1",
@ -8397,37 +8423,37 @@
"dev": true "dev": true
}, },
"node_modules/express": { "node_modules/express": {
"version": "4.19.2", "version": "4.21.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"accepts": "~1.3.8", "accepts": "~1.3.8",
"array-flatten": "1.1.1", "array-flatten": "1.1.1",
"body-parser": "1.20.2", "body-parser": "1.20.3",
"content-disposition": "0.5.4", "content-disposition": "0.5.4",
"content-type": "~1.0.4", "content-type": "~1.0.4",
"cookie": "0.6.0", "cookie": "0.7.1",
"cookie-signature": "1.0.6", "cookie-signature": "1.0.6",
"debug": "2.6.9", "debug": "2.6.9",
"depd": "2.0.0", "depd": "2.0.0",
"encodeurl": "~1.0.2", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"etag": "~1.8.1", "etag": "~1.8.1",
"finalhandler": "1.2.0", "finalhandler": "1.3.1",
"fresh": "0.5.2", "fresh": "0.5.2",
"http-errors": "2.0.0", "http-errors": "2.0.0",
"merge-descriptors": "1.0.1", "merge-descriptors": "1.0.3",
"methods": "~1.1.2", "methods": "~1.1.2",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
"path-to-regexp": "0.1.7", "path-to-regexp": "0.1.10",
"proxy-addr": "~2.0.7", "proxy-addr": "~2.0.7",
"qs": "6.11.0", "qs": "6.13.0",
"range-parser": "~1.2.1", "range-parser": "~1.2.1",
"safe-buffer": "5.2.1", "safe-buffer": "5.2.1",
"send": "0.18.0", "send": "0.19.0",
"serve-static": "1.15.0", "serve-static": "1.16.2",
"setprototypeof": "1.2.0", "setprototypeof": "1.2.0",
"statuses": "2.0.1", "statuses": "2.0.1",
"type-is": "~1.6.18", "type-is": "~1.6.18",
@ -8439,9 +8465,9 @@
} }
}, },
"node_modules/express/node_modules/cookie": { "node_modules/express/node_modules/cookie": {
"version": "0.6.0", "version": "0.7.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@ -8456,14 +8482,23 @@
"ms": "2.0.0" "ms": "2.0.0"
} }
}, },
"node_modules/express/node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"dev": true,
"engines": {
"node": ">= 0.8"
}
},
"node_modules/express/node_modules/finalhandler": { "node_modules/express/node_modules/finalhandler": {
"version": "1.2.0", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"debug": "2.6.9", "debug": "2.6.9",
"encodeurl": "~1.0.2", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
@ -10783,10 +10818,13 @@
} }
}, },
"node_modules/merge-descriptors": { "node_modules/merge-descriptors": {
"version": "1.0.1", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"dev": true "dev": true,
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}, },
"node_modules/merge-stream": { "node_modules/merge-stream": {
"version": "2.0.0", "version": "2.0.0",
@ -10813,9 +10851,9 @@
} }
}, },
"node_modules/micromatch": { "node_modules/micromatch": {
"version": "4.0.7", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"braces": "^3.0.3", "braces": "^3.0.3",
@ -11577,9 +11615,9 @@
} }
}, },
"node_modules/object-inspect": { "node_modules/object-inspect": {
"version": "1.13.2", "version": "1.13.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
"integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@ -12052,9 +12090,9 @@
"dev": true "dev": true
}, },
"node_modules/path-to-regexp": { "node_modules/path-to-regexp": {
"version": "0.1.7", "version": "0.1.10",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
"dev": true "dev": true
}, },
"node_modules/path-type": { "node_modules/path-type": {
@ -12343,12 +12381,12 @@
} }
}, },
"node_modules/qs": { "node_modules/qs": {
"version": "6.11.0", "version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"side-channel": "^1.0.4" "side-channel": "^1.0.6"
}, },
"engines": { "engines": {
"node": ">=0.6" "node": ">=0.6"
@ -12923,9 +12961,9 @@
} }
}, },
"node_modules/send": { "node_modules/send": {
"version": "0.18.0", "version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"debug": "2.6.9", "debug": "2.6.9",
@ -13067,20 +13105,29 @@
"dev": true "dev": true
}, },
"node_modules/serve-static": { "node_modules/serve-static": {
"version": "1.15.0", "version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"encodeurl": "~1.0.2", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
"send": "0.18.0" "send": "0.19.0"
}, },
"engines": { "engines": {
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/serve-static/node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"dev": true,
"engines": {
"node": ">= 0.8"
}
},
"node_modules/set-function-length": { "node_modules/set-function-length": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@ -13244,16 +13291,16 @@
} }
}, },
"node_modules/socket.io": { "node_modules/socket.io": {
"version": "4.7.5", "version": "4.8.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
"integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"accepts": "~1.3.4", "accepts": "~1.3.4",
"base64id": "~2.0.0", "base64id": "~2.0.0",
"cors": "~2.8.5", "cors": "~2.8.5",
"debug": "~4.3.2", "debug": "~4.3.2",
"engine.io": "~6.5.2", "engine.io": "~6.6.0",
"socket.io-adapter": "~2.5.2", "socket.io-adapter": "~2.5.2",
"socket.io-parser": "~4.2.4" "socket.io-parser": "~4.2.4"
}, },
@ -14469,9 +14516,9 @@
} }
}, },
"node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": {
"version": "2.0.6", "version": "2.0.7",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz",
"integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/http-proxy": "^1.17.8", "@types/http-proxy": "^1.17.8",

View File

@ -20,6 +20,8 @@
"@angular/platform-browser": "^18.0.0", "@angular/platform-browser": "^18.0.0",
"@angular/platform-browser-dynamic": "^18.0.0", "@angular/platform-browser-dynamic": "^18.0.0",
"@angular/router": "^18.0.0", "@angular/router": "^18.0.0",
"@ngx-translate/core": "^16.0.3",
"@ngx-translate/http-loader": "^16.0.0",
"@swimlane/ngx-charts": "^20.5.0", "@swimlane/ngx-charts": "^20.5.0",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"ngx-toastr": "^19.0.0", "ngx-toastr": "^19.0.0",

View File

@ -8,7 +8,7 @@ import { HeaderComponent } from './layout/header/header.component';
import { SidebarComponent } from './layout/sidebar/sidebar.component'; import { SidebarComponent } from './layout/sidebar/sidebar.component';
import { LoginComponent } from './components/login/login.component'; import { LoginComponent } from './components/login/login.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { HTTP_INTERCEPTORS, HttpClient, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { CustomInterceptor } from './core/services/custom.interceptor'; import { CustomInterceptor } from './core/services/custom.interceptor';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { MatToolbarModule } from '@angular/material/toolbar'; import { MatToolbarModule } from '@angular/material/toolbar';
@ -116,6 +116,21 @@ import { CreateOperativeSystemComponent } from './components/operative-system/cr
import { ShowTemplateContentComponent } from './components/ogboot/pxe/show-template-content/show-template-content.component'; import { ShowTemplateContentComponent } from './components/ogboot/pxe/show-template-content/show-template-content.component';
import { AddClientsToPxeComponent } from './components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component'; import { AddClientsToPxeComponent } from './components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component';
import { ClientsComponent } from './components/ogboot/pxe/clients/clients.component'; import { ClientsComponent } from './components/ogboot/pxe/clients/clients.component';
<<<<<<< Updated upstream
=======
import { RepositoriesComponent } from './components/repositories/repositories.component';
import { CreateRepositoryComponent } from './components/repositories/create-repository/create-repository.component';
import { ExecuteCommandComponent } from './components/commands/main-commands/execute-command/execute-command.component';
import { ExecuteCommandOuComponent } from './components/groups/shared/execute-command-ou/execute-command-ou.component';
import { JoyrideModule } from 'ngx-joyride';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, './locale/', '.json');
}
>>>>>>> Stashed changes
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
@ -217,6 +232,17 @@ import { ClientsComponent } from './components/ogboot/pxe/clients/clients.compon
MatDatepickerModule, MatDatepickerModule,
MatNativeDateModule, MatNativeDateModule,
MatSliderModule, MatSliderModule,
<<<<<<< Updated upstream
=======
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
}),
JoyrideModule.forRoot(),
>>>>>>> Stashed changes
ToastrModule.forRoot( ToastrModule.forRoot(
{ {
timeOut: 5000, timeOut: 5000,

View File

@ -1,10 +1,10 @@
<div class="container"> <div class="container">
<button mat-fab color="primary" class="fab-button" routerLink="/users"> <button mat-fab color="primary" class="fab-button" routerLink="/users">
<mat-icon>group</mat-icon> <mat-icon>group</mat-icon>
<span i18n="@@labelUsers">Usuarios</span> <span>{{ 'labelUsers' | translate }}</span>
</button> </button>
<button mat-fab color="primary" class="fab-button" routerLink="/user-groups"> <button mat-fab color="primary" class="fab-button" routerLink="/user-groups">
<mat-icon>admin_panel_settings</mat-icon> <mat-icon>admin_panel_settings</mat-icon>
<span i18n="@@labelRoles">Roles</span> <span>{{ 'labelRoles' | translate }}</span>
</button> </button>
</div> </div>

View File

@ -1,22 +1,22 @@
<h1 mat-dialog-title i18n="@@dialogTitleAddRole">Añadir Rol</h1> <h1 mat-dialog-title>{{ 'dialogTitleAddRole' | translate }}</h1>
<mat-dialog-content class="form-container"> <mat-dialog-content class="form-container">
<form [formGroup]="roleForm" class="role-form"> <form [formGroup]="roleForm" class="role-form">
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label i18n="@@labelRoleName">Nombre</mat-label> <mat-label>{{ 'labelRoleName' | translate }}</mat-label>
<input matInput formControlName="name" required> <input matInput formControlName="name" required>
</mat-form-field> </mat-form-field>
<section class="example-section"> <section class="example-section">
<h4 i18n="@@sectionTitlePermissions">Permisos:</h4> <h4>{{ 'sectionTitlePermissions' | translate }}</h4>
<p><mat-checkbox formControlName="superAdmin" i18n="@@checkboxSuperAdmin">Super Admin</mat-checkbox></p> <p><mat-checkbox formControlName="superAdmin">{{ 'checkboxSuperAdmin' | translate }}</mat-checkbox></p>
<p><mat-checkbox formControlName="orgAdmin" i18n="@@checkboxOrgAdmin">Admin de Unidad Organizativa</mat-checkbox></p> <p><mat-checkbox formControlName="orgAdmin">{{ 'checkboxOrgAdmin' | translate }}</mat-checkbox></p>
<p><mat-checkbox formControlName="orgOperator" i18n="@@checkboxOrgOperator">Operador de Unidad Organizativa</mat-checkbox></p> <p><mat-checkbox formControlName="orgOperator">{{ 'checkboxOrgOperator' | translate }}</mat-checkbox></p>
<p><mat-checkbox formControlName="orgMinimal" i18n="@@checkboxOrgMinimal">Unidad Organizativa Mínima</mat-checkbox></p> <p><mat-checkbox formControlName="orgMinimal">{{ 'checkboxOrgMinimal' | translate }}</mat-checkbox></p>
<p><mat-checkbox formControlName="userRole" i18n="@@checkboxUserRole">Usuario</mat-checkbox></p> <p><mat-checkbox formControlName="userRole">{{ 'checkboxUserRole' | translate }}</mat-checkbox></p>
</section> </section>
</form> </form>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button (click)="onNoClick()" i18n="@@buttonCancel">Cancelar</button> <button mat-button (click)="onNoClick()">{{ 'buttonCancel' | translate }}</button>
<button mat-button (click)="onSubmit()" i18n="@@buttonAdd">Añadir</button> <button mat-button (click)="onSubmit()">{{ 'buttonAdd' | translate }}</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,16 +1,18 @@
<div class="header-container"> <div class="header-container">
<h2 class="title" i18n="@@adminImagesTitle">Administrar Roles</h2> <h2 class="title">{{ 'adminRolesTitle' | translate }}</h2>
<div class="images-button-row"> <div class="images-button-row">
<button mat-flat-button color="primary" (click)="addUser()">Añadir rol</button> <button mat-flat-button color="primary" (click)="addUser()">
{{ 'addRole' | translate }}
</button>
</div> </div>
</div> </div>
<mat-divider class="divider"></mat-divider> <mat-divider class="divider"></mat-divider>
<div class="search-container"> <div class="search-container">
<mat-form-field appearance="fill" class="search-string"> <mat-form-field appearance="fill" class="search-string">
<mat-label i18n="@@searchLabel">Buscar nombre de rol</mat-label> <mat-label>{{ 'searchRoleLabel' | translate }}</mat-label>
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder"> <input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()">
<mat-icon matSuffix>search</mat-icon> <mat-icon matSuffix>search</mat-icon>
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint> <mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
@ -26,12 +28,12 @@
</ng-container> </ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th> <th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
<td mat-cell *matCellDef="let role" style="text-align: center;"> <td mat-cell *matCellDef="let role" style="text-align: center;">
<button mat-icon-button color="primary" (click)="editRole(role)" i18n="@@editImage"> <button mat-icon-button color="primary" (click)="editRole(role)">
<mat-icon>edit</mat-icon> <mat-icon>edit</mat-icon>
</button> </button>
<button mat-icon-button color="warn" (click)="deleteRole(role)" i18n="@@buttonDelete" [disabled]="role.permissions.includes('ROLE_SUPER_ADMIN')"> <button mat-icon-button color="warn" (click)="deleteRole(role)" [disabled]="role.permissions.includes('ROLE_SUPER_ADMIN')">
<mat-icon>delete</mat-icon> <mat-icon>delete</mat-icon>
</button> </button>
</td> </td>

View File

@ -1,17 +1,17 @@
<h1 mat-dialog-title i18n="@@dialogTitleAddRole">Añadir Usuario</h1> <h1 mat-dialog-title>{{ 'dialogTitleAddUser' | translate }}</h1>
<mat-dialog-content class="form-container"> <mat-dialog-content class="form-container">
<form [formGroup]="userForm" class="user-form"> <form [formGroup]="userForm" class="user-form">
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label i18n="@@addUserlabelUsername">Nombre de usuario</mat-label> <mat-label>{{ 'addUserlabelUsername' | translate }}</mat-label>
<input matInput formControlName="username" required> <input matInput formControlName="username" required>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label i18n="@@addUserlabelPassword">Contraseña</mat-label> <mat-label>{{ 'addUserlabelPassword' | translate }}</mat-label>
<input matInput formControlName="password" type="password" required> <input matInput formControlName="password" type="password" required>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label i18n="@@labelRole">Rol</mat-label> <mat-label>{{ 'labelRole' | translate }}</mat-label>
<mat-select formControlName="role" required> <mat-select formControlName="role" required>
<mat-option *ngFor="let group of userGroups" [value]="group['@id']"> <mat-option *ngFor="let group of userGroups" [value]="group['@id']">
{{ group.name }} {{ group.name }}
@ -20,16 +20,16 @@
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label i18n="@@labelOrganizationalUnit">Unidad organiativa</mat-label> <mat-label>{{ 'labelOrganizationalUnit' | translate }}</mat-label>
<mat-select multiple formControlName="organizationalUnits"> <mat-select multiple formControlName="organizationalUnits">
<mat-option *ngFor="let unit of organizationalUnits" [value]="unit['@id']"> <mat-option *ngFor="let unit of organizationalUnits" [value]="unit['@id']">
{{unit.name}} {{ unit.name }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
</form> </form>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button (click)="onNoClick()" i18n="@@buttonCancel">Cancelar</button> <button mat-button (click)="onNoClick()">{{ 'buttonCancel' | translate }}</button>
<button mat-button (click)="onSubmit()" i18n="@@buttonAdd">Añadir</button> <button mat-button (click)="onSubmit()">{{ 'buttonAdd' | translate }}</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,29 +1,29 @@
<h1 mat-dialog-title i18n="@@dialogTitleEditUser">Editar Usuario</h1> <h1 mat-dialog-title>{{ 'dialogTitleEditUser' | translate }}</h1>
<mat-dialog-content class="form-container"> <mat-dialog-content class="form-container">
<form [formGroup]="userForm" class="user-form"> <form [formGroup]="userForm" class="user-form">
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@labelCurrentPassword">Contraseña actual</mat-label> <mat-label>{{ 'labelCurrentPassword' | translate }}</mat-label>
<input matInput formControlName="currentPassword" type="password"> <input matInput formControlName="currentPassword" type="password">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@labelNewPassword">Nueva contraseña</mat-label> <mat-label>{{ 'labelNewPassword' | translate }}</mat-label>
<input matInput formControlName="newPassword" type="password"> <input matInput formControlName="newPassword" type="password">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@labelRepeatPassword">Repite la contraseña</mat-label> <mat-label>{{ 'labelRepeatPassword' | translate }}</mat-label>
<input matInput formControlName="repeatNewPassword" type="password"> <input matInput formControlName="repeatNewPassword" type="password">
</mat-form-field> </mat-form-field>
<div class="error-message" *ngIf="passwordMismatch" i18n="@@errorPasswordMismatch"> <div class="error-message" *ngIf="passwordMismatch">
Las contraseñas no coinciden {{ 'errorPasswordMismatch' | translate }}
</div> </div>
<div class="error-message" *ngIf="updateError" i18n="@@errorUpdate"> <div class="error-message" *ngIf="updateError">
{{ resetPasswordError }} {{ resetPasswordError }}
</div> </div>
</form> </form>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button (click)="onNoClick()" i18n="@@buttonCancel">Cancelar</button> <button mat-button (click)="onNoClick()">{{ 'buttonCancel' | translate }}</button>
<button mat-button (click)="onSubmit()" [disabled]="loading" i18n="@@buttonEdit">Editar</button> <button mat-button (click)="onSubmit()" [disabled]="loading">{{ 'buttonEdit' | translate }}</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,16 +1,18 @@
<div class="header-container"> <div class="header-container">
<h2 class="title" i18n="@@adminImagesTitle">Administrar usuarios</h2> <h2 class="title">{{ 'adminImagesTitle' | translate }}</h2>
<div class="images-button-row"> <div class="images-button-row">
<button mat-flat-button color="primary" (click)="addUser()">Añadir usuarios</button> <button mat-flat-button color="primary" (click)="addUser()">
{{ 'addUser' | translate }}
</button>
</div> </div>
</div> </div>
<mat-divider class="divider"></mat-divider> <mat-divider class="divider"></mat-divider>
<div class="search-container"> <div class="search-container">
<mat-form-field appearance="fill" class="search-string"> <mat-form-field appearance="fill" class="search-string">
<mat-label i18n="@@searchLabel">Buscar nombre de usuario</mat-label> <mat-label>{{ 'searchLabel' | translate }}</mat-label>
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder"> <input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()">
<mat-icon matSuffix>search</mat-icon> <mat-icon matSuffix>search</mat-icon>
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint> <mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
@ -26,10 +28,14 @@
</ng-container> </ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th> <th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
<td mat-cell *matCellDef="let user" style="text-align: center;"> <td mat-cell *matCellDef="let user" style="text-align: center;">
<button mat-icon-button color="primary" (click)="editUser(user)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button> <button mat-icon-button color="primary" (click)="editUser(user)">
<button mat-icon-button color="warn" (click)="deleteUser(user)" i18n="@@buttonDelete"><mat-icon>delete</mat-icon></button> <mat-icon>edit</mat-icon>
</button>
<button mat-icon-button color="warn" (click)="deleteUser(user)">
<mat-icon>delete</mat-icon>
</button>
</td> </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>

View File

@ -1,16 +1,33 @@
<div class="header-container"> <div class="header-container">
<<<<<<< Updated upstream
<h2 class="title" i18n="@@adminImagesTitle">Administrar calendarios</h2> <h2 class="title" i18n="@@adminImagesTitle">Administrar calendarios</h2>
<div class="calendar-button-row"> <div class="calendar-button-row">
<button mat-flat-button color="primary" (click)="addImage()">Añadir calendario</button> <button mat-flat-button color="primary" (click)="addImage()">Añadir calendario</button>
=======
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<h2 joyrideStep="titleStep" text="{{ 'titleStepText' | translate }}" class="title">{{ 'adminCalendarsTitle' | translate }}</h2>
<div class="calendar-button-row">
<button joyrideStep="addButtonStep" text="{{ 'addButtonStepText' | translate }}" mat-flat-button color="primary" (click)="addImage()">
{{ 'addCalendar' | translate }}
</button>
>>>>>>> Stashed changes
</div> </div>
</div> </div>
<mat-divider class="divider"></mat-divider> <mat-divider class="divider"></mat-divider>
<div class="search-container"> <div class="search-container">
<<<<<<< Updated upstream
<mat-form-field appearance="fill" class="search-string"> <mat-form-field appearance="fill" class="search-string">
<mat-label i18n="@@searchLabel">Buscar nombre de calendario</mat-label> <mat-label i18n="@@searchLabel">Buscar nombre de calendario</mat-label>
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder"> <input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder">
=======
<mat-form-field joyrideStep="searchStep" text="{{ 'searchStepText' | translate }}" appearance="fill" class="search-string">
<mat-label>{{ 'searchCalendarLabel' | translate }}</mat-label>
<input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()">
>>>>>>> Stashed changes
<mat-icon matSuffix>search</mat-icon> <mat-icon matSuffix>search</mat-icon>
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint> <mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
@ -19,29 +36,45 @@
</div> </div>
<div *ngIf="!loading"> <div *ngIf="!loading">
<<<<<<< Updated upstream
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
=======
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" joyrideStep="tableStep" text="{{ 'tableStepText' | translate }}">
>>>>>>> Stashed changes
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef"> <ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th> <th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
<td mat-cell *matCellDef="let image" > <td mat-cell *matCellDef="let image">
<ng-container *ngIf="column.columnDef === 'isDefault' || column.columnDef === 'installed'"> <ng-container *ngIf="column.columnDef === 'isDefault' || column.columnDef === 'installed'">
<mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'"> <mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'">
{{ image[column.columnDef] ? 'check_circle' : 'cancel' }} {{ image[column.columnDef] ? 'check_circle' : 'cancel' }}
</mat-icon> </mat-icon>
</ng-container> </ng-container>
<ng-container *ngIf="column.columnDef !== 'isDefault' && column.columnDef !== 'installed' && column.columnDef !== 'downloadUrl'"> <ng-container *ngIf="column.columnDef !== 'isDefault' && column.columnDef !== 'installed' && column.columnDef !== 'downloadUrl'">
{{ column.cell(image) }} {{ column.cell(image) }}
</ng-container> </ng-container>
</td> </td>
</ng-container> </ng-container>
<<<<<<< Updated upstream
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th> <th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
=======
<ng-container matColumnDef="actions" joyrideStep="actionsStep" text="{{ 'actionsStepText' | translate }}">
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
>>>>>>> Stashed changes
<td mat-cell *matCellDef="let calendar" style="text-align: center;"> <td mat-cell *matCellDef="let calendar" style="text-align: center;">
<button mat-icon-button color="primary" (click)="editCalendar(calendar)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button> <button mat-icon-button color="primary" (click)="editCalendar(calendar)">
<button *ngIf="!syncUds" mat-icon-button color="primary" (click)="sync(calendar)"><mat-icon>sync</mat-icon></button> <mat-icon>edit</mat-icon>
<button *ngIf="syncUds" mat-icon-button color="primary"><mat-spinner diameter="24"></mat-spinner></button> </button>
<button mat-icon-button color="warn" (click)="deleteCalendar(calendar)" i18n="@@buttonDelete"><mat-icon>delete</mat-icon></button> <button *ngIf="!syncUds" mat-icon-button color="primary" (click)="sync(calendar)">
<mat-icon>sync</mat-icon>
</button>
<button *ngIf="syncUds" mat-icon-button color="primary">
<mat-spinner diameter="24"></mat-spinner>
</button>
<button mat-icon-button color="warn" (click)="deleteCalendar(calendar)">
<mat-icon>delete</mat-icon>
</button>
</td> </td>
</ng-container> </ng-container>

View File

@ -1,17 +1,19 @@
<h2 mat-dialog-title>{{ isEditMode ? 'Editar' : 'Añadir' }} calendario</h2> <h2 mat-dialog-title>{{ isEditMode ? ('editCalendar' | translate) : ('addCalendar' | translate) }}</h2>
<mat-dialog-content class="form-container"> <mat-dialog-content class="form-container">
<mat-slide-toggle [(ngModel)]="isRemoteAvailable" class="example-margin">¿Disponibilidad remoto?</mat-slide-toggle> <mat-slide-toggle [(ngModel)]="isRemoteAvailable" class="example-margin">
{{ 'remoteAvailability' | translate }}
</mat-slide-toggle>
<div *ngIf="!isRemoteAvailable" class="form-group"> <div *ngIf="!isRemoteAvailable" class="form-group">
<mat-label>Selecciona los días de la semana</mat-label> <mat-label>{{ 'selectWeekDays' | translate }}</mat-label>
<div class="row"> <div class="row">
<div class="col-md-6 checkbox-group"> <div class="col-md-6 checkbox-group">
<mat-checkbox *ngFor="let day of weekDays.slice(0, (weekDays.length / 2) + 1)" [(ngModel)]="busyWeekDays[day]"> <mat-checkbox *ngFor="let day of weekDays.slice(0, (weekDays.length / 2) + 1)" [(ngModel)]="busyWeekDays[day]">
{{ day }} {{ day }}
</mat-checkbox> </mat-checkbox>
</div> </div>
<div class="col-md-6 checkbox-group "> <div class="col-md-6 checkbox-group">
<mat-checkbox *ngFor="let day of weekDays.slice(weekDays.length / 2 + 1 )" [(ngModel)]="busyWeekDays[day]"> <mat-checkbox *ngFor="let day of weekDays.slice(weekDays.length / 2 + 1)" [(ngModel)]="busyWeekDays[day]">
{{ day }} {{ day }}
</mat-checkbox> </mat-checkbox>
</div> </div>
@ -19,32 +21,32 @@
<div class="time-fields"> <div class="time-fields">
<mat-form-field appearance="fill" class="time-field"> <mat-form-field appearance="fill" class="time-field">
<mat-label>Hora de inicio</mat-label> <mat-label>{{ 'startTime' | translate }}</mat-label>
<input matInput [(ngModel)]="busyFromHour" type="time" placeholder="Selecciona la hora de inicio" [required]="!isRemoteAvailable"> <input matInput [(ngModel)]="busyFromHour" type="time" placeholder="{{ 'startTimePlaceholder' | translate }}" [required]="!isRemoteAvailable">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="time-field"> <mat-form-field appearance="fill" class="time-field">
<mat-label>Hora de fin</mat-label> <mat-label>{{ 'endTime' | translate }}</mat-label>
<input matInput [(ngModel)]="busyToHour" type="time" placeholder="Selecciona la hora de fin" [required]="!isRemoteAvailable"> <input matInput [(ngModel)]="busyToHour" type="time" placeholder="{{ 'endTimePlaceholder' | translate }}" [required]="!isRemoteAvailable">
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
<div *ngIf="isRemoteAvailable" class="form-group"> <div *ngIf="isRemoteAvailable" class="form-group">
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label>Razón</mat-label> <mat-label>{{ 'reasonLabel' | translate }}</mat-label>
<input matInput [(ngModel)]="availableReason" placeholder="Razon para la excepción" [required]="isRemoteAvailable"> <input matInput [(ngModel)]="availableReason" placeholder="{{ 'reasonPlaceholder' | translate }}" [required]="isRemoteAvailable">
</mat-form-field> </mat-form-field>
<div class="time-fields"> <div class="time-fields">
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label>Fecha de inicio</mat-label> <mat-label>{{ 'startDate' | translate }}</mat-label>
<input matInput [matDatepicker]="picker1" [(ngModel)]="availableFromDate" [required]="isRemoteAvailable"> <input matInput [matDatepicker]="picker1" [(ngModel)]="availableFromDate" [required]="isRemoteAvailable">
<mat-hint>MM/DD/YYYY</mat-hint> <mat-hint>MM/DD/YYYY</mat-hint>
<mat-datepicker-toggle matIconSuffix [for]="picker1"></mat-datepicker-toggle> <mat-datepicker-toggle matIconSuffix [for]="picker1"></mat-datepicker-toggle>
<mat-datepicker #picker1></mat-datepicker> <mat-datepicker #picker1></mat-datepicker>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label>Fecha de fin</mat-label> <mat-label>{{ 'endDate' | translate }}</mat-label>
<input matInput [matDatepicker]="picker2" [(ngModel)]="availableToDate" [required]="isRemoteAvailable"> <input matInput [matDatepicker]="picker2" [(ngModel)]="availableToDate" [required]="isRemoteAvailable">
<mat-hint>MM/DD/YYYY</mat-hint> <mat-hint>MM/DD/YYYY</mat-hint>
<mat-datepicker-toggle matIconSuffix [for]="picker2"></mat-datepicker-toggle> <mat-datepicker-toggle matIconSuffix [for]="picker2"></mat-datepicker-toggle>
@ -55,12 +57,12 @@
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button (click)="onNoClick()">Cancelar</button> <button mat-button (click)="onNoClick()">{{ 'buttonCancel' | translate }}</button>
<button <button
mat-button mat-button
(click)="submitRule()" (click)="submitRule()"
cdkFocusInitial cdkFocusInitial
[disabled]="(!isRemoteAvailable && (!busyFromHour || !busyToHour)) || (isRemoteAvailable && (!availableReason || !availableFromDate || !availableToDate))"> [disabled]="(!isRemoteAvailable && (!busyFromHour || !busyToHour)) || (isRemoteAvailable && (!availableReason || !availableFromDate || !availableToDate))">
{{ isEditMode ? 'Guardar' : 'Añadir' }} {{ isEditMode ? ('buttonSave' | translate) : ('buttonAdd' | translate) }}
</button> </button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,15 +1,16 @@
<h2 mat-dialog-title>{{ isEditMode ? 'Editar' : 'Añadir' }} calendario</h2> <h2 mat-dialog-title>{{ isEditMode ? ('editCalendar' | translate) : ('addCalendar' | translate) }}</h2>
<mat-dialog-content class="form-container"> <mat-dialog-content class="form-container">
<!-- Campo para el nombre --> <!-- Campo para el nombre -->
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label>Nombre</mat-label> <mat-label>{{ 'labelName' | translate }}</mat-label>
<input matInput [(ngModel)]="name" required> <input matInput [(ngModel)]="name" required>
<mat-icon *ngIf="isEditMode" matSuffix (click)="submitForm()">mode_edit</mat-icon> <mat-icon *ngIf="isEditMode" matSuffix (click)="submitForm()">mode_edit</mat-icon>
</mat-form-field> </mat-form-field>
<div style="display: flex; justify-content: space-between; align-items: center;"> <div style="display: flex; justify-content: space-between; align-items: center;">
<div *ngIf="isEditMode" mat-subheader>Reglas</div> <div *ngIf="isEditMode" mat-subheader>{{ 'rulesHeader' | translate }}</div>
<button mat-flat-button color="primary" *ngIf="isEditMode" (click)="createRule()" style="padding: 10px;"> <button mat-flat-button color="primary" *ngIf="isEditMode" (click)="createRule()" style="padding: 10px;">
Añadir regla {{ 'addRule' | translate }}
</button> </button>
</div> </div>
@ -21,16 +22,16 @@
<div class="list-item-content"> <div class="list-item-content">
<mat-icon matListItemIcon>event_available</mat-icon> <mat-icon matListItemIcon>event_available</mat-icon>
<div class="text-content"> <div class="text-content">
<div matListItemTitle>{{ rule.isRemoteAvailable ? 'Disponible' : 'No disponible ( periodo presencial )' }}</div> <div matListItemTitle>{{ rule.isRemoteAvailable ? ('statusAvailable' | translate) : ('statusUnavailable' | translate) }}</div>
<div matListItemLine *ngIf="!rule.isRemoteAvailable">{{ rule.busyFromHour }} - {{ rule.busyToHour }}</div> <div matListItemLine *ngIf="!rule.isRemoteAvailable">{{ rule.busyFromHour }} - {{ rule.busyToHour }}</div>
<div matListItemLine *ngIf="!rule.isRemoteAvailable">{{ rule.busyWeekDaysMap }}</div> <div matListItemLine *ngIf="!rule.isRemoteAvailable">{{ rule.busyWeekDaysMap }}</div>
<div matListItemLine *ngIf="rule.isRemoteAvailable">{{ rule.availableReason }} | {{ rule.availableFromDate | date }} - {{ rule.availableToDate | date }}</div> <div matListItemLine *ngIf="rule.isRemoteAvailable">{{ rule.availableReason }} | {{ rule.availableFromDate | date }} - {{ rule.availableToDate | date }}</div>
</div> </div>
<div class="icon-container"> <div class="icon-container">
<button mat-icon-button color="primary" class="right-icon" (click)="createRule(rule)" i18n="@@editImage"> <button mat-icon-button color="primary" class="right-icon" (click)="createRule(rule)">
<mat-icon>edit</mat-icon> <mat-icon>edit</mat-icon>
</button> </button>
<button mat-icon-button color="warn" class="right-icon" (click)="deleteCalendarRule(rule)" > <button mat-icon-button color="warn" class="right-icon" (click)="deleteCalendarRule(rule)">
<mat-icon>delete</mat-icon> <mat-icon>delete</mat-icon>
</button> </button>
</div> </div>
@ -41,6 +42,8 @@
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button (click)="onNoClick()">Cancelar</button> <button mat-button (click)="onNoClick()">{{ 'buttonCancel' | translate }}</button>
<button mat-button (click)="submitForm()" [disabled]="!name || name === ''" cdkFocusInitial> Guardar </button> <button mat-button (click)="submitForm()" [disabled]="!name || name === ''" cdkFocusInitial>
{{ 'buttonSave' | translate }}
</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,25 +1,49 @@
<div class="header-container"> <div class="header-container">
<<<<<<< Updated upstream
<h2 class="title" i18n="@@adminCommandGroupsTitle">Administrar Grupos de Comandos</h2> <h2 class="title" i18n="@@adminCommandGroupsTitle">Administrar Grupos de Comandos</h2>
<div class="command-groups-button-row"> <div class="command-groups-button-row">
<button mat-flat-button color="primary" (click)="openCreateCommandGroupModal()">Añadir Grupo de Comandos</button> <button mat-flat-button color="primary" (click)="openCreateCommandGroupModal()">Añadir Grupo de Comandos</button>
=======
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<h2 class="title" joyrideStep="titleStep" text="{{ 'titleStepText' | translate }}">{{ 'adminCommandGroupsTitle' | translate }}</h2>
<div class="command-groups-button-row">
<button mat-flat-button color="primary" (click)="openCreateCommandGroupModal()" joyrideStep="addCommandGroupStep" text="{{ 'addCommandGroupStepText' | translate }}">
{{ 'addCommandGroup' | translate }}
</button>
>>>>>>> Stashed changes
</div> </div>
</div> </div>
<mat-divider class="divider"></mat-divider> <mat-divider class="divider"></mat-divider>
<<<<<<< Updated upstream
<div class="search-container"> <div class="search-container">
=======
<div class="search-container" joyrideStep="searchStep" text="{{ 'searchStepText' | translate }}">
>>>>>>> Stashed changes
<mat-form-field appearance="fill" class="search-string"> <mat-form-field appearance="fill" class="search-string">
<mat-label i18n="@@searchLabel">Buscar nombre de grupo</mat-label> <mat-label>{{ 'searchGroupNameLabel' | translate }}</mat-label>
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder"> <input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()">
<mat-icon matSuffix>search</mat-icon> <mat-icon matSuffix>search</mat-icon>
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint> <mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<<<<<<< Updated upstream
<div *ngIf="loading" class="loading-container"> <div *ngIf="loading" class="loading-container">
=======
<div *ngIf="loading" class="loading-container" joyrideStep="loadingStep" text="{{ 'loadingStepText' | translate }}">
>>>>>>> Stashed changes
<mat-spinner></mat-spinner> <mat-spinner></mat-spinner>
</div> </div>
<div *ngIf="!loading"> <div *ngIf="!loading">
<<<<<<< Updated upstream
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
=======
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" joyrideStep="tableStep" text="{{ 'tableStepText' | translate }}">
>>>>>>> Stashed changes
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef"> <ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th> <th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
<td mat-cell *matCellDef="let commandGroup"> <td mat-cell *matCellDef="let commandGroup">
@ -27,8 +51,13 @@
{{ column.cell(commandGroup) }} {{ column.cell(commandGroup) }}
</ng-container> </ng-container>
<<<<<<< Updated upstream
<ng-container *ngIf="column.columnDef === 'commands'"> <ng-container *ngIf="column.columnDef === 'commands'">
<button mat-button [matMenuTriggerFor]="menu">Ver comandos</button> <button mat-button [matMenuTriggerFor]="menu">Ver comandos</button>
=======
<ng-container *ngIf="column.columnDef === 'commands'" joyrideStep="viewCommandsStep" text="{{ 'viewCommandsStepText' | translate }}">
<button mat-button [matMenuTriggerFor]="menu">{{ 'viewCommands' | translate }}</button>
>>>>>>> Stashed changes
<mat-menu #menu="matMenu"> <mat-menu #menu="matMenu">
<button mat-menu-item *ngFor="let command of commandGroup.commands"> <button mat-menu-item *ngFor="let command of commandGroup.commands">
{{ command.name }} {{ command.name }}
@ -38,12 +67,23 @@
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<<<<<<< Updated upstream
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th> <th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
<td mat-cell *matCellDef="let client" style="text-align: center;"> <td mat-cell *matCellDef="let client" style="text-align: center;">
<button mat-icon-button color="info" (click)="viewGroupDetails(client)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button> <button mat-icon-button color="info" (click)="viewGroupDetails(client)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button>
<button mat-icon-button color="primary" (click)="editCommandGroup(client)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button> <button mat-icon-button color="primary" (click)="editCommandGroup(client)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
=======
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
<td mat-cell *matCellDef="let client" style="text-align: center;" joyrideStep="actionsStep" text="{{ 'actionsStepText' | translate }}">
<button mat-icon-button color="info" (click)="viewGroupDetails(client)">
<mat-icon>visibility</mat-icon>
</button>
<button mat-icon-button color="primary" (click)="editCommandGroup(client)">
<mat-icon>edit</mat-icon>
</button>
>>>>>>> Stashed changes
<button mat-icon-button color="warn" (click)="deleteCommandGroup(client)"> <button mat-icon-button color="warn" (click)="deleteCommandGroup(client)">
<mat-icon i18n="@@deleteElementTooltip">delete</mat-icon> <mat-icon>delete</mat-icon>
</button> </button>
</td> </td>
</ng-container> </ng-container>
@ -53,7 +93,11 @@
</table> </table>
</div> </div>
<<<<<<< Updated upstream
<div class="paginator-container"> <div class="paginator-container">
=======
<div class="paginator-container" joyrideStep="paginationStep" text="{{ 'paginationStepText' | translate }}">
>>>>>>> Stashed changes
<mat-paginator [length]="length" <mat-paginator [length]="length"
[pageSize]="itemsPerPage" [pageSize]="itemsPerPage"
[pageIndex]="page" [pageIndex]="page"

View File

@ -1,4 +1,4 @@
<h2 mat-dialog-title>{{ editing ? 'Editar' : 'Crear' }} grupo de comando</h2> <h2 mat-dialog-title>{{ editing ? ('editCommandGroup' | translate) : ('createCommandGroup' | translate) }}</h2>
<mat-dialog-content class="form-container"> <mat-dialog-content class="form-container">
<div *ngIf="loading" class="loading-container"> <div *ngIf="loading" class="loading-container">
<mat-spinner></mat-spinner> <mat-spinner></mat-spinner>
@ -6,24 +6,24 @@
<form *ngIf="!loading" class="command-group-form" (ngSubmit)="onSubmit()"> <form *ngIf="!loading" class="command-group-form" (ngSubmit)="onSubmit()">
<mat-form-field> <mat-form-field>
<mat-label>Nombre del Grupo</mat-label> <mat-label>{{ 'groupNameLabel' | translate }}</mat-label>
<input matInput [(ngModel)]="groupName" name="groupName" required /> <input matInput [(ngModel)]="groupName" name="groupName" required />
</mat-form-field> </mat-form-field>
<mat-slide-toggle [(ngModel)]="enabled" name="enabled">Habilitado</mat-slide-toggle> <mat-slide-toggle [(ngModel)]="enabled" name="enabled">{{ 'enabledToggle' | translate }}</mat-slide-toggle>
<div class="command-selection"> <div class="command-selection">
<div class="available-commands"> <div class="available-commands">
<h3>Comandos Disponibles</h3> <h3>{{ 'availableCommandsTitle' | translate }}</h3>
<div class="table-wrapper"> <div class="table-wrapper">
<table mat-table [dataSource]="availableCommands" class="mat-elevation-z8"> <table mat-table [dataSource]="availableCommands" class="mat-elevation-z8">
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Nombre </th> <th mat-header-cell *matHeaderCellDef> {{ 'nameColumn' | translate }} </th>
<td mat-cell *matCellDef="let command"> {{ command.name }} </td> <td mat-cell *matCellDef="let command"> {{ command.name }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Acciones </th> <th mat-header-cell *matHeaderCellDef> {{ 'actionsColumn' | translate }} </th>
<td mat-cell *matCellDef="let command"> <td mat-cell *matCellDef="let command">
<button mat-icon-button type="button" (click)="addCommand(command)"> <button mat-icon-button type="button" (click)="addCommand(command)">
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
@ -38,8 +38,13 @@
</div> </div>
<div class="selected-commands"> <div class="selected-commands">
<<<<<<< Updated upstream
<h3>Comandos Seleccionados</h3> <h3>Comandos Seleccionados</h3>
<div class="selected-commands-list"> <div class="selected-commands-list">
=======
<h3>{{ 'selectedCommandsTitle' | translate }}</h3>
<div class="selected-commands-list" cdkDropList (cdkDropListDropped)="drop($event)">
>>>>>>> Stashed changes
<div class="commands-container"> <div class="commands-container">
<ng-container *ngFor="let command of selectedCommands; let last = last"> <ng-container *ngFor="let command of selectedCommands; let last = last">
<div class="command-item"> <div class="command-item">
@ -58,6 +63,6 @@
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button (click)="close()">Cancelar</button> <button mat-button (click)="close()">{{ 'buttonCancel' | translate }}</button>
<button mat-button (click)="onSubmit()" cdkFocusInitial> Guardar </button> <button mat-button (click)="onSubmit()" cdkFocusInitial>{{ 'buttonSave' | translate }}</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,5 +1,5 @@
<div class="detail-command-group-container"> <div class="detail-command-group-container">
<h2>Detalles del Grupo de Comandos</h2> <h2>{{ 'commandGroupDetailsTitle' | translate }}</h2>
<!-- Indicador de carga --> <!-- Indicador de carga -->
<div *ngIf="loading" class="loading-container"> <div *ngIf="loading" class="loading-container">
@ -9,17 +9,17 @@
<mat-card *ngIf="!loading"> <mat-card *ngIf="!loading">
<mat-card-header> <mat-card-header>
<mat-card-title>{{ data.name }}</mat-card-title> <mat-card-title>{{ data.name }}</mat-card-title>
<mat-card-subtitle>Creado por: {{ data.createdBy }}</mat-card-subtitle> <mat-card-subtitle>{{ 'createdBy' | translate }}: {{ data.createdBy }}</mat-card-subtitle>
</mat-card-header> </mat-card-header>
<mat-card-content> <mat-card-content>
<p><strong>ID del Grupo:</strong> {{ data.uuid }}</p> <p><strong>{{ 'groupId' | translate }}:</strong> {{ data.uuid }}</p>
<p><strong>Fecha de Creación:</strong> {{ data.createdAt | date:'short' }}</p> <p><strong>{{ 'creationDate' | translate }}:</strong> {{ data.createdAt | date:'short' }}</p>
<h3>Comandos Incluidos:</h3> <h3>{{ 'includedCommands' | translate }}</h3>
<table mat-table [dataSource]="data.commands" class="mat-elevation-z8"> <table mat-table [dataSource]="data.commands" class="mat-elevation-z8">
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Nombre </th> <th mat-header-cell *matHeaderCellDef> {{ 'nameColumn' | translate }} </th>
<td mat-cell *matCellDef="let command"> {{ command.name }} </td> <td mat-cell *matCellDef="let command"> {{ command.name }} </td>
</ng-container> </ng-container>
@ -37,16 +37,16 @@
<!-- Sección para seleccionar clientes --> <!-- Sección para seleccionar clientes -->
<div class="additional-section" *ngIf="showClientSelect && !loading"> <div class="additional-section" *ngIf="showClientSelect && !loading">
<form [formGroup]="form"> <form [formGroup]="form">
<h4>Selecciona los clientes:</h4> <h4>{{ 'selectClients' | translate }}</h4>
<mat-form-field appearance="fill"> <mat-form-field appearance="fill">
<mat-label>Clientes</mat-label> <mat-label>{{ 'clientsLabel' | translate }}</mat-label>
<mat-select formControlName="selectedClients" multiple (selectionChange)="onClientSelectionChange($event)"> <mat-select formControlName="selectedClients" multiple (selectionChange)="onClientSelectionChange($event)">
<mat-option *ngFor="let client of clients" [value]="client.uuid"> <mat-option *ngFor="let client of clients" [value]="client.uuid">
{{ client.name }} {{ client.name }}
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error *ngIf="form.get('selectedClients')?.invalid && form.get('selectedClients')?.touched"> <mat-error *ngIf="form.get('selectedClients')?.invalid && form.get('selectedClients')?.touched">
Debes seleccionar al menos un cliente. {{ 'selectAtLeastOneClient' | translate }}
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
</form> </form>
@ -54,8 +54,8 @@
<div class="command-group-actions" *ngIf="!loading"> <div class="command-group-actions" *ngIf="!loading">
<button mat-flat-button color="primary" (click)="toggleClientSelect()"> <button mat-flat-button color="primary" (click)="toggleClientSelect()">
{{ showClientSelect ? 'Ejecutar' : 'Programar Ejecución' }} {{ showClientSelect ? ('execute' | translate) : ('scheduleExecution' | translate) }}
</button> </button>
<button mat-flat-button color="warn" (click)="close()">Cancelar</button> <button mat-flat-button color="warn" (click)="close()">{{ 'buttonCancel' | translate }}</button>
</div> </div>
</div> </div>

View File

@ -1,18 +1,33 @@
<div class="header-container"> <div class="header-container">
<<<<<<< Updated upstream
<h2 class="title">Administrar Tareas</h2> <h2 class="title">Administrar Tareas</h2>
<div class="task-button-row"> <div class="task-button-row">
<button mat-flat-button color="primary" (click)="openCreateTaskModal()">Añadir Tarea</button> <button mat-flat-button color="primary" (click)="openCreateTaskModal()">Añadir Tarea</button>
=======
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<h2 class="title" joyrideStep="titleStep" text="{{ 'titleStepText' | translate }}">{{ 'manageTasksTitle' | translate }}</h2>
<div class="task-button-row">
<button mat-flat-button color="primary" (click)="openCreateTaskModal()" joyrideStep="addTaskStep" text="{{ 'addTaskStepText' | translate }}">
{{ 'addTask' | translate }}
</button>
>>>>>>> Stashed changes
</div> </div>
</div> </div>
<mat-divider class="divider"></mat-divider> <mat-divider class="divider"></mat-divider>
<<<<<<< Updated upstream
<div class="search-container"> <div class="search-container">
=======
<div class="search-container" joyrideStep="searchStep" text="{{ 'searchStepText' | translate }}">
>>>>>>> Stashed changes
<mat-form-field appearance="fill" class="search-string"> <mat-form-field appearance="fill" class="search-string">
<mat-label>Buscar tarea</mat-label> <mat-label>{{ 'searchTaskLabel' | translate }}</mat-label>
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" /> <input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()" />
<mat-icon matSuffix>search</mat-icon> <mat-icon matSuffix>search</mat-icon>
<mat-hint>Pulsar 'enter' para buscar</mat-hint> <mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
@ -21,39 +36,54 @@
</div> </div>
<div *ngIf="!loading"> <div *ngIf="!loading">
<<<<<<< Updated upstream
<table mat-table [dataSource]="tasks" class="mat-elevation-z8"> <table mat-table [dataSource]="tasks" class="mat-elevation-z8">
=======
<table mat-table [dataSource]="tasks" class="mat-elevation-z8" joyrideStep="tableStep" text="{{ 'tableStepText' | translate }}">
>>>>>>> Stashed changes
<ng-container matColumnDef="taskid"> <ng-container matColumnDef="taskid">
<th mat-header-cell *matHeaderCellDef> Id</th> <th mat-header-cell *matHeaderCellDef> {{ 'idColumn' | translate }} </th>
<td mat-cell *matCellDef="let task"> {{ task.id }} </td> <td mat-cell *matCellDef="let task"> {{ task.id }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="notes"> <ng-container matColumnDef="notes">
<th mat-header-cell *matHeaderCellDef> Info</th> <th mat-header-cell *matHeaderCellDef> {{ 'infoColumn' | translate }} </th>
<td mat-cell *matCellDef="let task"> {{ task.notes }} </td> <td mat-cell *matCellDef="let task"> {{ task.notes }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Creado por </th> <th mat-header-cell *matHeaderCellDef> {{ 'createdByColumn' | translate }} </th>
<td mat-cell *matCellDef="let task"> {{ task.createdBy }} </td> <td mat-cell *matCellDef="let task"> {{ task.createdBy }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="scheduledDate"> <ng-container matColumnDef="scheduledDate">
<th mat-header-cell *matHeaderCellDef> Fecha de Ejecución </th> <th mat-header-cell *matHeaderCellDef> {{ 'executionDateColumn' | translate }} </th>
<td mat-cell *matCellDef="let task"> {{ task.dateTime | date:'short' }} </td> <td mat-cell *matCellDef="let task"> {{ task.dateTime | date:'short' }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="enabled"> <ng-container matColumnDef="enabled">
<th mat-header-cell *matHeaderCellDef> Estado </th> <th mat-header-cell *matHeaderCellDef> {{ 'statusColumn' | translate }} </th>
<td mat-cell *matCellDef="let task"> {{ task.enabled ? 'Habilitado' : 'Deshabilitado' }} </td> <td mat-cell *matCellDef="let task"> {{ task.enabled ? ('enabled' | translate) : ('disabled' | translate) }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<<<<<<< Updated upstream
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th> <th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
<td mat-cell *matCellDef="let task" style="text-align: center;"> <td mat-cell *matCellDef="let task" style="text-align: center;">
<button mat-icon-button color="info" (click)="viewTaskDetails(task)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button> <button mat-icon-button color="info" (click)="viewTaskDetails(task)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button>
<button mat-icon-button color="primary" (click)="editTask(task)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button> <button mat-icon-button color="primary" (click)="editTask(task)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
=======
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
<td mat-cell *matCellDef="let task" style="text-align: center;" joyrideStep="actionsStep" text="{{ 'actionsStepText' | translate }}">
<button mat-icon-button color="info" (click)="viewTaskDetails(task)">
<mat-icon>visibility</mat-icon>
</button>
<button mat-icon-button color="primary" (click)="editTask(task)">
<mat-icon>edit</mat-icon>
</button>
>>>>>>> Stashed changes
<button mat-icon-button color="warn" (click)="deleteTask(task)"> <button mat-icon-button color="warn" (click)="deleteTask(task)">
<mat-icon i18n="@@deleteElementTooltip">delete</mat-icon> <mat-icon>delete</mat-icon>
</button> </button>
</td> </td>
</ng-container> </ng-container>
@ -63,7 +93,12 @@
</table> </table>
</div> </div>
<<<<<<< Updated upstream
<mat-paginator [length]="length" <mat-paginator [length]="length"
=======
<mat-paginator joyrideStep="paginationStep" text="{{ 'paginationStepText' | translate }}"
[length]="length"
>>>>>>> Stashed changes
[pageSize]="itemsPerPage" [pageSize]="itemsPerPage"
[pageSizeOptions]="pageSizeOptions" [pageSizeOptions]="pageSizeOptions"
(page)="onPageChange($event)"> (page)="onPageChange($event)">

View File

@ -1,4 +1,4 @@
<h2 mat-dialog-title class="dialog-title">{{ editing ? 'Editar Tarea' : 'Crear Tarea' }}</h2> <h2 mat-dialog-title class="dialog-title">{{ editing ? ('editTask' | translate) : ('createTask' | translate) }}</h2>
<form [formGroup]="taskForm" class="task-form"> <form [formGroup]="taskForm" class="task-form">
<mat-dialog-content> <mat-dialog-content>
@ -10,6 +10,7 @@
<textarea matInput formControlName="notes" placeholder="Ingresa tus notas aquí"></textarea> <textarea matInput formControlName="notes" placeholder="Ingresa tus notas aquí"></textarea>
</mat-form-field> </mat-form-field>
<<<<<<< Updated upstream
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label>Selecciona Comandos</mat-label> <mat-label>Selecciona Comandos</mat-label>
<mat-select formControlName="commandGroup" (selectionChange)="onCommandGroupChange()"> <mat-select formControlName="commandGroup" (selectionChange)="onCommandGroupChange()">
@ -84,6 +85,88 @@
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
=======
<h3 class="section-title">{{ 'informationSectionTitle' | translate }}</h3>
<mat-divider></mat-divider>
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'informationLabel' | translate }}</mat-label>
<textarea matInput formControlName="notes" placeholder="{{ 'notesPlaceholder' | translate }}"></textarea>
</mat-form-field>
<h3 class="section-title">{{ 'commandSelectionSectionTitle' | translate }}</h3>
<mat-divider></mat-divider>
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'selectCommandsLabel' | translate }}</mat-label>
<mat-select formControlName="commandGroup" (selectionChange)="onCommandGroupChange()">
<mat-option *ngFor="let group of availableCommandGroups" [value]="group.uuid">
{{ group.name }}
</mat-option>
</mat-select>
<mat-error *ngIf="taskForm.get('commandGroup')?.invalid">{{ 'requiredFieldError' | translate }}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'selectIndividualCommandsLabel' | translate }}</mat-label>
<mat-select formControlName="extraCommands" multiple>
<mat-option *ngFor="let command of availableIndividualCommands" [value]="command.uuid">
{{ command.name }}
</mat-option>
</mat-select>
</mat-form-field>
<h3 class="section-title">{{ 'executionDateTimeSectionTitle' | translate }}</h3>
<mat-divider></mat-divider>
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'executionDateLabel' | translate }}</mat-label>
<input matInput [matDatepicker]="picker" formControlName="date" placeholder="{{ 'selectDatePlaceholder' | translate }}">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
<mat-error *ngIf="taskForm.get('date')?.invalid">{{ 'requiredFieldError' | translate }}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'executionTimeLabel' | translate }}</mat-label>
<input matInput type="time" formControlName="time" placeholder="{{ 'selectTimePlaceholder' | translate }}">
<mat-error *ngIf="taskForm.get('time')?.invalid">{{ 'requiredFieldError' | translate }}</mat-error>
</mat-form-field>
<h3 class="section-title">{{ 'destinationSelectionSectionTitle' | translate }}</h3>
<mat-divider></mat-divider>
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'selectOrganizationalUnitLabel' | translate }}</mat-label>
<mat-select formControlName="organizationalUnit" (selectionChange)="onOrganizationalUnitChange()">
<mat-option *ngFor="let unit of availableOrganizationalUnits" [value]="unit['@id']">
{{ unit.name }}
</mat-option>
</mat-select>
<mat-error *ngIf="taskForm.get('organizationalUnit')?.invalid">{{ 'requiredFieldError' | translate }}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'selectClassroomLabel' | translate }}</mat-label>
<mat-select formControlName="selectedChild" (selectionChange)="onChildChange()">
<mat-option *ngFor="let child of selectedUnitChildren" [value]="child['@id']">
{{ child.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'selectClientsLabel' | translate }}</mat-label>
<mat-select formControlName="selectedClients" multiple>
<mat-option (click)="toggleSelectAll()" [selected]="areAllSelected()">
{{ 'selectAllClients' | translate }}
</mat-option>
<mat-option *ngFor="let client of selectedClients" [value]="client.uuid">
{{ client.name }} ({{ client.ip }})
</mat-option>
</mat-select>
</mat-form-field>
<div class="button-container">
<button mat-raised-button color="primary" (click)="saveTask()">{{ 'buttonSave' | translate }}</button>
</div>
>>>>>>> Stashed changes
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label>Selecciona Clientes</mat-label> <mat-label>Selecciona Clientes</mat-label>

View File

@ -1,56 +1,55 @@
<div class="detail-task-container"> <div class="detail-task-container">
<h2>Detalles de la Tarea</h2> <h2>{{ 'taskDetailsTitle' | translate }}</h2>
<mat-card> <mat-card>
<mat-card-header> <mat-card-header>
<mat-card-subtitle>Creado por: {{ task.createdBy }}</mat-card-subtitle> <mat-card-subtitle>{{ 'createdBy' | translate }}: {{ task.createdBy }}</mat-card-subtitle>
</mat-card-header> </mat-card-header>
<mat-card-content> <mat-card-content>
<p><strong>ID de la Tarea:</strong> {{ task.uuid }}</p> <p><strong>{{ 'taskId' | translate }}:</strong> {{ task.uuid }}</p>
<p><strong>Estado:</strong> {{ task.status }}</p> <p><strong>{{ 'status' | translate }}:</strong> {{ task.status }}</p>
<p><strong>Fecha de Creación:</strong> {{ task.createdAt | date: 'short' }}</p> <p><strong>{{ 'creationDate' | translate }}:</strong> {{ task.createdAt | date: 'short' }}</p>
<p><strong>Notas:</strong> {{ task.notes }}</p> <p><strong>{{ 'notes' | translate }}:</strong> {{ task.notes }}</p>
<h3>Grupos de Comandos Incluidos:</h3> <h3>{{ 'includedCommandGroups' | translate }}</h3>
<table mat-table [dataSource]="task.commandGroups" class="mat-elevation-z8"> <table mat-table [dataSource]="task.commandGroups" class="mat-elevation-z8">
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Grupo de Comandos </th> <th mat-header-cell *matHeaderCellDef> {{ 'commandGroupColumn' | translate }} </th>
<td mat-cell *matCellDef="let group"> {{ group.name }} </td> <td mat-cell *matCellDef="let group"> {{ group.name }} </td>
</ng-container>
<ng-container matColumnDef="uuid">
<th mat-header-cell *matHeaderCellDef> UUID </th>
<td mat-cell *matCellDef="let group"> {{ group.uuid }} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="['name', 'uuid']"></tr>
<tr mat-row *matRowDef="let row; columns: ['name', 'uuid'];"></tr>
</table>
<h3>{{ 'commandsToExecute' | translate }}</h3>
<div *ngFor="let group of task.commandGroups">
<p><strong>{{ 'group' | translate }}: </strong>{{ group.name }}</p>
<table mat-table [dataSource]="group.commands" class="mat-elevation-z8">
<ng-container matColumnDef="commandName">
<th mat-header-cell *matHeaderCellDef> {{ 'commandColumn' | translate }} </th>
<td mat-cell *matCellDef="let command"> {{ command.name }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="uuid"> <ng-container matColumnDef="commandUuid">
<th mat-header-cell *matHeaderCellDef> UUID </th> <th mat-header-cell *matHeaderCellDef> UUID </th>
<td mat-cell *matCellDef="let group"> {{ group.uuid }} </td> <td mat-cell *matCellDef="let command"> {{ command.uuid }} </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="['name', 'uuid']"></tr> <tr mat-header-row *matHeaderRowDef="['commandName', 'commandUuid']"></tr>
<tr mat-row *matRowDef="let row; columns: ['name', 'uuid'];"></tr> <tr mat-row *matRowDef="let row; columns: ['commandName', 'commandUuid'];"></tr>
</table> </table>
</div>
<h3>Comandos a ejecutar:</h3> </mat-card-content>
<div *ngFor="let group of task.commandGroups"> </mat-card>
<p><strong>Grupo: </strong>{{ group.name }}</p>
<table mat-table [dataSource]="group.commands" class="mat-elevation-z8"> <div class="task-actions">
<ng-container matColumnDef="commandName"> <button mat-flat-button class="cancel-button" (click)="closeDialog()">{{ 'buttonClose' | translate }}</button>
<th mat-header-cell *matHeaderCellDef> Comando </th>
<td mat-cell *matCellDef="let command"> {{ command.name }} </td>
</ng-container>
<ng-container matColumnDef="commandUuid">
<th mat-header-cell *matHeaderCellDef> UUID </th>
<td mat-cell *matCellDef="let command"> {{ command.uuid }} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="['commandName', 'commandUuid']"></tr>
<tr mat-row *matRowDef="let row; columns: ['commandName', 'commandUuid'];"></tr>
</table>
</div>
</mat-card-content>
</mat-card>
<div class="task-actions">
<button mat-flat-button class="cancel-button" (click)="closeDialog()">Cerrar</button>
</div>
</div> </div>
</div>

View File

@ -1,14 +1,30 @@
<div class="header-container"> <div class="header-container">
<<<<<<< Updated upstream
<h2 class="title" i18n="@@adminCommandsTitle">Trazas de comandos y procedimientos</h2> <h2 class="title" i18n="@@adminCommandsTitle">Trazas de comandos y procedimientos</h2>
<div class="images-button-row"> <div class="images-button-row">
<button mat-flat-button color="primary" (click)="resetFilters()">Reiniciar filtros</button> <button mat-flat-button color="primary" (click)="resetFilters()">Reiniciar filtros</button>
=======
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<h2 class="title" joyrideStep="titleStep" text="{{ 'titleStepText' | translate }}">{{ 'adminCommandsTitle' | translate }}</h2>
<div class="images-button-row">
<button mat-flat-button color="primary" (click)="resetFilters()" joyrideStep="resetFiltersStep" text="{{ 'resetFiltersStepText' | translate }}">
{{ 'resetFilters' | translate }}
</button>
>>>>>>> Stashed changes
</div> </div>
</div> </div>
<mat-divider class="divider"></mat-divider> <mat-divider class="divider"></mat-divider>
<div class="search-container"> <div class="search-container">
<<<<<<< Updated upstream
<mat-form-field appearance="fill" class="search-select"> <mat-form-field appearance="fill" class="search-select">
<input type="text" matInput [formControl]="clientControl" [matAutocomplete]="clientAuto" placeholder="Seleccione un cliente"> <input type="text" matInput [formControl]="clientControl" [matAutocomplete]="clientAuto" placeholder="Seleccione un cliente">
=======
<mat-form-field appearance="fill" class="search-select" joyrideStep="clientSelectStep" text="{{ 'clientSelectStepText' | translate }}">
<input type="text" matInput [formControl]="clientControl" [matAutocomplete]="clientAuto" placeholder="{{ 'selectClientPlaceholder' | translate }}">
>>>>>>> Stashed changes
<mat-autocomplete #clientAuto="matAutocomplete" [displayWith]="displayFnClient" (optionSelected)="onOptionClientSelected($event.option.value)"> <mat-autocomplete #clientAuto="matAutocomplete" [displayWith]="displayFnClient" (optionSelected)="onOptionClientSelected($event.option.value)">
<mat-option *ngFor="let client of filteredClients | async" [value]="client"> <mat-option *ngFor="let client of filteredClients | async" [value]="client">
{{ client.name }} {{ client.name }}
@ -16,8 +32,13 @@
</mat-autocomplete> </mat-autocomplete>
</mat-form-field> </mat-form-field>
<<<<<<< Updated upstream
<mat-form-field appearance="fill" class="search-select"> <mat-form-field appearance="fill" class="search-select">
<input type="text" matInput [formControl]="commandControl" [matAutocomplete]="commandAuto" placeholder="Seleccione un comando"> <input type="text" matInput [formControl]="commandControl" [matAutocomplete]="commandAuto" placeholder="Seleccione un comando">
=======
<mat-form-field appearance="fill" class="search-select" joyrideStep="commandSelectStep" text="{{ 'commandSelectStepText' | translate }}">
<input type="text" matInput [formControl]="commandControl" [matAutocomplete]="commandAuto" placeholder="{{ 'selectCommandPlaceholder' | translate }}">
>>>>>>> Stashed changes
<mat-autocomplete #commandAuto="matAutocomplete" [displayWith]="displayFnCommand" (optionSelected)="onOptionCommandSelected($event.option.value)"> <mat-autocomplete #commandAuto="matAutocomplete" [displayWith]="displayFnCommand" (optionSelected)="onOptionCommandSelected($event.option.value)">
<mat-option *ngFor="let command of filteredCommands | async" [value]="command"> <mat-option *ngFor="let command of filteredCommands | async" [value]="command">
{{ command.name }} {{ command.name }}
@ -33,7 +54,11 @@
<!-- Tabla de trazas --> <!-- Tabla de trazas -->
<div *ngIf="!loading"> <div *ngIf="!loading">
<<<<<<< Updated upstream
<table mat-table [dataSource]="traces" class="mat-elevation-z8"> <table mat-table [dataSource]="traces" class="mat-elevation-z8">
=======
<table mat-table [dataSource]="traces" class="mat-elevation-z8" joyrideStep="tableStep" text="{{ 'tableStepText' | translate }}">
>>>>>>> Stashed changes
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef"> <ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th> <th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
<td mat-cell *matCellDef="let trace"> <td mat-cell *matCellDef="let trace">
@ -46,7 +71,11 @@
</table> </table>
</div> </div>
<<<<<<< Updated upstream
<div class="paginator-container"> <div class="paginator-container">
=======
<div class="paginator-container" joyrideStep="paginationStep" text="{{ 'paginationStepText' | translate }}">
>>>>>>> Stashed changes
<mat-paginator [length]="length" <mat-paginator [length]="length"
[pageSize]="itemsPerPage" [pageSize]="itemsPerPage"
[pageIndex]="page" [pageIndex]="page"

View File

@ -1,26 +1,47 @@
<div class="header-container"> <div class="header-container">
<<<<<<< Updated upstream
<h2 class="title" i18n="@@adminCommandsTitle">Administrar Comandos</h2> <h2 class="title" i18n="@@adminCommandsTitle">Administrar Comandos</h2>
<div class="command-button-row"> <div class="command-button-row">
<button mat-flat-button color="primary" (click)="openCreateCommandModal()">Añadir Comando</button> <button mat-flat-button color="primary" (click)="openCreateCommandModal()">Añadir Comando</button>
=======
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<h2 class="title" joyrideStep="titleStep" text="{{ 'titleStepText' | translate }}">{{ 'adminCommandsTitle' | translate }}</h2>
<div class="command-button-row" joyrideStep="addCommandStep" text="{{ 'addCommandStepText' | translate }}">
<button mat-flat-button color="primary" (click)="openCreateCommandModal()">{{ 'addCommand' | translate }}</button>
>>>>>>> Stashed changes
</div> </div>
</div> </div>
<mat-divider class="divider"></mat-divider> <mat-divider class="divider"></mat-divider>
<<<<<<< Updated upstream
<div class="search-container"> <div class="search-container">
=======
<div class="search-container" joyrideStep="searchStep" text="{{ 'searchStepText' | translate }}">
>>>>>>> Stashed changes
<mat-form-field appearance="fill" class="search-string"> <mat-form-field appearance="fill" class="search-string">
<mat-label i18n="@@searchLabel">Buscar nombre de comando</mat-label> <mat-label>{{ 'searchCommandLabel' | translate }}</mat-label>
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder"> <input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()" />
<mat-icon matSuffix>search</mat-icon> <mat-icon matSuffix>search</mat-icon>
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint> <mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<<<<<<< Updated upstream
<div *ngIf="loading" class="loading-container"> <div *ngIf="loading" class="loading-container">
=======
<div *ngIf="loading" class="loading-container" joyrideStep="loadingStep" text="{{ 'loadingStepText' | translate }}">
>>>>>>> Stashed changes
<mat-spinner></mat-spinner> <mat-spinner></mat-spinner>
</div> </div>
<div *ngIf="!loading"> <div *ngIf="!loading">
<<<<<<< Updated upstream
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
=======
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" joyrideStep="tableStep" text="{{ 'tableStepText' | translate }}">
>>>>>>> Stashed changes
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef"> <ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th> <th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
<td mat-cell *matCellDef="let command"> <td mat-cell *matCellDef="let command">
@ -35,11 +56,20 @@
</ng-container> </ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<<<<<<< Updated upstream
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th> <th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
<td mat-cell *matCellDef="let client" style="text-align: center;"> <td mat-cell *matCellDef="let client" style="text-align: center;">
<button mat-icon-button color="info" (click)="viewDetails($event, client)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button> <button mat-icon-button color="info" (click)="viewDetails($event, client)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button>
<button mat-icon-button color="primary" (click)="editCommand($event, client)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button> <button mat-icon-button color="primary" (click)="editCommand($event, client)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
<button mat-icon-button color="warn" (click)="deleteCommand($event, client)"><mat-icon i18n="@@deleteElementTooltip">delete</mat-icon></button> <button mat-icon-button color="warn" (click)="deleteCommand($event, client)"><mat-icon i18n="@@deleteElementTooltip">delete</mat-icon></button>
=======
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
<td mat-cell *matCellDef="let command" style="text-align: center;" joyrideStep="actionsStep" text="{{ 'actionsStepText' | translate }}">
<button mat-icon-button color="info" (click)="executeCommand($event, command)"><mat-icon>play_arrow</mat-icon></button>
<button mat-icon-button color="info" (click)="viewDetails($event, command)"><mat-icon>visibility</mat-icon></button>
<button mat-icon-button color="primary" [disabled]="command.readOnly" (click)="editCommand($event, command)"><mat-icon>edit</mat-icon></button>
<button mat-icon-button color="warn" [disabled]="command.readOnly" (click)="deleteCommand($event, command)"><mat-icon>delete</mat-icon></button>
>>>>>>> Stashed changes
</td> </td>
</ng-container> </ng-container>
@ -48,7 +78,11 @@
</table> </table>
</div> </div>
<<<<<<< Updated upstream
<div class="paginator-container"> <div class="paginator-container">
=======
<div class="paginator-container" joyrideStep="paginationStep" text="{{ 'paginationStepText' | translate }}">
>>>>>>> Stashed changes
<mat-paginator [length]="length" <mat-paginator [length]="length"
[pageSize]="itemsPerPage" [pageSize]="itemsPerPage"
[pageIndex]="page" [pageIndex]="page"

View File

@ -1,30 +1,29 @@
<h2 mat-dialog-title>{{ commandId ? 'Editar' : 'Crear' }} Comando</h2> <h2 mat-dialog-title>{{ commandId ? ('editCommandTitle' | translate) : ('createCommandTitle' | translate) }}</h2>
<mat-dialog-content class="form-container"> <mat-dialog-content class="form-container">
<form [formGroup]="createCommandForm" (ngSubmit)="onSubmit()" class="command-form"> <form [formGroup]="createCommandForm" (ngSubmit)="onSubmit()" class="command-form">
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label>Nombre</mat-label> <mat-label>{{ 'nameLabel' | translate }}</mat-label>
<input matInput formControlName="name" placeholder="Nombre del comando" required> <input matInput formControlName="name" placeholder="{{ 'commandNamePlaceholder' | translate }}" required>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label>Script</mat-label> <mat-label>{{ 'scriptLabel' | translate }}</mat-label>
<textarea matInput formControlName="script" placeholder="Script del comando"></textarea> <textarea matInput formControlName="script" placeholder="{{ 'commandScriptPlaceholder' | translate }}"></textarea>
</mat-form-field> </mat-form-field>
<div class="checkbox-group"> <div class="checkbox-group">
<mat-checkbox formControlName="readOnly">Solo lectura</mat-checkbox> <mat-checkbox formControlName="readOnly">{{ 'readOnlyLabel' | translate }}</mat-checkbox>
<mat-checkbox formControlName="enabled">Habilitado</mat-checkbox> <mat-checkbox formControlName="enabled">{{ 'enabledLabel' | translate }}</mat-checkbox>
</div> </div>
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label>Comentarios</mat-label> <mat-label>{{ 'commentsLabel' | translate }}</mat-label>
<textarea matInput formControlName="comments" placeholder="Comentarios"></textarea> <textarea matInput formControlName="comments" placeholder="{{ 'commentsPlaceholder' | translate }}"></textarea>
</mat-form-field> </mat-form-field>
</form> </form>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button (click)="onCancel($event)">Cancelar</button> <button mat-button (click)="onCancel($event)">{{ 'buttonCancel' | translate }}</button>
<button mat-button (click)="onSubmit()" cdkFocusInitial> Guardar </button> <button mat-button (click)="onSubmit()" cdkFocusInitial>{{ 'buttonSave' | translate }}</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,29 +1,29 @@
<div class="modal-container"> <div class="modal-container">
<h3 class="modal-title">Detalles del Comando</h3> <h3 class="modal-title">{{ 'commandDetailsTitle' | translate }}</h3>
<div class="modal-content"> <div class="modal-content">
<p><strong>Nombre:</strong> {{ data.name }}</p> <p><strong>{{ 'nameLabel' | translate }}:</strong> {{ data.name }}</p>
<p><strong>Comentarios:</strong> {{ data.comments }}</p> <p><strong>{{ 'commentsLabel' | translate }}:</strong> {{ data.comments }}</p>
<p><strong>Creado por:</strong> {{ data.createdBy }}</p> <p><strong>{{ 'createdByLabel' | translate }}:</strong> {{ data.createdBy }}</p>
<p><strong>Fecha de Creación:</strong> {{ data.createdAt | date:'medium' }}</p> <p><strong>{{ 'creationDateLabel' | translate }}:</strong> {{ data.createdAt | date:'medium' }}</p>
<div class="script-display"> <div class="script-display">
<h4>Script:</h4> <h4>{{ 'scriptLabel' | translate }}:</h4>
<pre>{{ data.script }}</pre> <pre>{{ data.script }}</pre>
</div> </div>
</div> </div>
<div class="additional-section" *ngIf="showClientSelect"> <div class="additional-section" *ngIf="showClientSelect">
<form [formGroup]="form"> <form [formGroup]="form">
<h4>Selecciona los clientes:</h4> <h4>{{ 'selectClientsTitle' | translate }}</h4>
<mat-form-field appearance="fill"> <mat-form-field appearance="fill">
<mat-label>Clientes</mat-label> <mat-label>{{ 'clientsLabel' | translate }}</mat-label>
<mat-select formControlName="selectedClients" multiple (selectionChange)="onClientSelectionChange($event)"> <mat-select formControlName="selectedClients" multiple (selectionChange)="onClientSelectionChange($event)">
<mat-option *ngFor="let client of clients" [value]="client.uuid"> <mat-option *ngFor="let client of clients" [value]="client.uuid">
{{ client.name }} {{ client.name }}
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error *ngIf="form.get('selectedClients')?.invalid && form.get('selectedClients')?.touched"> <mat-error *ngIf="form.get('selectedClients')?.invalid && form.get('selectedClients')?.touched">
Debes seleccionar al menos un cliente. {{ 'selectAtLeastOneClientError' | translate }}
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
</form> </form>

View File

@ -0,0 +1,40 @@
<h2 mat-dialog-title>{{ 'executeCommandTitle' | translate }}</h2>
<mat-dialog-content class="form-container">
<form [formGroup]="form" class="command-form">
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'organizationalUnitLabel' | translate }}</mat-label>
<mat-select formControlName="unit">
<mat-option *ngFor="let unit of units" [value]="unit.uuid">{{ unit.name }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'subOrganizationalUnitLabel' | translate }}</mat-label>
<mat-select formControlName="childUnit">
<mat-option *ngFor="let child of childUnits" [value]="child.uuid">{{ child.name }}</mat-option>
</mat-select>
</mat-form-field>
<div class="checkbox-group">
<label>{{ 'clientsLabel' | translate }}</label>
<div *ngIf="clients.length > 0">
<mat-checkbox *ngFor="let client of clients"
(change)="toggleClientSelection(client.uuid)"
[checked]="form.get('clientSelection')?.value.includes(client.uuid)">
{{ client.name }}
</mat-checkbox>
</div>
<div *ngIf="clients.length === 0">
<p>{{ 'noClientsAvailable' | translate }}</p>
</div>
</div>
</form>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button (click)="closeModal()">{{ 'buttonCancel' | translate }}</button>
<button mat-button (click)="executeCommand()" [disabled]="!form.get('clientSelection')?.value.length">{{ 'buttonExecute' | translate }}</button>
</mat-dialog-actions>

View File

@ -1,9 +1,18 @@
<<<<<<< Updated upstream
<h2 class="title" i18n="@@searchTitle">Búsqueda avanzada</h2> <h2 class="title" i18n="@@searchTitle">Búsqueda avanzada</h2>
=======
<div class="header-container">
<h2 class="title">{{ 'searchTitle' | translate }}</h2>
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
</div>
>>>>>>> Stashed changes
<div class="container"> <div class="container">
<div class="header"> <div class="header">
<mat-form-field> <mat-form-field>
<mat-label i18n="@@selectFilterLabel">Seleccione filtro</mat-label> <mat-label>{{ 'selectFilterLabel' | translate }}</mat-label>
<mat-select (selectionChange)="loadSelectedFilter($event.value)"> <mat-select (selectionChange)="loadSelectedFilter($event.value)">
<mat-option *ngFor="let savedFilter of savedFilterNames" [value]="savedFilter"> <mat-option *ngFor="let savedFilter of savedFilterNames" [value]="savedFilter">
{{ savedFilter[0] }} {{ savedFilter[0] }}
@ -16,34 +25,49 @@
<div class="view-mode-buttons"> <div class="view-mode-buttons">
<button mat-button (click)="changeViewMode('grid')" [class.active]="viewMode === 'grid'"> <button mat-button (click)="changeViewMode('grid')" [class.active]="viewMode === 'grid'">
<mat-icon>grid_view</mat-icon> Cuadrícula <mat-icon>grid_view</mat-icon> {{ 'gridViewButton' | translate }}
</button> </button>
<button mat-button (click)="changeViewMode('list')" [class.active]="viewMode === 'list'"> <button mat-button (click)="changeViewMode('list')" [class.active]="viewMode === 'list'">
<mat-icon>list</mat-icon> Lista <mat-icon>list</mat-icon> {{ 'listViewButton' | translate }}
</button> </button>
</div> </div>
<div class="main-content"> <div class="main-content">
<div class="filters"> <div class="filters">
<mat-form-field> <mat-form-field>
<mat-label i18n="@@selectOptionLabel">Selecciona una opción</mat-label> <mat-label>{{ 'selectOptionLabel' | translate }}</mat-label>
<mat-select [(value)]="selectedFilter1" (selectionChange)="applyFilter()"> <mat-select [(value)]="selectedFilter1" (selectionChange)="applyFilter()">
<mat-option value="ou" i18n="@@organizationalUnitsOption">Unidades organizativas</mat-option> <mat-option value="ou">{{ 'organizationalUnitsOption' | translate }}</mat-option>
<mat-option value="client" i18n="@@clientsOption">Clientes</mat-option> <mat-option value="client">{{ 'clientsOption' | translate }}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="example-full-width"> <mat-form-field class="example-full-width">
<mat-label i18n="@@nameLabel">Nombre</mat-label> <mat-label>{{ 'nameLabel' | translate }}</mat-label>
<input matInput placeholder="Unidad organizativa" (input)="applyFilter()" [(ngModel)]="filterName" i18n-placeholder="@@namePlaceholder"> <input matInput placeholder="{{ 'namePlaceholder' | translate }}" (input)="applyFilter()" [(ngModel)]="filterName">
</mat-form-field> </mat-form-field>
<<<<<<< Updated upstream
<button mat-raised-button color="primary" (click)="toggleSelectAll()">Seleccionar/Deseleccionar Todos</button> <button mat-raised-button color="primary" (click)="toggleSelectAll()">Seleccionar/Deseleccionar Todos</button>
<button mat-raised-button color="primary" (click)="saveFilters()" i18n="@@saveFiltersButton">Guardar Filtros</button> <button mat-raised-button color="primary" (click)="saveFilters()" i18n="@@saveFiltersButton">Guardar Filtros</button>
<button mat-raised-button color="accent" (click)="sendActions()" i18n="@@sendFiltersButton" [disabled]="selectedElements.length === 0">Enviar Acción</button> <button mat-raised-button color="accent" (click)="sendActions()" i18n="@@sendFiltersButton" [disabled]="selectedElements.length === 0">Enviar Acción</button>
<button mat-flat-button color="primary" [disabled]="selectedElements.length === 0" (click)="onPxeBootFile()">Añadir fichero PXE</button> <button mat-flat-button color="primary" [disabled]="selectedElements.length === 0" (click)="onPxeBootFile()">Añadir fichero PXE</button>
=======
<button mat-raised-button color="primary" (click)="toggleSelectAll()">
{{ 'selectAllButton' | translate }}
</button>
<button mat-raised-button color="primary" (click)="saveFilters()">
{{ 'saveFiltersButton' | translate }}
</button>
<button mat-raised-button color="accent" (click)="sendActions()" [disabled]="selectedElements.length === 0">
{{ 'sendFiltersButton' | translate }}
</button>
<button mat-flat-button color="primary" [disabled]="selectedElements.length === 0" (click)="onPxeBootFile()">
{{ 'addPxeButton' | translate }}
</button>
>>>>>>> Stashed changes
</div> </div>
<div class="results"> <div class="results">
@ -59,8 +83,8 @@
<p class="result-ip" *ngIf="result.type === 'client'">{{ result.ip }}</p> <p class="result-ip" *ngIf="result.type === 'client'">{{ result.ip }}</p>
<p class="result-mac" *ngIf="result.type === 'client'">{{ result.mac }}</p> <p class="result-mac" *ngIf="result.type === 'client'">{{ result.mac }}</p>
<p class="result-status" *ngIf="result.type === 'client'">{{ result.status }}</p> <p class="result-status" *ngIf="result.type === 'client'">{{ result.status }}</p>
<p *ngIf="result.type !== 'client'" i18n="@@internalUnits" class="result-internal-units">Unidades internas: {{ result.children.length }}</p> <p *ngIf="result.type !== 'client'" class="result-internal-units">{{ 'internalUnits' | translate }}: {{ result.children.length }}</p>
<p *ngIf="result.type !== 'client'" i18n="@@clients" class="result-clients">Clientes: {{ result.clients.length }}</p> <p *ngIf="result.type !== 'client'" class="result-clients">{{ 'clients' | translate }}: {{ result.clients.length }}</p>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
</mat-grid-tile> </mat-grid-tile>
@ -89,7 +113,7 @@
</ng-container> </ng-container>
<ng-template #noResults> <ng-template #noResults>
<p i18n="@@noResultsMessage">No hay resultados para mostrar.</p> <p>{{ 'noResultsMessage' | translate }}</p>
</ng-template> </ng-template>
</div> </div>
</div> </div>

View File

@ -1,7 +1,7 @@
<div class="header-container"> <div class="header-container">
<h2 class="title" i18n="@@adminImagesTitle">Datos de cliente</h2> <h2 class="title">{{ 'clientDetailsTitle' | translate }}</h2>
<div class="calendar-button-row"> <div class="calendar-button-row">
<button mat-flat-button color="primary" [matMenuTriggerFor]="commandMenu">Comandos</button> <button mat-flat-button color="primary" [matMenuTriggerFor]="commandMenu">{{ 'commandsButton' | translate }}</button>
</div> </div>
<mat-menu #commandMenu="matMenu"> <mat-menu #commandMenu="matMenu">
<button mat-menu-item *ngFor="let command of commands" (click)="onCommandSelect(command)"> <button mat-menu-item *ngFor="let command of commands" (click)="onCommandSelect(command)">
@ -18,7 +18,7 @@
<div *ngIf="!loading" class="client-info"> <div *ngIf="!loading" class="client-info">
<div class="info-section"> <div class="info-section">
<mat-tab-group dynamicHeight> <mat-tab-group dynamicHeight>
<mat-tab label="Datos generales"> <mat-tab label="{{ 'generalDataTab' | translate }}">
<div class="two-column-table"> <div class="two-column-table">
<div class="table-row" *ngFor="let clientData of generalData"> <div class="table-row" *ngFor="let clientData of generalData">
<div class="column property">{{ clientData?.property }}</div> <div class="column property">{{ clientData?.property }}</div>
@ -26,7 +26,7 @@
</div> </div>
</div> </div>
</mat-tab> </mat-tab>
<mat-tab label="Propiedades de red"> <mat-tab label="{{ 'networkPropertiesTab' | translate }}">
<div class="two-column-table"> <div class="two-column-table">
<div class="table-row" *ngFor="let clientData of networkData"> <div class="table-row" *ngFor="let clientData of networkData">
<div class="column property">{{ clientData?.property }}</div> <div class="column property">{{ clientData?.property }}</div>
@ -38,21 +38,21 @@
</div> </div>
<div class="header-container"> <div class="header-container">
<h2 class="title" i18n="@@adminImagesTitle">Discos/Particiones</h2> <h2 class="title">{{ 'disksPartitionsTitle' | translate }}</h2>
</div> </div>
<div class="table-container"> <div class="table-container">
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef"> <ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th> <th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
<td mat-cell *matCellDef="let image" > <td mat-cell *matCellDef="let image">
<ng-container *ngIf="column.columnDef !== 'size'"> <ng-container *ngIf="column.columnDef !== 'size'">
{{ column.cell(image) }} {{ column.cell(image) }}
</ng-container> </ng-container>
<ng-container *ngIf="column.columnDef === 'size'"> <ng-container *ngIf="column.columnDef === 'size'">
<mat-chip color="primary" > <mat-chip color="primary">
{{ (image.size / 1024).toFixed(2) }} GB {{ (image.size / 1024).toFixed(2) }} GB
</mat-chip> </mat-chip>
</ng-container> </ng-container>
</td> </td>
</ng-container> </ng-container>
@ -65,7 +65,7 @@
<ng-container *ngIf="diskUsageData && diskUsageData.length > 0"> <ng-container *ngIf="diskUsageData && diskUsageData.length > 0">
<div class="charts-row"> <div class="charts-row">
<div *ngFor="let disk of diskUsageData" class="disk-usage"> <div *ngFor="let disk of diskUsageData" class="disk-usage">
<h3>Disco {{ disk.diskNumber }}</h3> <h3>{{ 'diskTitle' | translate }} {{ disk.diskNumber }}</h3>
<div class="chart"> <div class="chart">
<svg viewBox="0 0 36 36" class="circular-chart green"> <svg viewBox="0 0 36 36" class="circular-chart green">
<path class="circle-bg" <path class="circle-bg"
@ -80,8 +80,8 @@
<text x="18" y="20.35" class="percentage">{{ disk.percentage }}%</text> <text x="18" y="20.35" class="percentage">{{ disk.percentage }}%</text>
</svg> </svg>
</div> </div>
<p>Usado: {{ disk.used }} GB ({{ disk.percentage }}%)</p> <p>{{ 'diskUsedLabel' | translate }}: {{ disk.used }} GB ({{ disk.percentage }}%)</p>
<p>Total: {{ disk.total }} GB</p> <p>{{ 'diskTotalLabel' | translate }}: {{ disk.total }} GB</p>
</div> </div>
</div> </div>
</ng-container> </ng-container>

View File

@ -1,5 +1,21 @@
<<<<<<< Updated upstream
<h2 mat-dialog-title>Asistente de particionado</h2> <h2 mat-dialog-title>Asistente de particionado</h2>
=======
<div class="header-container">
<h2 class="title">{{ 'partitionAssistantTitle' | translate }}</h2>
<div class="subnets-button-row">
<button mat-flat-button color="primary" (click)="save()">{{ 'saveButton' | translate }}</button>
</div>
</div>
<mat-divider></mat-divider>
<div class="partition-assistant" *ngFor="let disk of disks; let i = index">
<div>
<label for="disk-number-{{i}}">{{ 'diskLabel' | translate }} {{ disk.diskNumber }}:</label>
<span class="disk-size"> {{ 'diskSizeLabel' | translate }}: {{ (disk.totalDiskSize / 1024).toFixed(2) }} GB</span>
</div>
>>>>>>> Stashed changes
<mat-dialog-content> <mat-dialog-content>
<div class="partition-assistant" *ngFor="let disk of disks; let i = index"> <div class="partition-assistant" *ngFor="let disk of disks; let i = index">
@ -64,7 +80,57 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<<<<<<< Updated upstream
</mat-dialog-content> </mat-dialog-content>
=======
<button mat-flat-button color="primary" (click)="addPartition(disk.diskNumber)"> + </button>
<table class="partition-table">
<thead>
<tr>
<th>{{ 'partitionColumn' | translate }}</th>
<th>{{ 'partitionTypeColumn' | translate }}</th>
<th>{{ 'partitionSizeColumn' | translate }}</th>
<th>{{ 'usageColumn' | translate }}</th>
<th>{{ 'formatColumn' | translate }}</th>
<th>{{ 'deleteColumn' | translate }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let partition of disk.partitions; let j = index">
<td>{{ partition.partitionNumber }}</td>
<td>
<select [(ngModel)]="partition.type">
<option value="NTFS">{{ 'ntfsOption' | translate }}</option>
<option value="LINUX">{{ 'linuxOption' | translate }}</option>
<option value="CACHE">{{ 'cacheOption' | translate }}</option>
</select>
</td>
<td>
<input
type="number"
[(ngModel)]="partition.size"
(input)="updatePartitionSize(disk.diskNumber, j, partition.size)"
/>
</td>
<td>
<input
type="number"
[(ngModel)]="partition.memoryUsage"
/>
</td>
<td>
<input type="checkbox" [(ngModel)]="partition.format" />
</td>
<td>
<button (click)="removePartition(disk.diskNumber, partition)" class="remove-btn">{{ 'deleteButton' | translate }}</button>
</td>
</tr>
</tbody>
</table>
</div>
>>>>>>> Stashed changes
<div *ngIf="errorMessage" class="error-message">{{ errorMessage }}</div> <div *ngIf="errorMessage" class="error-message">{{ errorMessage }}</div>

View File

@ -1,15 +1,15 @@
<h2>Asistente de imagenes en disco</h2> <h2>{{ 'diskImageAssistantTitle' | translate }}</h2>
<div *ngFor="let disk of disks" class="partition-assistant"> <div *ngFor="let disk of disks" class="partition-assistant">
<div class="header"> <div class="header">
<label>Disco {{ disk.diskNumber }}</label> <label>{{ 'diskLabel' | translate }} {{ disk.diskNumber }}</label>
</div> </div>
<table class="partition-table"> <table class="partition-table">
<thead> <thead>
<tr> <tr>
<th>Partición</th> <th>{{ 'partitionColumn' | translate }}</th>
<th>Imagen ISO</th> <th>{{ 'isoImageColumn' | translate }}</th>
<th>OgLive</th> <th>{{ 'ogliveColumn' | translate }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -17,7 +17,7 @@
<td>{{ partition.partitionNumber }}</td> <td>{{ partition.partitionNumber }}</td>
<td> <td>
<select [(ngModel)]="partition.associatedImageId" (change)="onImageSelected(partition, $event)" name="associatedImage-{{partition.partitionNumber}}"> <select [(ngModel)]="partition.associatedImageId" (change)="onImageSelected(partition, $event)" name="associatedImage-{{partition.partitionNumber}}">
<option value="">Seleccionar imagen</option> <option value="">{{ 'selectImageOption' | translate }}</option>
<option *ngFor="let image of availableImages" [value]="image['@id']"> <option *ngFor="let image of availableImages" [value]="image['@id']">
{{ image.name }} {{ image.name }}
</option> </option>
@ -25,7 +25,7 @@
</td> </td>
<td> <td>
<select (change)="onOgLiveSelected(partition, $event)"> <select (change)="onOgLiveSelected(partition, $event)">
<option value="">Seleccionar OgLive</option> <option value="">{{ 'selectOgLiveOption' | translate }}</option>
<option *ngFor="let ogLive of availableOgLives" [value]="ogLive">{{ ogLive }}</option> <option *ngFor="let ogLive of availableOgLives" [value]="ogLive">{{ ogLive }}</option>
</select> </select>
</td> </td>
@ -35,5 +35,5 @@
</div> </div>
<div class="actions"> <div class="actions">
<button mat-flat-button color="primary" (click)="saveAssociations()">Guardar Asociaciones</button> <button mat-flat-button color="primary" (click)="saveAssociations()">{{ 'saveAssociationsButton' | translate }}</button>
</div> </div>

View File

@ -1,3 +1,4 @@
<<<<<<< Updated upstream
<div class="header-container"> <div class="header-container">
<h2 class="title" i18n="@@adminImagesTitle">Administrar clientes</h2> <h2 class="title" i18n="@@adminImagesTitle">Administrar clientes</h2>
<div class="images-button-row"> <div class="images-button-row">
@ -33,6 +34,110 @@
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
=======
<div class="header-container">
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<h2 class="title">{{ 'adminImagesTitle' | translate }}</h2>
<div class="images-button-row">
<button mat-flat-button color="primary" (click)="resetFilters()">{{ 'resetFiltersButton' | translate }}</button>
<button mat-flat-button color="primary" (click)="addClient($event)">{{ 'addClientButton' | translate }}</button>
</div>
</div>
<mat-divider class="divider"></mat-divider>
<div class="search-container">
<mat-form-field appearance="fill" class="search-string">
<mat-label>{{ 'searchClientNameLabel' | translate }}</mat-label>
<input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()">
<mat-icon matSuffix>search</mat-icon>
<mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill" class="search-string">
<mat-label>{{ 'searchIPLabel' | translate }}</mat-label>
<input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['ip']" (keyup.enter)="search()">
<mat-icon matSuffix>search</mat-icon>
<mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill" class="search-string">
<mat-label>{{ 'searchMACLabel' | translate }}</mat-label>
<input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['mac']" (keyup.enter)="search()">
<mat-icon matSuffix>search</mat-icon>
<mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill" class="search-select">
<mat-label>{{ 'organizationalUnitLabel' | translate }}</mat-label>
<mat-select [(ngModel)]="filters['organizationalUnit.id']" (selectionChange)="search()">
<mat-option *ngFor="let unit of organizationalUnits" [value]="unit.id">
{{ unit.name }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div *ngIf="loading" class="loading-container">
<mat-spinner></mat-spinner>
</div>
<div *ngIf="!loading">
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef>{{ column.header | translate }}</th>
<td mat-cell *matCellDef="let client">
<ng-container *ngIf="column.columnDef === 'name'">
<div class="client-info">
<div class="client-name">{{ client.name }}</div>
<div class="client-ip">{{ client.ip }}</div>
<div class="client-mac">{{ client.mac }}</div>
</div>
</ng-container>
<ng-container *ngIf="column.columnDef === 'status'">
<mat-chip>{{ client.status | translate }}</mat-chip>
</ng-container>
<ng-container *ngIf="column.columnDef !== 'status' && column.columnDef !== 'name'">
{{ column.cell(client) }}
</ng-container>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef>{{ 'columnActions' | translate }}</th>
<td mat-cell *matCellDef="let client" style="text-align: center;">
<button *ngIf="!syncStatus" mat-icon-button color="primary" (click)="getStatus(client)">
<mat-icon>sync</mat-icon>
</button>
<button *ngIf="syncStatus" mat-icon-button color="primary">
<mat-spinner diameter="24"></mat-spinner>
</button>
<button mat-icon-button color="info" (click)="handleClientClick($event, client)">
<mat-icon>visibility</mat-icon>
</button>
<button mat-icon-button color="primary" (click)="onEditClick($event, client.uuid)">
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button color="warn" (click)="onDeleteClick($event, client)">
<mat-icon>delete</mat-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<div class="paginator-container">
<mat-paginator [length]="length"
[pageSize]="itemsPerPage"
[pageIndex]="page"
[pageSizeOptions]="pageSizeOptions"
(page)="onPageChange($event)">
</mat-paginator>
>>>>>>> Stashed changes
</div> </div>
<div *ngIf="!loading" class="loading-container"> <div *ngIf="!loading" class="loading-container">

View File

@ -1,19 +1,34 @@
<div class="header-container"> <div class="header-container">
<<<<<<< Updated upstream
<h2 class="title" i18n="@@adminImagesTitle">Administrar unidades organizativas</h2> <h2 class="title" i18n="@@adminImagesTitle">Administrar unidades organizativas</h2>
<div class="button-row"> <div class="button-row">
<button mat-flat-button color="primary" (click)="resetFilters()">Reiniciar filtros</button> <button mat-flat-button color="primary" (click)="resetFilters()">Reiniciar filtros</button>
<button mat-flat-button color="primary" (click)="addOrganizationalUnit($event)">Añadir OU</button> <button mat-flat-button color="primary" (click)="addOrganizationalUnit($event)">Añadir OU</button>
=======
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<h2 class="title">{{ 'adminOuTitle' | translate }}</h2>
<div class="button-row">
<button mat-flat-button color="primary" (click)="resetFilters()">{{ 'resetFiltersButton' | translate }}</button>
<button mat-flat-button color="primary" (click)="addOrganizationalUnit($event)">{{ 'addOUButton' | translate }}</button>
>>>>>>> Stashed changes
</div> </div>
</div> </div>
<mat-divider class="divider"></mat-divider> <mat-divider class="divider"></mat-divider>
<<<<<<< Updated upstream
=======
>>>>>>> Stashed changes
<div class="search-container"> <div class="search-container">
<mat-form-field appearance="fill" class="search-string"> <mat-form-field appearance="fill" class="search-string">
<mat-label i18n="@@searchLabel">Buscar nombre de OU</mat-label> <mat-label>{{ 'searchLabelOu' | translate }}</mat-label>
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder"> <input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()">
<mat-icon matSuffix>search</mat-icon> <mat-icon matSuffix>search</mat-icon>
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint> <mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="search-boolean"> <mat-form-field appearance="fill" class="search-boolean">
<<<<<<< Updated upstream
<mat-label i18n="@@searchLabel">Tipo</mat-label> <mat-label i18n="@@searchLabel">Tipo</mat-label>
<mat-select [(ngModel)]="filters['type']" (selectionChange)="search()" placeholder="Seleccionar opción" > <mat-select [(ngModel)]="filters['type']" (selectionChange)="search()" placeholder="Seleccionar opción" >
<mat-option [value]="''">Todos</mat-option> <mat-option [value]="''">Todos</mat-option>
@ -37,25 +52,69 @@
</ng-container> </ng-container>
<ng-container *ngIf="column.columnDef === 'type'" > <ng-container *ngIf="column.columnDef === 'type'" >
<mat-chip> {{ ou.type }} </mat-chip> <mat-chip> {{ ou.type }} </mat-chip>
=======
<mat-label>{{ 'typeLabel' | translate }}</mat-label>
<mat-select [(ngModel)]="filters['type']" (selectionChange)="search()">
<mat-option [value]="''">{{ 'allOption' | translate }}</mat-option>
<mat-option [value]="'organizational-unit'">{{ 'centerOption' | translate }}</mat-option>
<mat-option [value]="'classrooms-group'">{{ 'classroomsGroupOption' | translate }}</mat-option>
<mat-option [value]="'classroom'">{{ 'classroomOption' | translate }}</mat-option>
<mat-option [value]="'clients-group'">{{ 'clientsGroupOption' | translate }}</mat-option>
</mat-select>
</mat-form-field>
</div>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
<td mat-cell *matCellDef="let ou">
<ng-container *ngIf="column.columnDef !== 'available' && column.columnDef !== 'type'">
{{ column.cell(ou) }}
</ng-container>
<ng-container *ngIf="column.columnDef === 'available'">
<mat-chip *ngIf="ou.available" class="mat-chip-success">
<mat-icon class="calendar-ico">event_available</mat-icon>
</mat-chip>
<mat-chip *ngIf="!ou.available" class="mat-chip-error">
<mat-icon class="calendar-ico">event_busy</mat-icon>
</mat-chip>
</ng-container>
<ng-container *ngIf="column.columnDef === 'type'">
<mat-chip>{{ ou.type | translate }}</mat-chip>
>>>>>>> Stashed changes
</ng-container> </ng-container>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<<<<<<< Updated upstream
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th> <th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
<td mat-cell *matCellDef="let ou" style="text-align: center;"> <td mat-cell *matCellDef="let ou" style="text-align: center;">
<button mat-icon-button color="info" (click)="onShowClick($event, ou)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button> <button mat-icon-button color="info" (click)="onShowClick($event, ou)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button>
<button mat-icon-button color="primary" (click)="onEditClick($event, ou.uuid)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button> <button mat-icon-button color="primary" (click)="onEditClick($event, ou.uuid)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
<button mat-icon-button color="warn" (click)="onDeleteClick($event, ou)"><mat-icon>delete</mat-icon></button> <button mat-icon-button color="warn" (click)="onDeleteClick($event, ou)"><mat-icon>delete</mat-icon></button>
=======
<th mat-header-cell *matHeaderCellDef>{{ 'columnActions' | translate }}</th>
<td mat-cell *matCellDef="let ou">
<button mat-icon-button color="info" (click)="onShowClick($event, ou)">
<mat-icon>visibility</mat-icon>
</button>
<button mat-icon-button color="primary" (click)="onEditClick($event, ou.uuid)">
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button color="warn" (click)="onDeleteClick($event, ou)">
<mat-icon>delete</mat-icon>
</button>
>>>>>>> Stashed changes
<button mat-icon-button color="info" [matMenuTriggerFor]="menu"> <button mat-icon-button color="info" [matMenuTriggerFor]="menu">
<mat-icon>menu</mat-icon> <mat-icon>menu</mat-icon>
</button> </button>
<mat-menu #menu="matMenu"> <mat-menu #menu="matMenu">
<button mat-menu-item [disabled]="ou.type !== 'classroom'" (click)="roomMap(ou)"> <button mat-menu-item [disabled]="ou.type !== 'classroom'" (click)="roomMap(ou)">
<span i18n="@@viewTreeMenu">Plano de aula</span> {{ 'roomMapOption' | translate }}
</button> </button>
<button mat-menu-item [disabled]="ou.type !== 'organizational-unit'" (click)="onTreeClick(ou)"> <button mat-menu-item [disabled]="ou.type !== 'organizational-unit'" (click)="onTreeClick(ou)">
<span i18n="@@viewTreeMenu">Ver organigrama</span> {{ 'viewTreeMenu' | translate }}
</button> </button>
</mat-menu> </mat-menu>
</td> </td>
@ -64,6 +123,10 @@
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table> </table>
<<<<<<< Updated upstream
=======
>>>>>>> Stashed changes
<div class="paginator-container"> <div class="paginator-container">
<mat-paginator [length]="length" <mat-paginator [length]="length"
[pageSize]="itemsPerPage" [pageSize]="itemsPerPage"

View File

@ -183,9 +183,14 @@ mat-spinner {
.result-card { .result-card {
width: 100%; width: 100%;
max-width: 250px; max-width: 250px;
<<<<<<< Updated upstream
height: 250px; /* Fijo para mantener la forma cuadrada */ height: 250px; /* Fijo para mantener la forma cuadrada */
} }
=======
height: 250px;
}
>>>>>>> Stashed changes
.paginator-container { .paginator-container {
display: flex; display: flex;
justify-content: center; justify-content: center;

View File

@ -1,4 +1,5 @@
<mat-tab-group (selectedTabChange)="onTabChange($event)"> <mat-tab-group (selectedTabChange)="onTabChange($event)">
<<<<<<< Updated upstream
<mat-tab label="General"> <mat-tab label="General">
<div class="header-container"> <div class="header-container">
<h2 class="title" i18n="@@adminGroupsTitle">Administrar grupos</h2> <h2 class="title" i18n="@@adminGroupsTitle">Administrar grupos</h2>
@ -6,9 +7,22 @@
<button mat-flat-button color="primary" (click)="addOU($event)" i18n="@@newOrganizationalUnitButton">Nueva Unidad Organizativa</button> <button mat-flat-button color="primary" (click)="addOU($event)" i18n="@@newOrganizationalUnitButton">Nueva Unidad Organizativa</button>
<button mat-flat-button color="primary" (click)="addClient($event)" i18n="@@newClientButton">Nuevo Cliente</button> <button mat-flat-button color="primary" (click)="addClient($event)" i18n="@@newClientButton">Nuevo Cliente</button>
<button mat-raised-button (click)="openBottomSheet()" i18n="@@legendButton">Leyenda</button> <button mat-raised-button (click)="openBottomSheet()" i18n="@@legendButton">Leyenda</button>
=======
<mat-tab label="{{ 'generalTabLabel' | translate }}">
<div class="header-container" joyrideStep="tabsStep" text="{{ 'tabsStepText' | translate }}">
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<h2 class="title" joyrideStep="titleStep" text="{{ 'titleStepText' | translate }}">{{ 'adminGroupsTitle' | translate }}</h2>
<div class="groups-button-row" joyrideStep="addStep" text="{{ 'addStepText' | translate }}">
<button mat-flat-button color="primary" (click)="addOU($event)" matTooltip="{{ 'newOrganizationalUnitTooltip' | translate }}" matTooltipShowDelay="1000">{{ 'newOrganizationalUnitButton' | translate }}</button>
<button mat-flat-button color="primary" (click)="addClient($event)" matTooltipShowDelay="1000">{{ 'newClientButton' | translate }}</button>
<button mat-raised-button (click)="openBottomSheet()" joyrideStep="keyStep" text="{{ 'keyStepText' | translate }}" matTooltipShowDelay="1000">{{ 'legendButton' | translate }}</button>
>>>>>>> Stashed changes
</div> </div>
</div> </div>
<div class="groupLists-container"> <div class="groupLists-container">
<<<<<<< Updated upstream
<mat-card class="card unidad-card"> <mat-card class="card unidad-card">
<mat-card-title i18n="@@organizationalUnitTitle">Centros</mat-card-title> <mat-card-title i18n="@@organizationalUnitTitle">Centros</mat-card-title>
<mat-card-content> <mat-card-content>
@ -16,6 +30,14 @@
<mat-list *ngIf="!loading"> <mat-list *ngIf="!loading">
<mat-list-item *ngFor="let unidad of organizationalUnits" <mat-list-item *ngFor="let unidad of organizationalUnits"
[ngClass]="{'selected-item': unidad === selectedUnidad, 'clickable-item': true}" (click)="onSelectUnidad(unidad)"> [ngClass]="{'selected-item': unidad === selectedUnidad, 'clickable-item': true}" (click)="onSelectUnidad(unidad)">
=======
<mat-card class="card unidad-card" joyrideStep="unitStep" text="{{ 'unitStepText' | translate }}" matTooltipShowDelay="1000" matTooltipPosition="above">
<mat-card-title>{{ 'organizationalUnitTitle' | translate }}</mat-card-title>
<mat-card-content>
<mat-spinner *ngIf="loading"></mat-spinner>
<mat-list *ngIf="!loading">
<mat-list-item *ngFor="let unidad of organizationalUnits" [ngClass]="{'selected-item': unidad === selectedUnidad, 'clickable-item': true}" (click)="onSelectUnidad(unidad)">
>>>>>>> Stashed changes
<div class="item-content"> <div class="item-content">
<mat-icon>apartment</mat-icon> <mat-icon>apartment</mat-icon>
{{ unidad.name }} {{ unidad.name }}
@ -23,6 +45,7 @@
<mat-icon mat-button [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">more_vert</mat-icon> <mat-icon mat-button [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">more_vert</mat-icon>
<mat-menu #menu="matMenu"> <mat-menu #menu="matMenu">
<button mat-menu-item (click)="onTreeClick($event, unidad)"> <button mat-menu-item (click)="onTreeClick($event, unidad)">
<<<<<<< Updated upstream
<mat-icon <mat-icon
#tooltip="matTooltip" #tooltip="matTooltip"
matTooltip="Visualizar en forma de arbol" matTooltip="Visualizar en forma de arbol"
@ -30,8 +53,13 @@
i18n="@@viewTreeTooltip">account_tree i18n="@@viewTreeTooltip">account_tree
</mat-icon> </mat-icon>
<span i18n="@@viewTreeMenu">Ver organigrama</span> <span i18n="@@viewTreeMenu">Ver organigrama</span>
=======
<mat-icon matTooltip="{{ 'viewTreeTooltip' | translate }}" matTooltipHideDelay="0">account_tree</mat-icon>
<span>{{ 'viewTreeMenu' | translate }}</span>
>>>>>>> Stashed changes
</button> </button>
<button mat-menu-item (click)="onEditClick($event, unidad.type, unidad.uuid)"> <button mat-menu-item (click)="onEditClick($event, unidad.type, unidad.uuid)">
<<<<<<< Updated upstream
<mat-icon <mat-icon
#tooltip="matTooltip" #tooltip="matTooltip"
matTooltip="Editar unidad organizativa" matTooltip="Editar unidad organizativa"
@ -39,8 +67,13 @@
i18n="@@editUnitTooltip">edit i18n="@@editUnitTooltip">edit
</mat-icon> </mat-icon>
<span i18n="@@editUnitMenu">Editar</span> <span i18n="@@editUnitMenu">Editar</span>
=======
<mat-icon matTooltip="{{ 'editUnitTooltip' | translate }}" matTooltipHideDelay="0">edit</mat-icon>
<span>{{ 'editUnitMenu' | translate }}</span>
>>>>>>> Stashed changes
</button> </button>
<button mat-menu-item (click)="onShowClick($event, unidad)"> <button mat-menu-item (click)="onShowClick($event, unidad)">
<<<<<<< Updated upstream
<mat-icon <mat-icon
#tooltip="matTooltip" #tooltip="matTooltip"
matTooltip="Visualizar unidad organizativa" matTooltip="Visualizar unidad organizativa"
@ -48,8 +81,13 @@
i18n="@@viewUnitTool">visibility i18n="@@viewUnitTool">visibility
</mat-icon> </mat-icon>
<span i18n="@@viewUnitMenu">Visualizar datos</span> <span i18n="@@viewUnitMenu">Visualizar datos</span>
=======
<mat-icon matTooltip="{{ 'viewUnitTooltip' | translate }}" matTooltipHideDelay="0">visibility</mat-icon>
<span>{{ 'viewUnitMenu' | translate }}</span>
>>>>>>> Stashed changes
</button> </button>
<button mat-menu-item (click)="addOU($event, unidad)"> <button mat-menu-item (click)="addOU($event, unidad)">
<<<<<<< Updated upstream
<mat-icon <mat-icon
#tooltip="matTooltip" #tooltip="matTooltip"
matTooltip="Crear unidad organizativa interna" matTooltip="Crear unidad organizativa interna"
@ -57,8 +95,13 @@
i18n="@@addInternalUnitTool">add_home_work i18n="@@addInternalUnitTool">add_home_work
</mat-icon> </mat-icon>
<span i18n="@@addInternalUnitMenu">Añadir unidad organizativa</span> <span i18n="@@addInternalUnitMenu">Añadir unidad organizativa</span>
=======
<mat-icon matTooltip="{{ 'addInternalUnitTooltip' | translate }}" matTooltipHideDelay="0">add_home_work</mat-icon>
<span>{{ 'addInternalUnitMenu' | translate }}</span>
>>>>>>> Stashed changes
</button> </button>
<button mat-menu-item (click)="addClient($event, unidad)"> <button mat-menu-item (click)="addClient($event, unidad)">
<<<<<<< Updated upstream
<mat-icon <mat-icon
#tooltip="matTooltip" #tooltip="matTooltip"
matTooltip="Crear cliente en esta unidad organizativa" matTooltip="Crear cliente en esta unidad organizativa"
@ -66,6 +109,10 @@
i18n="@@addClientDevice">devices i18n="@@addClientDevice">devices
</mat-icon> </mat-icon>
<span i18n="@@addClientMenu">Crear cliente</span> <span i18n="@@addClientMenu">Crear cliente</span>
=======
<mat-icon matTooltip="{{ 'addClientTooltip' | translate }}" matTooltipHideDelay="0">devices</mat-icon>
<span>{{ 'addClientMenu' | translate }}</span>
>>>>>>> Stashed changes
</button> </button>
</mat-menu> </mat-menu>
</span> </span>
@ -74,10 +121,15 @@
</mat-list> </mat-list>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
<<<<<<< Updated upstream
<mat-card class="card elements-card"> <mat-card class="card elements-card">
=======
<mat-card class="card elements-card" joyrideStep="elementsStep" text="{{ 'elementsStepText' | translate }}" matTooltipShowDelay="1000" matTooltipPosition="above">
>>>>>>> Stashed changes
<mat-card-title> <mat-card-title>
<div class="title-with-breadcrumb"> <div class="title-with-breadcrumb">
<span i18n="@@internalElementsTitle"></span> <span>{{ 'internalElementsTitle' | translate }}</span>
<mat-card-subtitle> <mat-card-subtitle>
<ng-container *ngFor="let crumb of breadcrumb; let i = index"> <ng-container *ngFor="let crumb of breadcrumb; let i = index">
<a (click)="navigateToBreadcrumb(i)">{{ crumb }}</a> <a (click)="navigateToBreadcrumb(i)">{{ crumb }}</a>
@ -91,7 +143,7 @@
<mat-list *ngIf="!loadingChildren"> <mat-list *ngIf="!loadingChildren">
<div *ngIf="children.length === 0" class="empty-list"> <div *ngIf="children.length === 0" class="empty-list">
<mat-icon>info</mat-icon> <mat-icon>info</mat-icon>
<span i18n="@@noInternalElementsMessage">No hay elementos internos</span> <span>{{ 'noInternalElementsMessage' | translate }}</span>
</div> </div>
<mat-list-item *ngFor="let child of children" [ngClass]="{'selected-item': child === selectedUnidad, 'clickable-item': true}" (click)="onSelectChild(child)"> <mat-list-item *ngFor="let child of children" [ngClass]="{'selected-item': child === selectedUnidad, 'clickable-item': true}" (click)="onSelectChild(child)">
<div class="item-content"> <div class="item-content">
@ -108,24 +160,54 @@
<mat-icon mat-button [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">more_vert</mat-icon> <mat-icon mat-button [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">more_vert</mat-icon>
<mat-menu #menu="matMenu"> <mat-menu #menu="matMenu">
<button mat-menu-item (click)="onEditClick($event, child.type, child.uuid)"> <button mat-menu-item (click)="onEditClick($event, child.type, child.uuid)">
<<<<<<< Updated upstream
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Editar elemento" matTooltipHideDelay="0" i18n="@@editElementTooltip">edit</mat-icon> <mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Editar elemento" matTooltipHideDelay="0" i18n="@@editElementTooltip">edit</mat-icon>
<span i18n="@@editElementMenu">Editar</span> <span i18n="@@editElementMenu">Editar</span>
=======
<mat-icon matTooltip="{{ 'editElementTooltip' | translate }}" matTooltipHideDelay="0">edit</mat-icon>
<span>{{ 'editElementMenu' | translate }}</span>
>>>>>>> Stashed changes
</button> </button>
<button *ngIf="child.type !== 'client'" mat-menu-item (click)="onShowClick($event, child)"> <button *ngIf="child.type !== 'client'" mat-menu-item (click)="onShowClick($event, child)">
<<<<<<< Updated upstream
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Visualizar unidad organizativa" matTooltipHideDelay="0" i18n="@@viewUnitTooltip">visibility</mat-icon> <mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Visualizar unidad organizativa" matTooltipHideDelay="0" i18n="@@viewUnitTooltip">visibility</mat-icon>
<span i18n="@@viewUnitMenu">Visualizar datos</span> <span i18n="@@viewUnitMenu">Visualizar datos</span>
=======
<mat-icon matTooltip="{{ 'viewUnitTooltip' | translate }}" matTooltipHideDelay="0">visibility</mat-icon>
<span>{{ 'viewUnitMenu' | translate }}</span>
>>>>>>> Stashed changes
</button> </button>
<button *ngIf="child.type !== 'client'" mat-menu-item (click)="addOU($event, child)"> <button *ngIf="child.type !== 'client'" mat-menu-item (click)="addOU($event, child)">
<<<<<<< Updated upstream
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Crear unidad organizativa interna" matTooltipHideDelay="0" i18n="@@addInternalUnitTooltip">add_home_work</mat-icon> <mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Crear unidad organizativa interna" matTooltipHideDelay="0" i18n="@@addInternalUnitTooltip">add_home_work</mat-icon>
<span i18n="@@addInternalUnitMenu">Añadir unidad organizativa</span> <span i18n="@@addInternalUnitMenu">Añadir unidad organizativa</span>
=======
<mat-icon matTooltip="{{ 'addInternalUnitTooltip' | translate }}" matTooltipHideDelay="0">add_home_work</mat-icon>
<span>{{ 'addInternalUnitMenu' | translate }}</span>
>>>>>>> Stashed changes
</button> </button>
<button *ngIf="child.type !== 'client'" mat-menu-item (click)="addClient($event, child)"> <button *ngIf="child.type !== 'client'" mat-menu-item (click)="addClient($event, child)">
<<<<<<< Updated upstream
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Crear cliente en esta unidad organizativa" matTooltipHideDelay="0" i18n="@@addClientTooltip">devices</mat-icon> <mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Crear cliente en esta unidad organizativa" matTooltipHideDelay="0" i18n="@@addClientTooltip">devices</mat-icon>
<span i18n="@@addClientMenu">Crear cliente</span> <span i18n="@@addClientMenu">Crear cliente</span>
=======
<mat-icon matTooltip="{{ 'addClientTooltip' | translate }}" matTooltipHideDelay="0">devices</mat-icon>
<span>{{ 'addClientMenu' | translate }}</span>
>>>>>>> Stashed changes
</button> </button>
<button mat-menu-item (click)="onDeleteClick($event, child.uuid, child.name, child.type)"> <button mat-menu-item (click)="onDeleteClick($event, child.uuid, child.name, child.type)">
<<<<<<< Updated upstream
<mat-icon class="delete-icon" #tooltip="matTooltip" matTooltip="Borrar elemento" matTooltipHideDelay="0" i18n="@@deleteElementTooltip">delete</mat-icon> <mat-icon class="delete-icon" #tooltip="matTooltip" matTooltip="Borrar elemento" matTooltipHideDelay="0" i18n="@@deleteElementTooltip">delete</mat-icon>
<span i18n="@@deleteElementMenu">Borrar elemento</span> <span i18n="@@deleteElementMenu">Borrar elemento</span>
=======
<mat-icon matTooltip="{{ 'deleteElementTooltip' | translate }}" matTooltipHideDelay="0">delete</mat-icon>
<span>{{ 'deleteElementMenu' | translate }}</span>
</button>
<button mat-menu-item (click)="onExecuteCommand($event, child.uuid, child.name, child.type)">
<mat-icon matTooltip="{{ 'executeCommandTooltip' | translate }}" matTooltipHideDelay="0">play_arrow</mat-icon>
<span>{{ 'executeCommandMenu' | translate }}</span>
>>>>>>> Stashed changes
</button> </button>
</mat-menu> </mat-menu>
</div> </div>
@ -136,6 +218,7 @@
</mat-card> </mat-card>
</div> </div>
</mat-tab> </mat-tab>
<<<<<<< Updated upstream
<mat-tab i18n-label label="Búsqueda avanzada"> <mat-tab i18n-label label="Búsqueda avanzada">
<app-advanced-search></app-advanced-search> <app-advanced-search></app-advanced-search>
</mat-tab> </mat-tab>
@ -143,6 +226,18 @@
<app-client-tab-view #clientTab></app-client-tab-view> <app-client-tab-view #clientTab></app-client-tab-view>
</mat-tab> </mat-tab>
<mat-tab i18n-label label="Unidades organizativas"> <mat-tab i18n-label label="Unidades organizativas">
=======
<mat-tab label="{{ 'advancedSearchTabLabel' | translate }}">
<app-advanced-search></app-advanced-search>
</mat-tab>
<mat-tab label="{{ 'clientsTabLabel' | translate }}">
<app-client-tab-view #clientTab></app-client-tab-view>
</mat-tab>
<mat-tab label="{{ 'organizationalUnitsTabLabel' | translate }}">
>>>>>>> Stashed changes
<app-organizational-unit-tab-view #organizationalUnitTab></app-organizational-unit-tab-view> <app-organizational-unit-tab-view #organizationalUnitTab></app-organizational-unit-tab-view>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>

View File

@ -1,4 +1,4 @@
<h1 mat-dialog-title i18n="@@actions-modal-title">Acciones</h1> <h1 mat-dialog-title>{{ 'actionsModalTitle' | translate }}</h1>
<mat-dialog-content> <mat-dialog-content>
<div class="button-container"> <div class="button-container">

View File

@ -1,15 +1,15 @@
<mat-dialog-content class="classroom"> <mat-dialog-content class="classroom">
<div *ngFor="let group of groupedClients" class="classroom-group"> <div *ngFor="let group of groupedClients" class="classroom-group">
<div class="misc-clients"> <div class="misc-clients">
<div class="classroom-board" cdkDrag cdkDragBoundary=".classroom">Pizarra digital</div> <div class="classroom-board" cdkDrag cdkDragBoundary=".classroom">{{ 'digitalBoard' | translate }}</div>
<img mat-card-image src="assets/images/proyector.png" alt="Proyector" class="proyector-image" cdkDrag cdkDragBoundary=".classroom"/> <img mat-card-image src="assets/images/proyector.png" alt="{{ 'projectorAlt' | translate }}" class="proyector-image" cdkDrag cdkDragBoundary=".classroom"/>
</div> </div>
<div *ngFor="let row of group.clientRows" class="client-row"> <div *ngFor="let row of group.clientRows" class="client-row">
<div class="client-container" *ngFor="let client of row" cdkDrag [cdkDragFreeDragPosition]="client.dragPosition" (cdkDragMoved)="onDragMoved($event, client)" cdkDragBoundary=".classroom"> <div class="client-container" *ngFor="let client of row" cdkDrag [cdkDragFreeDragPosition]="client.dragPosition" (cdkDragMoved)="onDragMoved($event, client)" cdkDragBoundary=".classroom">
<div class="client-box" (dblclick)="handleClientClick(client)"> <div class="client-box" (dblclick)="handleClientClick(client)">
<mat-card appearance="outlined"> <mat-card appearance="outlined">
<div class="client-image-container"> <div class="client-image-container">
<img mat-card-image src="assets/images/client.png" alt="Client" class="client-image"/> <img mat-card-image src="assets/images/client.png" alt="{{ 'clientAlt' | translate }}" class="client-image"/>
<div class="client-info"> <div class="client-info">
<div class="client-name">{{ client.name }}</div> <div class="client-name">{{ client.name }}</div>
<div class="client-details"> <div class="client-details">
@ -24,5 +24,5 @@
</div> </div>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-raised-button color="primary" class="saveDisposition-btn" (click)="saveDisposition()">Guardar disposición</button> <button mat-raised-button color="primary" class="saveDisposition-btn" (click)="saveDisposition()">{{ 'saveDispositionButton' | translate }}</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,63 +1,56 @@
<h1 mat-dialog-title i18n="@@client-properties-title">Propiedades cliente</h1> <h1 mat-dialog-title>{{ 'clientPropertiesTitle' | translate }}</h1>
<mat-dialog-content> <mat-dialog-content>
<mat-tab-group dynamicHeight> <mat-tab-group dynamicHeight>
<mat-tab label="Datos generales"> <mat-tab label="{{ 'generalDataTab' | translate }}">
<table mat-table [dataSource]="generalData" class="mat-elevation-z8"> <table mat-table [dataSource]="generalData" class="mat-elevation-z8">
<ng-container matColumnDef="property"> <ng-container matColumnDef="property">
<th mat-header-cell *matHeaderCellDef class="fixed-column" i18n="@@property-header">Propiedad</th> <th mat-header-cell *matHeaderCellDef class="fixed-column">{{ 'propertyHeader' | translate }}</th>
<td mat-cell *matCellDef="let element" class="fixed-column"> {{element.property}} </td> <td mat-cell *matCellDef="let element" class="fixed-column"> {{ element.property }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="value"> <ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef i18n="@@value-header">Valor</th> <th mat-header-cell *matHeaderCellDef>{{ 'valueHeader' | translate }}</th>
<td mat-cell *matCellDef="let element"> {{element.value}} </td> <td mat-cell *matCellDef="let element"> {{ element.value }} </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table> </table>
</mat-tab> </mat-tab>
<mat-tab label="Propiedades de red">
<mat-tab label="{{ 'networkPropertiesTab' | translate }}">
<table mat-table [dataSource]="networkData" class="mat-elevation-z8"> <table mat-table [dataSource]="networkData" class="mat-elevation-z8">
<ng-container matColumnDef="property"> <ng-container matColumnDef="property">
<th mat-header-cell *matHeaderCellDef class="fixed-column" i18n="@@property-header">Propiedad</th> <th mat-header-cell *matHeaderCellDef class="fixed-column">{{ 'propertyHeader' | translate }}</th>
<td mat-cell *matCellDef="let element" class="fixed-column"> {{element.property}} </td> <td mat-cell *matCellDef="let element" class="fixed-column"> {{ element.property }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="value"> <ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef i18n="@@value-header">Valor</th> <th mat-header-cell *matHeaderCellDef>{{ 'valueHeader' | translate }}</th>
<td mat-cell *matCellDef="let element"> {{element.value}} </td> <td mat-cell *matCellDef="let element"> {{ element.value }} </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table> </table>
</mat-tab> </mat-tab>
<mat-tab label="Propiedades del aula">
<mat-tab label="{{ 'classroomPropertiesTab' | translate }}">
<table mat-table [dataSource]="classroomData" class="mat-elevation-z8"> <table mat-table [dataSource]="classroomData" class="mat-elevation-z8">
<ng-container matColumnDef="property"> <ng-container matColumnDef="property">
<th mat-header-cell *matHeaderCellDef class="fixed-column" i18n="@@property-header">Propiedad</th> <th mat-header-cell *matHeaderCellDef class="fixed-column">{{ 'propertyHeader' | translate }}</th>
<td mat-cell *matCellDef="let element" class="fixed-column"> {{element.property}} </td> <td mat-cell *matCellDef="let element" class="fixed-column"> {{ element.property }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="value"> <ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef i18n="@@value-header">Valor</th> <th mat-header-cell *matHeaderCellDef>{{ 'valueHeader' | translate }}</th>
<td mat-cell *matCellDef="let element"> {{element.value}} </td> <td mat-cell *matCellDef="let element"> {{ element.value }} </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table> </table>
</mat-tab> </mat-tab>
<!-- <mat-tab label="Acciones">
<div class="button-column"> <mat-tab label="{{ 'partitionsTab' | translate }}">
<button mat-flat-button color="primary" class="button-action button-encender" i18n="@@power-on-button">Encender</button>
<button mat-flat-button color="accent" class="button-action button-apagar" i18n="@@power-off-button">Apagar</button>
<button mat-flat-button color="warn" class="button-action button-resetear" i18n="@@reset-button">Resetear</button>
<button mat-flat-button class="button-action button-otros-1" i18n="@@other-actions-1">Otras acciones 1</button>
<button mat-flat-button class="button-action button-otros-2" i18n="@@other-actions-2">Otras acciones 2</button>
<button mat-flat-button class="button-action button-otros-3" i18n="@@other-actions-3">Otras acciones 3</button>
</div>
</mat-tab> -->
<mat-tab label="Particiones">
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button mat-dialog-close (click)="onNoClick()" i18n="@@close-button">Cerrar</button> <button mat-button mat-dialog-close (click)="onNoClick()">{{ 'closeButton' | translate }}</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,10 +1,10 @@
<div class="create-client-container"> <div class="create-client-container">
<h1 mat-dialog-title i18n="@@add-client-dialog-title">Añadir Cliente</h1> <h1 mat-dialog-title>{{ 'addClientDialogTitle' | translate }}</h1>
<div class="mat-dialog-content" [ngClass]="{'loading': loading}"> <div class="mat-dialog-content" [ngClass]="{'loading': loading}">
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner> <mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
<form [formGroup]="clientForm" class="client-form grid-form" *ngIf="!loading"> <form [formGroup]="clientForm" class="client-form grid-form" *ngIf="!loading">
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@organizational-unit-label">Padre</mat-label> <mat-label>{{ 'organizationalUnitLabel' | translate }}</mat-label>
<mat-select formControlName="organizationalUnit"> <mat-select formControlName="organizationalUnit">
<mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']"> <mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']">
<div class="unit-name">{{ unit.name }}</div> <div class="unit-name">{{ unit.name }}</div>
@ -14,12 +14,12 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@name-label">Nombre</mat-label> <mat-label>{{ 'nameLabel' | translate }}</mat-label>
<input matInput formControlName="name"> <input matInput formControlName="name">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@oglive-label">OgLive</mat-label> <mat-label>{{ 'ogLiveLabel' | translate }}</mat-label>
<mat-select formControlName="ogLive"> <mat-select formControlName="ogLive">
<mat-option *ngFor="let oglive of ogLives" [value]="oglive['@id']"> <mat-option *ngFor="let oglive of ogLives" [value]="oglive['@id']">
{{ oglive.name }} {{ oglive.name }}
@ -28,12 +28,12 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@serial-number-label">Número de Serie</mat-label> <mat-label>{{ 'serialNumberLabel' | translate }}</mat-label>
<input matInput formControlName="serialNumber"> <input matInput formControlName="serialNumber">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@netiface-label">Interfaz de red</mat-label> <mat-label>{{ 'netifaceLabel' | translate }}</mat-label>
<mat-select formControlName="netiface"> <mat-select formControlName="netiface">
<mat-option *ngFor="let type of netifaceTypes" [value]="type.value"> <mat-option *ngFor="let type of netifaceTypes" [value]="type.value">
{{ type.name }} {{ type.name }}
@ -42,7 +42,7 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@net-driver-label">Controlador de red</mat-label> <mat-label>{{ 'netDriverLabel' | translate }}</mat-label>
<mat-select formControlName="netDriver"> <mat-select formControlName="netDriver">
<mat-option *ngFor="let type of netDriverTypes" [value]="type.value"> <mat-option *ngFor="let type of netDriverTypes" [value]="type.value">
{{ type.name }} {{ type.name }}
@ -51,21 +51,21 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@mac-label">MAC</mat-label> <mat-label>{{ 'macLabel' | translate }}</mat-label>
<mat-hint i18n="@@mac-hint">Ejemplo: 00:11:22:33:44:55</mat-hint> <mat-hint>{{ 'macHint' | translate }}</mat-hint>
<input matInput formControlName="mac"> <input matInput formControlName="mac">
<mat-error i18n="@@mac-error">Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55</mat-error> <mat-error>{{ 'macError' | translate }}</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@ip-label">Dirección IP</mat-label> <mat-label>{{ 'ipLabel' | translate }}</mat-label>
<mat-hint i18n="@@ip-hint">Ejemplo: 127.0.0.1</mat-hint> <mat-hint>{{ 'ipHint' | translate }}</mat-hint>
<input matInput formControlName="ip"> <input matInput formControlName="ip">
<mat-error i18n="@@ip-error">Formato de dirección IP inválido. Ejemplo válido: 127.0.0.1</mat-error> <mat-error>{{ 'ipError' | translate }}</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@oglive-label">Plantilla PXE</mat-label> <mat-label>{{ 'templateLabel' | translate }}</mat-label>
<mat-select formControlName="template"> <mat-select formControlName="template">
<mat-option *ngFor="let template of templates" [value]="template['@id']"> <mat-option *ngFor="let template of templates" [value]="template['@id']">
{{ template.name }} {{ template.name }}
@ -74,19 +74,19 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@hardware-profile-label">Perfil de Hardware</mat-label> <mat-label>{{ 'hardwareProfileLabel' | translate }}</mat-label>
<mat-select formControlName="hardwareProfile"> <mat-select formControlName="hardwareProfile">
<mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']"> <mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">
{{ unit.description }} {{ unit.description }}
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error i18n="@@hardware-profile-error">Formato de URL inválido.</mat-error> <mat-error>{{ 'hardwareProfileError' | translate }}</mat-error>
</mat-form-field> </mat-form-field>
</form> </form>
</div> </div>
<div mat-dialog-actions align="end"> <div mat-dialog-actions align="end">
<button mat-button (click)="onNoClick()" i18n="@@cancel-button">Cancelar</button> <button mat-button (click)="onNoClick()">{{ 'cancelButton' | translate }}</button>
<button mat-button [disabled]="!clientForm.valid" (click)="onSubmit()" i18n="@@add-button">Añadir</button> <button mat-button [disabled]="!clientForm.valid" (click)="onSubmit()">{{ 'addButton' | translate }}</button>
</div> </div>
</div> </div>

View File

@ -1,10 +1,10 @@
<h1 mat-dialog-title i18n="@@edit-client-dialog-title">Editar Cliente</h1> <h1 mat-dialog-title>{{ 'editClientDialogTitle' | translate }}</h1>
<div class="mat-dialog-content" [ngClass]="{'loading': loading}"> <div class="mat-dialog-content" [ngClass]="{'loading': loading}">
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner> <mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
<form [formGroup]="clientForm" class="client-form grid-form" *ngIf="!loading"> <form [formGroup]="clientForm" class="client-form grid-form" *ngIf="!loading">
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@organizational-unit-label">Padre</mat-label> <mat-label>{{ 'organizationalUnitLabel' | translate }}</mat-label>
<mat-select formControlName="organizationalUnit"> <mat-select formControlName="organizationalUnit">
<mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']"> <mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']">
{{ unit.name }} {{ unit.name }}
@ -13,12 +13,12 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@name-label">Nombre</mat-label> <mat-label>{{ 'nameLabel' | translate }}</mat-label>
<input matInput formControlName="name"> <input matInput formControlName="name">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@oglive-label">OgLive</mat-label> <mat-label>{{ 'ogLiveLabel' | translate }}</mat-label>
<mat-select formControlName="ogLive"> <mat-select formControlName="ogLive">
<mat-option *ngFor="let ogLive of ogLives" [value]="ogLive['@id']"> <mat-option *ngFor="let ogLive of ogLives" [value]="ogLive['@id']">
{{ ogLive.name }} {{ ogLive.name }}
@ -27,12 +27,12 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@serial-number-label">Número de Serie</mat-label> <mat-label>{{ 'serialNumberLabel' | translate }}</mat-label>
<input matInput formControlName="serialNumber"> <input matInput formControlName="serialNumber">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@netiface-label">Interfaz de red</mat-label> <mat-label>{{ 'netifaceLabel' | translate }}</mat-label>
<mat-select formControlName="netiface"> <mat-select formControlName="netiface">
<mat-option *ngFor="let type of netifaceTypes" [value]="type.value"> <mat-option *ngFor="let type of netifaceTypes" [value]="type.value">
{{ type.name }} {{ type.name }}
@ -41,7 +41,7 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@net-driver-label">Controlador de red</mat-label> <mat-label>{{ 'netDriverLabel' | translate }}</mat-label>
<mat-select formControlName="netDriver"> <mat-select formControlName="netDriver">
<mat-option *ngFor="let type of netDriverTypes" [value]="type.value"> <mat-option *ngFor="let type of netDriverTypes" [value]="type.value">
{{ type.name }} {{ type.name }}
@ -50,19 +50,19 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@mac-label">MAC</mat-label> <mat-label>{{ 'macLabel' | translate }}</mat-label>
<input matInput formControlName="mac"> <input matInput formControlName="mac">
<mat-error i18n="@@mac-error">Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55</mat-error> <mat-error>{{ 'macError' | translate }}</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@ip-label">Dirección IP</mat-label> <mat-label>{{ 'ipLabel' | translate }}</mat-label>
<input matInput formControlName="ip"> <input matInput formControlName="ip">
<mat-error i18n="@@ip-error">Formato de dirección IP inválido. Ejemplo válido: 127.0.0.1</mat-error> <mat-error>{{ 'ipError' | translate }}</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@oglive-label">Plantilla PXE</mat-label> <mat-label>{{ 'templateLabel' | translate }}</mat-label>
<mat-select formControlName="template"> <mat-select formControlName="template">
<mat-option *ngFor="let template of templates" [value]="template['@id']"> <mat-option *ngFor="let template of templates" [value]="template['@id']">
{{ template.name }} {{ template.name }}
@ -71,21 +71,21 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@hardware-profile-label">Perfil de Hardware</mat-label> <mat-label>{{ 'hardwareProfileLabel' | translate }}</mat-label>
<mat-select formControlName="hardwareProfile"> <mat-select formControlName="hardwareProfile">
<mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']"> <mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">
{{ unit.description }} {{ unit.description }}
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error i18n="@@hardware-profile-error">Formato de URL inválido.</mat-error> <mat-error>{{ 'hardwareProfileError' | translate }}</mat-error>
</mat-form-field> </mat-form-field>
</form> </form>
</div> </div>
<div mat-dialog-actions align="end"> <div mat-dialog-actions align="end">
<button mat-button (click)="onNoClick()" i18n="@@cancel-button">Cancelar</button> <button mat-button (click)="onNoClick()">{{ 'cancelButton' | translate }}</button>
<button mat-button [disabled]="!clientForm.valid" (click)="onSubmit()"> <button mat-button [disabled]="!clientForm.valid" (click)="onSubmit()">
{{ !isEditMode ? 'Añadir' : 'Guardar' }} {{ !isEditMode ? ('addButton' | translate) : ('saveButton' | translate) }}
</button> </button>
</div> </div>

View File

@ -0,0 +1,45 @@
<h2 mat-dialog-title>{{ 'executeCommandOrGroupTitle' | translate }}</h2>
<mat-dialog-content class="form-container">
<form [formGroup]="form" class="command-form">
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'selectCommandLabel' | translate }}</mat-label>
<mat-select formControlName="selectedCommand" (selectionChange)="form.get('selectedCommandGroup')?.reset()">
<mat-option *ngFor="let command of commands" [value]="command.uuid">{{ command.name }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'selectCommandGroupLabel' | translate }}</mat-label>
<mat-select formControlName="selectedCommandGroup" (selectionChange)="form.get('selectedCommand')?.reset()">
<mat-option *ngFor="let group of commandGroups" [value]="group.uuid">{{ group.name }}</mat-option>
</mat-select>
</mat-form-field>
<div class="checkbox-group">
<label>{{ 'clientsLabel' | translate }}</label>
<div *ngIf="clients.length > 0">
<mat-checkbox *ngFor="let client of clients"
(change)="toggleClientSelection(client.uuid)"
[checked]="form.get('clientSelection')?.value.includes(client.uuid)">
{{ client.name }}
</mat-checkbox>
</div>
<div *ngIf="clients.length === 0">
<p>{{ 'noClientsMessage' | translate }}</p>
</div>
</div>
</form>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button (click)="closeModal()">{{ 'cancelButton' | translate }}</button>
<button mat-button
(click)="executeCommand()"
[disabled]="!form.get('clientSelection')?.value.length ||
(!form.get('selectedCommand')?.value && !form.get('selectedCommandGroup')?.value)">
{{ 'executeButton' | translate }}
</button>
</mat-dialog-actions>

View File

@ -1,22 +1,22 @@
<mat-list> <mat-list>
<mat-list-item> <mat-list-item>
<mat-icon matListItemIcon>apartment</mat-icon> <mat-icon matListItemIcon>apartment</mat-icon>
<div matListItemTitle i18n="@@orgUnitTitle">Unidad organizativa</div> <div matListItemTitle>{{ 'orgUnitTitle' | translate }}</div>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<mat-icon matListItemIcon>meeting_room</mat-icon> <mat-icon matListItemIcon>meeting_room</mat-icon>
<div matListItemTitle i18n="@@classroomGroupsTitle">Grupos de aula</div> <div matListItemTitle>{{ 'classroomGroupsTitle' | translate }}</div>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<mat-icon matListItemIcon>school</mat-icon> <mat-icon matListItemIcon>school</mat-icon>
<div matListItemTitle i18n="@@classroomTitle">Aula</div> <div matListItemTitle>{{ 'classroomTitle' | translate }}</div>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<mat-icon matListItemIcon>lan</mat-icon> <mat-icon matListItemIcon>lan</mat-icon>
<div matListItemTitle i18n="@@clientGroupsTitle">Grupos de clientes</div> <div matListItemTitle>{{ 'clientGroupsTitle' | translate }}</div>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<mat-icon matListItemIcon>computer</mat-icon> <mat-icon matListItemIcon>computer</mat-icon>
<div matListItemTitle i18n="@@clientTitle">Cliente</div> <div matListItemTitle>{{ 'clientTitle' | translate }}</div>
</mat-list-item> </mat-list-item>
</mat-list> </mat-list>

View File

@ -1,13 +1,13 @@
<h1 mat-dialog-title i18n="@@addOrgUnitTitle">Añadir Unidad Organizativa</h1> <h1 mat-dialog-title>{{ 'addOrgUnitTitle' | translate }}</h1>
<div mat-dialog-content> <div mat-dialog-content>
<mat-stepper orientation="vertical" [linear]="isLinear"> <mat-stepper orientation="vertical" [linear]="isLinear">
<!-- Step 1: General --> <!-- Paso 1: General -->
<mat-step [stepControl]="generalFormGroup"> <mat-step [stepControl]="generalFormGroup">
<form [formGroup]="generalFormGroup"> <form [formGroup]="generalFormGroup">
<ng-template matStepLabel i18n="@@generalStepLabel">General</ng-template> <ng-template matStepLabel>{{ 'generalStepLabel' | translate }}</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@typeLabel">Tipo</mat-label> <mat-label>{{ 'typeLabel' | translate }}</mat-label>
<mat-select formControlName="type" required> <mat-select formControlName="type" required>
<mat-option *ngFor="let type of types" [value]="type"> <mat-option *ngFor="let type of types" [value]="type">
{{ typeTranslations[type] }} {{ typeTranslations[type] }}
@ -15,42 +15,42 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@nameLabel">Nombre</mat-label> <mat-label>{{ 'nameLabel' | translate }}</mat-label>
<input matInput formControlName="name" required> <input matInput formControlName="name" required>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@createOrgUnitparentLabel">Unidad organizativa padre</mat-label> <mat-label>{{ 'createOrgUnitparentLabel' | translate }}</mat-label>
<mat-select formControlName="parent"> <mat-select formControlName="parent">
<mat-option i18n="@@noParentOption">--</mat-option> <mat-option>{{ 'noParentOption' | translate }}</mat-option>
<mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']">{{ unit.name }}</mat-option> <mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']">{{ unit.name }}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@descriptionLabel">Descripción</mat-label> <mat-label>{{ 'descriptionLabel' | translate }}</mat-label>
<textarea matInput formControlName="description"></textarea> <textarea matInput formControlName="description"></textarea>
</mat-form-field> </mat-form-field>
<div> <div>
<button mat-button matStepperNext i18n="@@nextButton">Siguiente</button> <button mat-button matStepperNext>{{ 'nextButton' | translate }}</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
<!-- Step 2: Classroom Info --> <!-- Paso 2: Información del Aula -->
<mat-step *ngIf="generalFormGroup.value.type === 'classroom'" [stepControl]="classroomInfoFormGroup"> <mat-step *ngIf="generalFormGroup.value.type === 'classroom'" [stepControl]="classroomInfoFormGroup">
<form [formGroup]="classroomInfoFormGroup"> <form [formGroup]="classroomInfoFormGroup">
<ng-template matStepLabel i18n="@@classroomInfoStepLabel">Información del Aula</ng-template> <ng-template matStepLabel>{{ 'classroomInfoStepLabel' | translate }}</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@locationLabel">Ubicación</mat-label> <mat-label>{{ 'locationLabel' | translate }}</mat-label>
<input matInput formControlName="location"> <input matInput formControlName="location">
</mat-form-field> </mat-form-field>
<mat-slide-toggle formControlName="projector" i18n="@@projectorToggle">Proyector</mat-slide-toggle> <mat-slide-toggle formControlName="projector">{{ 'projectorToggle' | translate }}</mat-slide-toggle>
<mat-slide-toggle formControlName="board" i18n="@@boardToggle">Pizarra</mat-slide-toggle> <mat-slide-toggle formControlName="board">{{ 'boardToggle' | translate }}</mat-slide-toggle>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@capacityLabel">Aforo</mat-label> <mat-label>{{ 'capacityLabel' | translate }}</mat-label>
<input matInput formControlName="capacity" type="number"> <input matInput formControlName="capacity" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field" appearance="fill"> <mat-form-field class="form-field" appearance="fill">
<mat-label>Calendario Asociado</mat-label> <mat-label>{{ 'associatedCalendarLabel' | translate }}</mat-label>
<mat-select formControlName="remoteCalendar" (selectionChange)="onCalendarChange($event)"> <mat-select formControlName="remoteCalendar" (selectionChange)="onCalendarChange($event)">
<mat-option *ngFor="let calendar of calendars" [value]="calendar['@id']"> <mat-option *ngFor="let calendar of calendars" [value]="calendar['@id']">
{{ calendar.name }} {{ calendar.name }}
@ -59,62 +59,62 @@
</mat-form-field> </mat-form-field>
<div> <div>
<button mat-button matStepperPrevious i18n="@@backButton">Atrás</button> <button mat-button matStepperPrevious>{{ 'backButton' | translate }}</button>
<button mat-button matStepperNext i18n="@@nextButton">Siguiente</button> <button mat-button matStepperNext>{{ 'nextButton' | translate }}</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
<!-- Step 3: Información Adicional --> <!-- Paso 3: Información Adicional -->
<mat-step [stepControl]="additionalInfoFormGroup"> <mat-step [stepControl]="additionalInfoFormGroup">
<form [formGroup]="additionalInfoFormGroup"> <form [formGroup]="additionalInfoFormGroup">
<ng-template matStepLabel i18n="@@additionalInfoStepLabel">Información Adicional</ng-template> <ng-template matStepLabel>{{ 'additionalInfoStepLabel' | translate }}</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@commentsLabel">Comentarios</mat-label> <mat-label>{{ 'commentsLabel' | translate }}</mat-label>
<textarea matInput formControlName="comments"></textarea> <textarea matInput formControlName="comments"></textarea>
</mat-form-field> </mat-form-field>
<div> <div>
<button mat-button matStepperPrevious i18n="@@backButton">Atrás</button> <button mat-button matStepperPrevious>{{ 'backButton' | translate }}</button>
<button mat-button matStepperNext i18n="@@nextButton">Siguiente</button> <button mat-button matStepperNext>{{ 'nextButton' | translate }}</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
<!-- Step 4: Configuración de Red --> <!-- Paso 4: Configuración de Red -->
<mat-step *ngIf="generalFormGroup.value.type === 'classroom'" [stepControl]="networkSettingsFormGroup"> <mat-step *ngIf="generalFormGroup.value.type === 'classroom'" [stepControl]="networkSettingsFormGroup">
<form [formGroup]="networkSettingsFormGroup"> <form [formGroup]="networkSettingsFormGroup">
<ng-template matStepLabel i18n="@@networkSettingsStepLabel">Configuración de Red</ng-template> <ng-template matStepLabel>{{ 'networkSettingsStepLabel' | translate }}</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@nextServerLabel">NextServer</mat-label> <mat-label>{{ 'nextServerLabel' | translate }}</mat-label>
<input matInput formControlName="nextServer"> <input matInput formControlName="nextServer">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@bootFileNameLabel">bootFileName</mat-label> <mat-label>{{ 'bootFileNameLabel' | translate }}</mat-label>
<input matInput formControlName="bootFileName"> <input matInput formControlName="bootFileName">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@proxyUrlLabel">Url servidor Proxy</mat-label> <mat-label>{{ 'proxyUrlLabel' | translate }}</mat-label>
<input matInput formControlName="proxy"> <input matInput formControlName="proxy">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@dnsIpLabel">IP servidor DNS</mat-label> <mat-label>{{ 'dnsIpLabel' | translate }}</mat-label>
<input matInput formControlName="dns"> <input matInput formControlName="dns">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@netmaskLabel">Máscara de Red</mat-label> <mat-label>{{ 'netmaskLabel' | translate }}</mat-label>
<input matInput formControlName="netmask"> <input matInput formControlName="netmask">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@routerLabel">Router</mat-label> <mat-label>{{ 'routerLabel' | translate }}</mat-label>
<input matInput formControlName="router"> <input matInput formControlName="router">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@ntpIpLabel">IP servidor NTP</mat-label> <mat-label>{{ 'ntpIpLabel' | translate }}</mat-label>
<input matInput formControlName="ntp"> <input matInput formControlName="ntp">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@p2pModeLabel">Modo P2P</mat-label> <mat-label>{{ 'p2pModeLabel' | translate }}</mat-label>
<mat-select formControlName="p2pMode"> <mat-select formControlName="p2pMode">
<mat-option *ngFor="let option of p2pModeOptions" [value]="option.value"> <mat-option *ngFor="let option of p2pModeOptions" [value]="option.value">
{{ option.name }} {{ option.name }}
@ -122,23 +122,23 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@p2pTimeLabel">Tiempo P2P</mat-label> <mat-label>{{ 'p2pTimeLabel' | translate }}</mat-label>
<input matInput formControlName="p2pTime" type="number"> <input matInput formControlName="p2pTime" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@mcastIpLabel">IP Multicast</mat-label> <mat-label>{{ 'mcastIpLabel' | translate }}</mat-label>
<input matInput formControlName="mcastIp"> <input matInput formControlName="mcastIp">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@mcastSpeedLabel">Velocidad Multicast</mat-label> <mat-label>{{ 'mcastSpeedLabel' | translate }}</mat-label>
<input matInput formControlName="mcastSpeed" type="number"> <input matInput formControlName="mcastSpeed" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@mcastPortLabel">Puerto Multicast</mat-label> <mat-label>{{ 'mcastPortLabel' | translate }}</mat-label>
<input matInput formControlName="mcastPort" type="number"> <input matInput formControlName="mcastPort" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@mcastModeLabel">Modo Multicast</mat-label> <mat-label>{{ 'mcastModeLabel' | translate }}</mat-label>
<mat-select formControlName="mcastMode"> <mat-select formControlName="mcastMode">
<mat-option *ngFor="let option of multicastModeOptions" [value]="option.value"> <mat-option *ngFor="let option of multicastModeOptions" [value]="option.value">
{{ option.name }} {{ option.name }}
@ -146,21 +146,21 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@menuUrlLabel">Menú URL</mat-label> <mat-label>{{ 'menuUrlLabel' | translate }}</mat-label>
<input matInput formControlName="menu" type="url"> <input matInput formControlName="menu" type="url">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@hardwareProfileLabel">Perfil de Hardware</mat-label> <mat-label>{{ 'hardwareProfileLabel' | translate }}</mat-label>
<mat-select formControlName="hardwareProfile"> <mat-select formControlName="hardwareProfile">
<mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">{{ unit.description }}</mat-option> <mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">{{ unit.description }}</mat-option>
</mat-select> </mat-select>
<mat-error i18n="@@urlFormatError">Formato de URL inválido.</mat-error> <mat-error>{{ 'urlFormatError' | translate }}</mat-error>
</mat-form-field> </mat-form-field>
</form> </form>
</mat-step> </mat-step>
</mat-stepper> </mat-stepper>
</div> </div>
<div mat-dialog-actions align="end"> <div mat-dialog-actions align="end">
<button mat-button (click)="onNoClick()" i18n="@@cancelButton">Cancelar</button> <button mat-button (click)="onNoClick()">{{ 'cancelButton' | translate }}</button>
<button mat-button (click)="onSubmit()" [disabled]="!networkSettingsFormGroup.valid" i18n="@@submitButton">Añadir</button> <button mat-button (click)="onSubmit()" [disabled]="!networkSettingsFormGroup.valid">{{ 'submitButton' | translate }}</button>
</div> </div>

View File

@ -1,163 +1,154 @@
<h1 mat-dialog-title i18n="@@editOrgUnitTitle">Editar Unidad Organizativa</h1> <h1 mat-dialog-title>{{ 'editOrgUnitTitle' | translate }}</h1>
<div mat-dialog-content> <div mat-dialog-content>
<mat-stepper orientation="vertical" [linear]="isLinear"> <mat-stepper orientation="vertical" [linear]="isLinear">
<!-- Step 1: General --> <!-- Paso 1: General -->
<mat-step [stepControl]="generalFormGroup"> <mat-step [stepControl]="generalFormGroup">
<form [formGroup]="generalFormGroup"> <form [formGroup]="generalFormGroup">
<ng-template matStepLabel i18n="@@generalStepLabel">General</ng-template> <ng-template matStepLabel>{{ 'generalStepLabel' | translate }}</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@typeLabel">Tipo</mat-label> <mat-label>{{ 'typeLabel' | translate }}</mat-label>
<mat-select formControlName="type" required> <mat-select formControlName="type" required>
<mat-option *ngFor="let type of types" [value]="type">{{ type }}</mat-option> <mat-option *ngFor="let type of types" [value]="type">{{ type }}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@nameLabel">Nombre</mat-label> <mat-label>{{ 'nameLabel' | translate }}</mat-label>
<input matInput formControlName="name" required> <input matInput formControlName="name" required>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@editOrgUnitParentLabel">Padre</mat-label> <mat-label>{{ 'editOrgUnitParentLabel' | translate }}</mat-label>
<mat-select formControlName="parent"> <mat-select formControlName="parent">
<mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']">{{ unit.name }}</mat-option> <mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']">{{ unit.name }}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@descriptionLabel">Descripción</mat-label> <mat-label>{{ 'descriptionLabel' | translate }}</mat-label>
<textarea matInput formControlName="description"></textarea> <textarea matInput formControlName="description"></textarea>
</mat-form-field> </mat-form-field>
<div> <div>
<button mat-button matStepperNext i18n="@@nextButton">Siguiente</button> <button mat-button matStepperNext>{{ 'nextButton' | translate }}</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
<!-- Step 2: Classroom Info --> <!-- Paso 2: Información del Aula -->
<mat-step *ngIf="generalFormGroup.value.type === 'classroom'" [stepControl]="classroomInfoFormGroup"> <mat-step *ngIf="generalFormGroup.value.type === 'classroom'" [stepControl]="classroomInfoFormGroup">
<form [formGroup]="classroomInfoFormGroup"> <form [formGroup]="classroomInfoFormGroup">
<ng-template matStepLabel i18n="@@classroomInfoStepLabel">Información del Aula</ng-template> <ng-template matStepLabel>{{ 'classroomInfoStepLabel' | translate }}</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@locationLabel">Ubicación</mat-label> <mat-label>{{ 'locationLabel' | translate }}</mat-label>
<input matInput formControlName="location"> <input matInput formControlName="location">
</mat-form-field> </mat-form-field>
<mat-slide-toggle formControlName="projector" i18n="@@projectorToggle">Proyector</mat-slide-toggle> <mat-slide-toggle formControlName="projector">{{ 'projectorToggle' | translate }}</mat-slide-toggle>
<mat-slide-toggle formControlName="board" i18n="@@boardToggle">Pizarra</mat-slide-toggle> <mat-slide-toggle formControlName="board">{{ 'boardToggle' | translate }}</mat-slide-toggle>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@capacityLabel">Aforo</mat-label> <mat-label>{{ 'capacityLabel' | translate }}</mat-label>
<input matInput formControlName="capacity" type="number"> <input matInput formControlName="capacity" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field" appearance="fill"> <mat-form-field class="form-field" appearance="fill">
<mat-label>Calendario Asociado</mat-label> <mat-label>{{ 'associatedCalendarLabel' | translate }}</mat-label>
<mat-select formControlName="remoteCalendar" (selectionChange)="onCalendarChange($event)"> <mat-select formControlName="remoteCalendar" (selectionChange)="onCalendarChange($event)">
<mat-option *ngFor="let calendar of calendars" [value]="calendar['@id']"> <mat-option *ngFor="let calendar of calendars" [value]="calendar['@id']">
{{ calendar.name }} {{ calendar.name }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<div> <div>
<button mat-button matStepperPrevious i18n="@@backButton">Atrás</button> <button mat-button matStepperPrevious>{{ 'backButton' | translate }}</button>
<button mat-button matStepperNext i18n="@@nextButton">Siguiente</button> <button mat-button matStepperNext>{{ 'nextButton' | translate }}</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
<!-- Paso 3: Información Adicional -->
<!-- Step 3: Información Adicional -->
<mat-step [stepControl]="additionalInfoFormGroup"> <mat-step [stepControl]="additionalInfoFormGroup">
<form [formGroup]="additionalInfoFormGroup"> <form [formGroup]="additionalInfoFormGroup">
<ng-template matStepLabel i18n="@@additionalInfoStepLabel">Información Adicional</ng-template> <ng-template matStepLabel>{{ 'additionalInfoStepLabel' | translate }}</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@commentsLabel">Comentarios</mat-label> <mat-label>{{ 'commentsLabel' | translate }}</mat-label>
<textarea matInput formControlName="comments"></textarea> <textarea matInput formControlName="comments"></textarea>
</mat-form-field> </mat-form-field>
<div> <div>
<button mat-button matStepperPrevious i18n="@@backButton">Atrás</button> <button mat-button matStepperPrevious>{{ 'backButton' | translate }}</button>
<button mat-button matStepperNext i18n="@@nextButton">Siguiente</button> <button mat-button matStepperNext>{{ 'nextButton' | translate }}</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
<!-- Step 4: Configuración de Red --> <!-- Paso 4: Configuración de Red -->
<mat-step [stepControl]="networkSettingsFormGroup"> <mat-step [stepControl]="networkSettingsFormGroup">
<form [formGroup]="networkSettingsFormGroup"> <form [formGroup]="networkSettingsFormGroup">
<ng-template matStepLabel i18n="@@networkSettingsStepLabel">Configuración de Red</ng-template> <ng-template matStepLabel>{{ 'networkSettingsStepLabel' | translate }}</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@proxyUrlLabel">Url servidor Proxy</mat-label> <mat-label>{{ 'proxyUrlLabel' | translate }}</mat-label>
<input matInput formControlName="proxy"> <input matInput formControlName="proxy">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@dnsIpLabel">IP servidor DNS</mat-label> <mat-label>{{ 'dnsIpLabel' | translate }}</mat-label>
<input matInput formControlName="dns"> <input matInput formControlName="dns">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@netmaskLabel">Máscara de Red</mat-label> <mat-label>{{ 'netmaskLabel' | translate }}</mat-label>
<input matInput formControlName="netmask"> <input matInput formControlName="netmask">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@routerLabel">Router</mat-label> <mat-label>{{ 'routerLabel' | translate }}</mat-label>
<input matInput formControlName="router"> <input matInput formControlName="router">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@ntpIpLabel">IP servidor NTP</mat-label> <mat-label>{{ 'ntpIpLabel' | translate }}</mat-label>
<input matInput formControlName="ntp"> <input matInput formControlName="ntp">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@p2pModeLabel">Modo P2P</mat-label> <mat-label>{{ 'p2pModeLabel' | translate }}</mat-label>
<mat-select formControlName="p2pMode"> <mat-select formControlName="p2pMode">
<mat-option <mat-option *ngFor="let option of p2pModeOptions" [value]="option.value">{{ option.name }}</mat-option>
*ngFor="let option of p2pModeOptions"
[value]="option.value">
{{ option.name }}
</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@p2pTimeLabel">Tiempo P2P</mat-label> <mat-label>{{ 'p2pTimeLabel' | translate }}</mat-label>
<input matInput formControlName="p2pTime" type="number"> <input matInput formControlName="p2pTime" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@mcastIpLabel">IP Multicast</mat-label> <mat-label>{{ 'mcastIpLabel' | translate }}</mat-label>
<input matInput formControlName="mcastIp"> <input matInput formControlName="mcastIp">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@mcastSpeedLabel">Velocidad Multicast</mat-label> <mat-label>{{ 'mcastSpeedLabel' | translate }}</mat-label>
<input matInput formControlName="mcastSpeed" type="number"> <input matInput formControlName="mcastSpeed" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@mcastPortLabel">Puerto Multicast</mat-label> <mat-label>{{ 'mcastPortLabel' | translate }}</mat-label>
<input matInput formControlName="mcastPort" type="number"> <input matInput formControlName="mcastPort" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@mcastModeLabel">Modo Multicast</mat-label> <mat-label>{{ 'mcastModeLabel' | translate }}</mat-label>
<mat-select formControlName="mcastMode"> <mat-select formControlName="mcastMode">
<mat-option <mat-option *ngFor="let option of multicastModeOptions" [value]="option.value">{{ option.name }}</mat-option>
*ngFor="let option of multicastModeOptions"
[value]="option.value">
{{ option.name }}
</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@menuUrlLabel">Menú URL</mat-label> <mat-label>{{ 'menuUrlLabel' | translate }}</mat-label>
<input matInput formControlName="menu" type="url"> <input matInput formControlName="menu" type="url">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label i18n="@@hardwareProfileLabel">Perfil de Hardware</mat-label> <mat-label>{{ 'hardwareProfileLabel' | translate }}</mat-label>
<mat-select formControlName="hardwareProfile"> <mat-select formControlName="hardwareProfile">
<mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">{{ unit.description }} </mat-option> <mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">{{ unit.description }}</mat-option>
</mat-select> </mat-select>
<mat-error i18n="@@urlFormatError">Formato de URL inválido.</mat-error> <mat-error>{{ 'urlFormatError' | translate }}</mat-error>
</mat-form-field> </mat-form-field>
<mat-slide-toggle formControlName="validation" i18n="@@validationToggle">Validación</mat-slide-toggle> <mat-slide-toggle formControlName="validation">{{ 'validationToggle' | translate }}</mat-slide-toggle>
<div> <div>
<button mat-button matStepperPrevious i18n="@@backButton">Atrás</button> <button mat-button matStepperPrevious>{{ 'backButton' | translate }}</button>
<button mat-button (click)="onSubmit()" [disabled]="!networkSettingsFormGroup.valid" i18n="@@submitButton">Añadir</button> <button mat-button (click)="onSubmit()" [disabled]="!networkSettingsFormGroup.valid">{{ 'submitButton' | translate }}</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
</mat-stepper> </mat-stepper>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-button (click)="onNoClick()" i18n="@@cancelButton">Cancelar</button> <button mat-button (click)="onNoClick()">{{ 'cancelButton' | translate }}</button>
</div> </div>

View File

@ -1,28 +1,28 @@
<h1 mat-dialog-title i18n="@@orgUnitPropertiesTitle">Propiedades unidad organizativa</h1> <h1 mat-dialog-title>{{ 'orgUnitPropertiesTitle' | translate }}</h1>
<div mat-dialog-content> <div mat-dialog-content>
<mat-tab-group dynamicHeight> <mat-tab-group dynamicHeight>
<mat-tab label="Datos generales" i18n-label="@@generalDataTab"> <mat-tab label="{{ 'generalDataTab' | translate }}">
<table mat-table [dataSource]="generalData" class="mat-elevation-z8"> <table mat-table [dataSource]="generalData" class="mat-elevation-z8">
<ng-container matColumnDef="property"> <ng-container matColumnDef="property">
<th mat-header-cell *matHeaderCellDef i18n-header="@@propertyHeader"> Propiedad </th> <th mat-header-cell *matHeaderCellDef>{{ 'propertyHeader' | translate }}</th>
<td mat-cell *matCellDef="let element"> {{ element.property }} </td> <td mat-cell *matCellDef="let element"> {{ element.property }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="value"> <ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef i18n-header="@@valueHeader"> Valor </th> <th mat-header-cell *matHeaderCellDef>{{ 'valueHeader' | translate }}</th>
<td mat-cell *matCellDef="let element"> {{ element.value }} </td> <td mat-cell *matCellDef="let element"> {{ element.value }} </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table> </table>
</mat-tab> </mat-tab>
<mat-tab [disabled]="data.data.type !== 'classroom'" label="Propiedades aula y de red" i18n-label="@@classroomNetworkPropertiesTab"> <mat-tab [disabled]="data.data.type !== 'classroom'" label="{{ 'classroomNetworkPropertiesTab' | translate }}">
<table mat-table [dataSource]="networkData" class="mat-elevation-z8"> <table mat-table [dataSource]="networkData" class="mat-elevation-z8">
<ng-container matColumnDef="property"> <ng-container matColumnDef="property">
<th mat-header-cell *matHeaderCellDef i18n-header="@@propertyHeader"> Propiedad </th> <th mat-header-cell *matHeaderCellDef>{{ 'propertyHeader' | translate }}</th>
<td mat-cell *matCellDef="let element"> {{ element.property }} </td> <td mat-cell *matCellDef="let element"> {{ element.property }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="value"> <ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef i18n-header="@@valueHeader"> Valor </th> <th mat-header-cell *matHeaderCellDef>{{ 'valueHeader' | translate }}</th>
<td mat-cell *matCellDef="let element"> {{ element.value }} </td> <td mat-cell *matCellDef="let element"> {{ element.value }} </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>

View File

@ -1,4 +1,4 @@
<h1 mat-dialog-title i18n="@@viewTreeTitle">Visualizar árbol unidad Organizativa</h1> <h1 mat-dialog-title>{{ 'viewTreeTitle' | translate }}</h1>
<mat-dialog-content> <mat-dialog-content>
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl" class="tree"> <mat-tree [dataSource]="dataSource" [treeControl]="treeControl" class="tree">
@ -11,16 +11,15 @@
<ng-container *ngSwitchCase="'clients-group'">lan</ng-container> <ng-container *ngSwitchCase="'clients-group'">lan</ng-container>
<ng-container *ngSwitchDefault>help_outline</ng-container> <ng-container *ngSwitchDefault>help_outline</ng-container>
</mat-icon> </mat-icon>
{{node.name}} {{ node.name }}
</mat-tree-node> </mat-tree-node>
<!-- This is the tree node template for expandable nodes -->
<!-- Nodo expandible -->
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild"> <mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">
<div class="mat-tree-node"> <div class="mat-tree-node">
<button mat-icon-button matTreeNodeToggle <button mat-icon-button matTreeNodeToggle [attr.aria-label]="'Toggle ' + node.name | translate">
[attr.aria-label]="'Toggle ' + node.name"
i18n-aria-label="@@toggleNodeAriaLabel">
<mat-icon class="mat-icon-rtl-mirror"> <mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}} {{ treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}
</mat-icon> </mat-icon>
</button> </button>
<div class="item-content"> <div class="item-content">
@ -32,13 +31,11 @@
<ng-container *ngSwitchCase="'clients-group'">lan</ng-container> <ng-container *ngSwitchCase="'clients-group'">lan</ng-container>
<ng-container *ngSwitchDefault>help_outline</ng-container> <ng-container *ngSwitchDefault>help_outline</ng-container>
</mat-icon> </mat-icon>
{{node.name}} {{ node.name }}
</div> </div>
</div> </div>
<!-- There is inline padding applied to this div using styles.
This padding value depends on the mat-icon-button width. --> <div [class.tree-invisible]="!treeControl.isExpanded(node)" role="group">
<div [class.tree-invisible]="!treeControl.isExpanded(node)"
role="group">
<ng-container matTreeNodeOutlet></ng-container> <ng-container matTreeNodeOutlet></ng-container>
<mat-list *ngIf="node.clients"> <mat-list *ngIf="node.clients">
<mat-list-item *ngFor="let client of node.clients"> <mat-list-item *ngFor="let client of node.clients">
@ -51,6 +48,7 @@
</mat-nested-tree-node> </mat-nested-tree-node>
</mat-tree> </mat-tree>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button (click)="close()" i18n="@@closeButton">Cerrar</button> <button mat-button (click)="close()">{{ 'closeButton' | translate }}</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,24 +1,37 @@
<h2 mat-dialog-title>Añadir nueva imagen</h2> <h2 mat-dialog-title>{{ 'addImageTitle' | translate }}</h2>
<mat-dialog-content class="dialog-content"> <mat-dialog-content class="dialog-content">
<form [formGroup]="imageForm" (ngSubmit)="saveImage()" class="image-form"> <form [formGroup]="imageForm" (ngSubmit)="saveImage()" class="image-form">
<mat-form-field appearance="fill" class="form-field"> <mat-form-field appearance="fill" class="form-field">
<mat-label>Nombre de la imagen</mat-label> <mat-label>{{ 'imageNameLabel' | translate }}</mat-label>
<input matInput formControlName="name" required> <input matInput formControlName="name" required>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="form-field"> <mat-form-field appearance="fill" class="form-field">
<<<<<<< Updated upstream
<mat-label>Descripción</mat-label> <mat-label>Descripción</mat-label>
=======
<mat-label>{{ 'repositoryLabel' | translate }}</mat-label>
<mat-select formControlName="imageRepository" required>
<mat-option *ngFor="let imageRepository of repositories" [value]="imageRepository['@id']">
{{ imageRepository.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill" class="form-field">
<mat-label>{{ 'descriptionLabel' | translate }}</mat-label>
>>>>>>> Stashed changes
<input matInput formControlName="description" name="description"> <input matInput formControlName="description" name="description">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="form-field"> <mat-form-field appearance="fill" class="form-field">
<mat-label>Comentarios</mat-label> <mat-label>{{ 'commentsLabel' | translate }}</mat-label>
<input matInput formControlName="comments" name="comments"> <input matInput formControlName="comments" name="comments">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="form-field"> <mat-form-field appearance="fill" class="form-field">
<mat-label>Perfil de software</mat-label> <mat-label>{{ 'softwareProfileLabel' | translate }}</mat-label>
<mat-select formControlName="softwareProfile" required> <mat-select formControlName="softwareProfile" required>
<mat-option *ngFor="let profile of softwareProfiles" [value]="profile['@id']"> <mat-option *ngFor="let profile of softwareProfiles" [value]="profile['@id']">
{{ profile.description }} {{ profile.description }}
@ -30,12 +43,12 @@
formControlName="remotePc" formControlName="remotePc"
class="example-margin" class="example-margin"
> >
Remote Pc {{ 'remotePcLabel' | translate }}
</mat-checkbox> </mat-checkbox>
</form> </form>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end" class="dialog-actions"> <mat-dialog-actions align="end" class="dialog-actions">
<button mat-button (click)="close()">Cancelar</button> <button mat-button (click)="close()">{{ 'cancelButton' | translate }}</button>
<button mat-button color="primary" (click)="saveImage()">Guardar</button> <button mat-button color="primary" (click)="saveImage()">{{ 'saveButton' | translate }}</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,8 +1,19 @@
<div class="header-container"> <div class="header-container">
<<<<<<< Updated upstream
<h2 class="title">Administrar imágenes</h2> <h2 class="title">Administrar imágenes</h2>
<div class="images-button-row"> <div class="images-button-row">
<button mat-flat-button color="primary" (click)="addImage()">Añadir imagen</button> <button mat-flat-button color="primary" (click)="addImage()">Añadir imagen</button>
</div> </div>
=======
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<h2 class="title">{{ 'imagesTitle' | translate }}</h2>
<div class="images-button-row">
<button mat-flat-button color="primary" (click)="addImage()">
{{ 'addImageButton' | translate }}
</button>
>>>>>>> Stashed changes
</div> </div>
<mat-divider class="divider"></mat-divider> <mat-divider class="divider"></mat-divider>
@ -15,6 +26,7 @@
</mat-form-field> </mat-form-field>
</div> </div>
<<<<<<< Updated upstream
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef"> <ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th> <th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
@ -51,3 +63,52 @@
(page)="onPageChange($event)"> (page)="onPageChange($event)">
</mat-paginator> </mat-paginator>
</div> </div>
=======
<div class="search-container">
<mat-form-field appearance="fill" class="search-string">
<mat-label>{{ 'searchLabel' | translate }}</mat-label>
<input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()">
<mat-icon matSuffix>search</mat-icon>
<mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field>
</div>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
<td mat-cell *matCellDef="let image">
<ng-container *ngIf="column.columnDef === 'remotePc'">
<mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'">
{{ image[column.columnDef] ? 'check_circle' : 'cancel' }}
</mat-icon>
</ng-container>
<ng-container *ngIf="column.columnDef !== 'remotePc'">
{{ column.cell(image) }}
</ng-container>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="actions-header">{{ 'columnActions' | translate }}</th>
<td mat-cell *matCellDef="let client">
<button mat-icon-button color="primary" (click)="editImage($event, client)">
<mat-icon>{{ 'editButtonIcon' | translate }}</mat-icon>
</button>
<button mat-icon-button color="warn" (click)="deleteImage($event, client)">
<mat-icon>{{ 'deleteButtonIcon' | translate }}</mat-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<div class="paginator-container">
<mat-paginator [length]="length"
[pageSize]="itemsPerPage"
[pageIndex]="page"
[pageSizeOptions]="[5, 10, 20, 40, 100]"
(page)="onPageChange($event)">
</mat-paginator>
</div>
>>>>>>> Stashed changes

View File

@ -1,14 +1,14 @@
<div> <div>
<form class="login" (ngSubmit)="onLogin()" #loginForm="ngForm" (keydown.enter)="onLogin()"> <form class="login" (ngSubmit)="onLogin()" #loginForm="ngForm" (keydown.enter)="onLogin()">
<img src="assets/images/logo.png" alt="Opengnsys" class="login-logo" [class.rotating]="isLoading"> <img src="assets/images/logo.png" alt="Opengnsys" class="login-logo" [class.rotating]="isLoading">
<h2 i18n="@@headerOpengnsys">Opengnsys</h2> <h2>Opengnsys</h2>
<mat-form-field> <mat-form-field>
<mat-label i18n="@@loginlabelUsername">Introduce tu usuario</mat-label> <mat-label>{{ 'loginlabelUsername' | translate }}</mat-label>
<input matInput [(ngModel)]="loginObj.username" name="username" required #usernameInput="ngModel" <input matInput [(ngModel)]="loginObj.username" name="username" required #usernameInput="ngModel"
[ngClass]="{'invalid': !usernameInput.valid && usernameInput.touched}" /> [ngClass]="{'invalid': !usernameInput.valid && usernameInput.touched}" />
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label i18n="@@loginlabelPassword">Introduce tu contraseña</mat-label> <mat-label>{{ 'loginlabelPassword' | translate }}</mat-label>
<input matInput (keydown.enter)="$event.preventDefault()" [type]="hide() ? 'password' : 'text'" required <input matInput (keydown.enter)="$event.preventDefault()" [type]="hide() ? 'password' : 'text'" required
[(ngModel)]="loginObj.password" name="password" /> [(ngModel)]="loginObj.password" name="password" />
<button mat-icon-button matSuffix (click)="clickEvent($event)" [attr.aria-label]="'Ocultar contraseña'"> <button mat-icon-button matSuffix (click)="clickEvent($event)" [attr.aria-label]="'Ocultar contraseña'">
@ -17,14 +17,21 @@
</mat-form-field> </mat-form-field>
<div class="button-row"> <div class="button-row">
<button mat-flat-button color="primary" type="submit" [disabled]="!loginObj.username || !loginObj.password" <button mat-flat-button color="primary" type="submit" [disabled]="!loginObj.username || !loginObj.password">
i18n="@@buttonLogin">Iniciar sesión</button> {{ 'buttonLogin' | translate }}
</button>
</div> </div>
</form> </form>
</div> </div>
<<<<<<< Updated upstream
<!-- BORRAR DESPUES DE LA DEMO --> <!-- BORRAR DESPUES DE LA DEMO -->
<button mat-flat-button (click)="redirectToUrl1()">Español</button> <button mat-flat-button (click)="redirectToUrl1()">Español</button>
<!-- Botón para redirigir a http://localhost:4200/auth/login --> <!-- Botón para redirigir a http://localhost:4200/auth/login -->
<button mat-flat-button (click)="redirectToUrl2()">Inglés</button> <button mat-flat-button (click)="redirectToUrl2()">Inglés</button>
=======
<button mat-flat-button (click)="changeLanguage('es')">Español</button>
<button mat-flat-button (click)="changeLanguage('en')">Inglés</button>
>>>>>>> Stashed changes

View File

@ -1,6 +1,7 @@
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import {Component, signal} from '@angular/core'; import {Component, signal} from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import {ToastrService} from "ngx-toastr"; import {ToastrService} from "ngx-toastr";
@Component({ @Component({
@ -22,7 +23,15 @@ export class LoginComponent {
private http: HttpClient, private http: HttpClient,
private router: Router, private router: Router,
private toastService: ToastrService, private toastService: ToastrService,
) { } private translateService: TranslateService
) {
const savedLanguage = localStorage.getItem('language') || 'es';
this.translateService.use(savedLanguage);
}
ngOnInit() {
this.changeLanguage('es');
}
onLogin() { onLogin() {
this.errorMessage = ''; this.errorMessage = '';
@ -77,12 +86,8 @@ export class LoginComponent {
} }
} }
// SOLO PARA LA DEMO BORRAR EN PRODUCCIÓN changeLanguage(language: string) {
redirectToUrl1() { localStorage.setItem('language', language);
window.location.href = 'http://localhost:4200/auth/login'; this.translateService.use(language);
}
redirectToUrl2() {
window.location.href = 'http://localhost:4201/auth/login';
} }
} }

View File

@ -1,4 +1,5 @@
<div class="dashboard"> <div class="dashboard">
<<<<<<< Updated upstream
<h2>OgBoot server Status</h2> <h2>OgBoot server Status</h2>
<div class="disk-usage-container"> <div class="disk-usage-container">
@ -57,3 +58,73 @@
</table> </table>
</div> </div>
</div> </div>
=======
<div class="header-container">
<h2 joyrideStep="titleStep" text="Esta sección muestra el estado general del servidor OgBoot.">
{{ 'ogBootServerStatus' | translate }}
</h2>
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
</div>
<div class="disk-usage-container">
<!-- Disk Usage Section -->
<div class="disk-usage" joyrideStep="diskUsageStep" text="{{ 'diskUsageDescription' | translate }}">
<h3>{{ 'diskUsageTitle' | translate }}</h3>
<ngx-charts-pie-chart
[view]="view"
[scheme]="colorScheme"
[results]="diskUsageChartData"
[gradient]="gradient"
[doughnut]="isDoughnut"
[labels]="showLabels"
[legend]="showLegend">
</ngx-charts-pie-chart>
<div class="disk-usage-info">
<p>{{ 'totalLabel' | translate }}: {{ formatBytes(diskUsage.total) }}</p>
<p>{{ 'usedLabel' | translate }}: {{ formatBytes(diskUsage.used) }}</p>
<p>{{ 'availableLabel' | translate }}: {{ formatBytes(diskUsage.available) }}</p>
<p>{{ 'freeLabel' | translate }}: {{ diskUsage.percentage }}%</p>
</div>
</div>
<!-- Services Status Section -->
<div class="services-status" joyrideStep="servicesStatusStep" text="{{ 'servicesStatusDescription' | translate }}">
<h3>{{ 'servicesTitle' | translate }}</h3>
<ul>
<li *ngFor="let service of getServices()">
<span
class="status-led"
[ngClass]="{ 'active': service.status === 'active', 'inactive': service.status !== 'active' }"
></span>
{{ service.name }}: {{ service.status | translate }}
</li>
</ul>
</div>
</div>
<!-- Installed OgLives Section -->
<div class="installed-oglives" joyrideStep="oglivesStep" text="{{ 'oglivesDescription' | translate }}">
<h3>{{ 'installedOglivesTitle' | translate }}</h3>
<table>
<thead>
<tr>
<th>{{ 'idLabel' | translate }}</th>
<th>{{ 'kernelLabel' | translate }}</th>
<th>{{ 'architectureLabel' | translate }}</th>
<th>{{ 'revisionLabel' | translate }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let oglive of installedOglives">
<td>{{ oglive.id }}</td>
<td>{{ oglive.kernel }}</td>
<td>{{ oglive.architecture }}</td>
<td>{{ oglive.revision }}</td>
</tr>
</tbody>
</table>
</div>
</div>
>>>>>>> Stashed changes

View File

@ -1,8 +1,8 @@
<div class="create-PxeBootFile-container"> <div class="create-PxeBootFile-container">
<h1 mat-dialog-title>{{ isEditMode ? 'Editar Cliente' : 'Añadir Cliente' }}</h1> <h1 mat-dialog-title>{{ isEditMode ? ('editClientTitle' | translate) : ('addClientTitle' | translate) }}</h1>
<div class="mat-dialog-content"> <div class="mat-dialog-content">
<mat-form-field appearance="fill"> <mat-form-field appearance="fill">
<mat-label>Seleccione una plantilla PXE</mat-label> <mat-label>{{ 'selectPxeTemplateLabel' | translate }}</mat-label>
<mat-select [(value)]="selectedPxeTemplate"> <mat-select [(value)]="selectedPxeTemplate">
<mat-option *ngFor="let template of pxeTemplates" [value]="template.uuid"> <mat-option *ngFor="let template of pxeTemplates" [value]="template.uuid">
{{ template.name }} {{ template.name }}
@ -11,7 +11,9 @@
</mat-form-field> </mat-form-field>
</div> </div>
<div class="mat-dialog-actions"> <div class="mat-dialog-actions">
<button mat-button (click)="onCancel()">Cancelar</button> <button mat-button (click)="onCancel()">{{ 'cancelButton' | translate }}</button>
<button mat-button color="primary" (click)="onSave()">{{ isEditMode ? 'Guardar' : 'Añadir' }}</button> <button mat-button color="primary" (click)="onSave()">
{{ isEditMode ? ('saveButton' | translate) : ('addButton' | translate) }}
</button>
</div> </div>
</div> </div>

View File

@ -1,24 +1,47 @@
<div class="header-container"> <div class="header-container">
<<<<<<< Updated upstream
<h2 class="title">Netboot avanzado</h2> <h2 class="title">Netboot avanzado</h2>
</div> </div>
<div [formGroup]="taskForm" class="search-container"> <div [formGroup]="taskForm" class="search-container">
<mat-form-field appearance="fill" class="search-boolean"> <mat-form-field appearance="fill" class="search-boolean">
<mat-label>Selecciona Unidad Organizacional</mat-label> <mat-label>Selecciona Unidad Organizacional</mat-label>
=======
<h2 class="title" joyrideStep="titleStep" text="{{ 'advancedNetbootDescription' | translate }}">
{{ 'advancedNetbootTitle' | translate }}
</h2>
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
</div>
<div [formGroup]="taskForm" class="search-container">
<mat-form-field appearance="fill" class="search-boolean" joyrideStep="selectUnitStep" text="{{ 'selectUnitDescription' | translate }}">
<mat-label>{{ 'selectUnitLabel' | translate }}</mat-label>
>>>>>>> Stashed changes
<mat-select formControlName="organizationalUnit" (selectionChange)="onOrganizationalUnitChange()"> <mat-select formControlName="organizationalUnit" (selectionChange)="onOrganizationalUnitChange()">
<mat-option *ngIf="loadingUnits" disabled>Cargando unidades...</mat-option> <mat-option *ngIf="loadingUnits" disabled>{{ 'loadingUnitsOption' | translate }}</mat-option>
<mat-option *ngFor="let unit of availableOrganizationalUnits" [value]="unit['@id']"> <mat-option *ngFor="let unit of availableOrganizationalUnits" [value]="unit['@id']">
{{ unit.name }} {{ unit.name }}
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error *ngIf="taskForm.get('organizationalUnit')?.invalid">Este campo es obligatorio</mat-error> <mat-error *ngIf="taskForm.get('organizationalUnit')?.invalid">
{{ 'requiredFieldError' | translate }}
</mat-error>
</mat-form-field> </mat-form-field>
<<<<<<< Updated upstream
<mat-form-field appearance="fill" class="search-boolean"> <mat-form-field appearance="fill" class="search-boolean">
<mat-label>Selecciona aula</mat-label> <mat-label>Selecciona aula</mat-label>
=======
<mat-form-field appearance="fill" class="search-boolean" joyrideStep="selectClassStep" text="{{ 'selectClassDescription' | translate }}">
<mat-label>{{ 'selectClassLabel' | translate }}</mat-label>
>>>>>>> Stashed changes
<mat-select formControlName="selectedChild" (selectionChange)="onChildChange()"> <mat-select formControlName="selectedChild" (selectionChange)="onChildChange()">
<mat-option *ngIf="selectedUnitChildren.length === 0" disabled>No hay aulas disponibles</mat-option> <mat-option *ngIf="selectedUnitChildren.length === 0" disabled>
{{ 'noClassesOption' | translate }}
</mat-option>
<mat-option *ngFor="let child of selectedUnitChildren" [value]="child['@id']"> <mat-option *ngFor="let child of selectedUnitChildren" [value]="child['@id']">
{{ child.name }} {{ child.name }}
</mat-option> </mat-option>
@ -29,6 +52,7 @@
<mat-divider class="divider"></mat-divider> <mat-divider class="divider"></mat-divider>
<div class="global-selectors"> <div class="global-selectors">
<<<<<<< Updated upstream
<mat-form-field appearance="fill" class="selected-global"> <mat-form-field appearance="fill" class="selected-global">
<mat-label>Seleccione plantilla para aplicar a todos los clientes</mat-label> <mat-label>Seleccione plantilla para aplicar a todos los clientes</mat-label>
<mat-select [(value)]="globalOgLive" (selectionChange)="applyToAll()" > <mat-select [(value)]="globalOgLive" (selectionChange)="applyToAll()" >
@ -40,23 +64,51 @@
</div> </div>
<mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <mat-table [dataSource]="dataSource" class="mat-elevation-z8">
=======
<mat-form-field appearance="fill" class="selected-global" joyrideStep="applyToAllStep" text="{{ 'applyToAllDescription' | translate }}">
<mat-label>{{ 'applyToAllLabel' | translate }}</mat-label>
<mat-select [(value)]="globalOgLive" (selectionChange)="applyToAll()">
<mat-option *ngFor="let option of ogLiveOptions" [value]="option['@id']">
{{ option.name }}
</mat-option>
</mat-select>
</mat-form-field>
<button
mat-flat-button
color="primary"
[disabled]="selectedUnitChildren.length === 0"
(click)="saveOgLiveTemplates()"
joyrideStep="saveButtonStep"
text="{{ 'saveButtonDescription' | translate }}">
{{ 'saveButtonLabel' | translate }}
</button>
</div>
<mat-table [dataSource]="dataSource" class="mat-elevation-z8" joyrideStep="tableStep" text="{{ 'tableDescription' | translate }}">
>>>>>>> Stashed changes
<ng-container matColumnDef="id"> <ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef> Id </mat-header-cell> <mat-header-cell *matHeaderCellDef>{{ 'idColumnHeader' | translate }}</mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.id}} </mat-cell> <mat-cell *matCellDef="let element"> {{ element.id }} </mat-cell>
</ng-container> </ng-container>
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Nombre </mat-header-cell> <mat-header-cell *matHeaderCellDef>{{ 'nameColumnHeader' | translate }}</mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.name}} </mat-cell> <mat-cell *matCellDef="let element"> {{ element.name }} </mat-cell>
</ng-container> </ng-container>
<ng-container matColumnDef="ogLive"> <ng-container matColumnDef="ogLive">
<mat-header-cell *matHeaderCellDef> Plantilla </mat-header-cell> <mat-header-cell *matHeaderCellDef>{{ 'templateColumnHeader' | translate }}</mat-header-cell>
<mat-cell *matCellDef="let client"> <mat-cell *matCellDef="let client">
<<<<<<< Updated upstream
<mat-form-field appearance="fill"> <mat-form-field appearance="fill">
<mat-label>Seleccione una plantilla</mat-label> <mat-label>Seleccione una plantilla</mat-label>
=======
<mat-form-field appearance="fill" joyrideStep="selectTemplateStep" text="{{ 'selectTemplateDescription' | translate }}">
<mat-label>{{ 'selectTemplateLabel' | translate }}</mat-label>
>>>>>>> Stashed changes
<mat-select [(ngModel)]="client.ogLive" [name]="'ogLive' + client.id"> <mat-select [(ngModel)]="client.ogLive" [name]="'ogLive' + client.id">
<mat-option [value]="null">Ninguna</mat-option> <mat-option [value]="null">{{ 'noTemplateOption' | translate }}</mat-option>
<mat-option *ngFor="let template of ogLiveOptions" [value]="template['@id']"> <mat-option *ngFor="let template of ogLiveOptions" [value]="template['@id']">
{{ template.name }} {{ template.name }}
</mat-option> </mat-option>

View File

@ -1,32 +1,64 @@
<mat-accordion class="example-headers-align"> <mat-accordion class="example-headers-align">
<mat-expansion-panel hideToggle> <mat-expansion-panel hideToggle>
<<<<<<< Updated upstream
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> Información en servidor ogBoot </mat-panel-title> <mat-panel-title> Información en servidor ogBoot </mat-panel-title>
=======
<mat-expansion-panel-header joyrideStep="serverInfoStep" [text]="'serverInfoDescription' | translate">
<mat-panel-title>{{ 'serverInfoTitle' | translate }}</mat-panel-title>
>>>>>>> Stashed changes
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div class="button-row"> <div class="button-row">
<<<<<<< Updated upstream
<button mat-flat-button color="primary" (click)="syncOgBoot()"> Sincronizar base de datos</button> <button mat-flat-button color="primary" (click)="syncOgBoot()"> Sincronizar base de datos</button>
</div> </div>
<div class="button-row"> <div class="button-row">
<button mat-flat-button color="accent" (click)="openSubnetInfoDialog()">Ver Información</button> <button mat-flat-button color="accent" (click)="openSubnetInfoDialog()">Ver Información</button>
=======
<button mat-flat-button color="primary" (click)="syncOgBoot()">{{ 'syncDatabaseButton' | translate }}</button>
</div>
<div class="button-row">
<button mat-flat-button color="accent" (click)="openSubnetInfoDialog()">{{ 'viewInfoButton' | translate }}</button>
>>>>>>> Stashed changes
</div> </div>
</mat-expansion-panel> </mat-expansion-panel>
</mat-accordion> </mat-accordion>
<div class="header-container"> <div class="header-container">
<<<<<<< Updated upstream
<h2 class="title" i18n="@@adminImagesTitle">Administrar imágenes</h2> <h2 class="title" i18n="@@adminImagesTitle">Administrar imágenes</h2>
<div class="images-button-row"> <div class="images-button-row">
<button mat-flat-button color="primary" (click)="addImage()">Añadir imagen</button> <button mat-flat-button color="primary" (click)="addImage()">Añadir imagen</button>
=======
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<h2 class="title" joyrideStep="titleStep" [text]="'adminImagesDescription' | translate">
{{ 'adminImagesTitle' | translate }}
</h2>
<div class="images-button-row">
<button mat-flat-button color="primary" (click)="addImage()" joyrideStep="addImageStep" [text]="'addImageButtonDescription' | translate">
{{ 'addImageButton' | translate }}
</button>
>>>>>>> Stashed changes
</div> </div>
</div> </div>
<mat-divider class="divider"></mat-divider> <mat-divider class="divider"></mat-divider>
<div class="search-container"> <div class="search-container">
<<<<<<< Updated upstream
<mat-form-field appearance="fill" class="search-string"> <mat-form-field appearance="fill" class="search-string">
<mat-label i18n="@@searchLabel">Buscar nombre de imagen</mat-label> <mat-label i18n="@@searchLabel">Buscar nombre de imagen</mat-label>
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder"> <input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder">
=======
<mat-form-field appearance="fill" class="search-string" joyrideStep="searchNameStep" [text]="'searchNameDescription' | translate">
<mat-label>{{ 'searchLabel' | translate }}</mat-label>
<input matInput [placeholder]="'searchPlaceholder' | translate" [(ngModel)]="filters['name']" (keyup.enter)="search()">
>>>>>>> Stashed changes
<mat-icon matSuffix>search</mat-icon> <mat-icon matSuffix>search</mat-icon>
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint> <mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field> </mat-form-field>
<<<<<<< Updated upstream
<mat-form-field appearance="fill" class="search-boolean"> <mat-form-field appearance="fill" class="search-boolean">
<mat-label i18n="@@searchLabel">Imagen por defecto</mat-label> <mat-label i18n="@@searchLabel">Imagen por defecto</mat-label>
<mat-select [(ngModel)]="filters['isDefault']" (selectionChange)="search()" placeholder="Seleccionar opción" > <mat-select [(ngModel)]="filters['isDefault']" (selectionChange)="search()" placeholder="Seleccionar opción" >
@ -49,9 +81,40 @@
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th> <th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
<td mat-cell *matCellDef="let image" > <td mat-cell *matCellDef="let image" >
=======
<mat-form-field appearance="fill" class="search-boolean" joyrideStep="searchDefaultImageStep" [text]="'searchDefaultDescription' | translate">
<mat-label>{{ 'searchDefaultLabel' | translate }}</mat-label>
<mat-select [(ngModel)]="filters['isDefault']" (selectionChange)="search()" [placeholder]="'selectOptionPlaceholder' | translate">
<mat-option [value]="''">{{ 'allOption' | translate }}</mat-option>
<mat-option [value]="true">{{ 'yesOption' | translate }}</mat-option>
<mat-option [value]="false">{{ 'noOption' | translate }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill" class="search-boolean" joyrideStep="searchInstalledStep" [text]="'searchInstalledDescription' | translate">
<mat-label>{{ 'searchInstalledLabel' | translate }}</mat-label>
<mat-select [(ngModel)]="filters['installed']" (selectionChange)="search()" [placeholder]="'selectOptionPlaceholder' | translate">
<mat-option [value]="''">{{ 'allOption' | translate }}</mat-option>
<mat-option [value]="true">{{ 'yesOption' | translate }}</mat-option>
<mat-option [value]="false">{{ 'noOption' | translate }}</mat-option>
</mat-select>
</mat-form-field>
</div>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" joyrideStep="tableStep" [text]="'tableDescription' | translate">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef>{{ column.header }}</th>
<td mat-cell *matCellDef="let image">
>>>>>>> Stashed changes
<ng-container *ngIf="column.columnDef === 'isDefault' || column.columnDef === 'installed'"> <ng-container *ngIf="column.columnDef === 'isDefault' || column.columnDef === 'installed'">
<mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'"> <mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'">
{{ image[column.columnDef] ? 'check_circle' : 'cancel' }} <ng-container *ngIf="image[column.columnDef]; else cancelIcon">
{{ 'checkCircle' | translate }}
</ng-container>
<ng-template #cancelIcon>
{{ 'cancelIcon' | translate }}
</ng-template>
</mat-icon> </mat-icon>
</ng-container> </ng-container>
@ -73,7 +136,7 @@
</mat-chip> </mat-chip>
</ng-container> </ng-container>
<ng-container *ngIf="column.columnDef !== 'isDefault' && column.columnDef !== 'installed' && column.columnDef !== 'downloadUrl' && column.columnDef !== 'status' && column.columnDef !== 'name' "> <ng-container *ngIf="column.columnDef !== 'isDefault' && column.columnDef !== 'installed' && column.columnDef !== 'downloadUrl' && column.columnDef !== 'status' && column.columnDef !== 'name'">
{{ column.cell(image) }} {{ column.cell(image) }}
</ng-container> </ng-container>
@ -81,18 +144,36 @@
</ng-container> </ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<<<<<<< Updated upstream
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions">Acciones</th> <th mat-header-cell *matHeaderCellDef i18n="@@columnActions">Acciones</th>
<td mat-cell *matCellDef="let image"> <td mat-cell *matCellDef="let image">
<button mat-icon-button color="info" (click)="showOgLive($event, image)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button> <button mat-icon-button color="info" (click)="showOgLive($event, image)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button>
<button mat-icon-button color="primary" (click)="editImage(image)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button> <button mat-icon-button color="primary" (click)="editImage(image)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
<button mat-icon-button color="warn" (click)="deleteImage(image)" i18n="@@buttonDelete"><mat-icon>delete</mat-icon></button> <button mat-icon-button color="warn" (click)="deleteImage(image)" i18n="@@buttonDelete"><mat-icon>delete</mat-icon></button>
=======
<th mat-header-cell *matHeaderCellDef>{{ 'actionsColumnHeader' | translate }}</th>
<td mat-cell *matCellDef="let image" joyrideStep="actionsStep" [text]="'actionsDescription' | translate">
<button mat-icon-button color="info" (click)="showOgLive($event, image)">
<mat-icon>{{ 'viewIcon' | translate }}</mat-icon>
</button>
<button mat-icon-button color="primary" (click)="editImage(image)">
<mat-icon>{{ 'editIcon' | translate }}</mat-icon>
</button>
<button mat-icon-button color="warn" (click)="deleteImage(image)">
<mat-icon>{{ 'deleteIcon' | translate }}</mat-icon>
</button>
>>>>>>> Stashed changes
<button mat-icon-button [matMenuTriggerFor]="menu"> <button mat-icon-button [matMenuTriggerFor]="menu">
<mat-icon>menu</mat-icon> <mat-icon>menu</mat-icon>
</button> </button>
<mat-menu #menu="matMenu"> <mat-menu #menu="matMenu">
<button mat-menu-item (click)="toggleAction(image, 'install')">Instalar</button> <button mat-menu-item (click)="toggleAction(image, 'install')">{{ 'installOption' | translate }}</button>
<button mat-menu-item [disabled]="!image.installed" (click)="toggleAction(image, 'uninstall')">Desinstalar</button> <button mat-menu-item [disabled]="!image.installed" (click)="toggleAction(image, 'uninstall')">
<button mat-menu-item [disabled]="!image.installed" (click)="toggleAction(image, 'set-default')">Cambiar a imagen por defecto</button> {{ 'uninstallOption' | translate }}
</button>
<button mat-menu-item [disabled]="!image.installed" (click)="toggleAction(image, 'set-default')">
{{ 'setDefaultOption' | translate }}
</button>
</mat-menu> </mat-menu>
</td> </td>
</ng-container> </ng-container>
@ -100,7 +181,12 @@
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table> </table>
<<<<<<< Updated upstream
<div class="paginator-container"> <div class="paginator-container">
=======
<div class="paginator-container" joyrideStep="paginationStep" [text]="'paginationDescription' | translate">
>>>>>>> Stashed changes
<mat-paginator [length]="length" <mat-paginator [length]="length"
[pageSize]="itemsPerPage" [pageSize]="itemsPerPage"
[pageIndex]="page" [pageIndex]="page"

View File

@ -1,22 +1,32 @@
<h2 mat-dialog-title>Añade clientes a {{data.subnetName}}</h2> <h2 mat-dialog-title>{{ 'addClientsTitle' | translate: { subnetName: data.subnetName } }}</h2>
<mat-dialog-content> <mat-dialog-content>
<mat-form-field appearance="fill" class="search-select"> <mat-form-field appearance="fill" class="search-select">
<input type="text" matInput [formControl]="clientControl" [matAutocomplete]="clientAuto" placeholder="Seleccione un cliente"> <input
<mat-autocomplete #clientAuto="matAutocomplete" [displayWith]="displayFnClient" (optionSelected)="onOptionClientSelected($event.option.value)"> type="text"
<mat-option *ngFor="let client of filteredClients | async" [value]="client"> matInput
[formControl]="clientControl"
[matAutocomplete]="clientAuto"
[placeholder]="'selectClientPlaceholder' | translate">
<mat-autocomplete
#clientAuto="matAutocomplete"
[displayWith]="displayFnClient"
(optionSelected)="onOptionClientSelected($event.option.value)">
<mat-option
*ngFor="let client of filteredClients | async"
[value]="client">
{{ client.name }} {{ client.name }}
</mat-option> </mat-option>
</mat-autocomplete> </mat-autocomplete>
</mat-form-field> </mat-form-field>
<div *ngIf="selectedClients.length > 0"> <div *ngIf="selectedClients.length > 0">
<h3>Clientes seleccionados:</h3> <h3>{{ 'selectedClientsTitle' | translate }}</h3>
<ul> <ul>
<li *ngFor="let client of selectedClients"> <li *ngFor="let client of selectedClients">
{{ client.name }} {{ client.name }}
<button mat-icon-button color="warn" (click)="removeClient(client)"> <button mat-icon-button color="warn" (click)="removeClient(client)">
<mat-icon>delete</mat-icon> <mat-icon>{{ 'deleteIcon' | translate }}</mat-icon>
</button> </button>
</li> </li>
</ul> </ul>
@ -24,6 +34,6 @@
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions> <mat-dialog-actions>
<button mat-button (click)="close()">Cancelar</button> <button mat-button (click)="close()">{{ 'cancelButton' | translate }}</button>
<button mat-button (click)="save()">Añadir</button> <button mat-button (click)="save()">{{ 'addButton' | translate }}</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,19 +1,25 @@
<h2 mat-dialog-title>Gestionar clientes </h2> <h2 mat-dialog-title>{{ 'manageClientsTitle' | translate }}</h2>
<mat-dialog-content> <mat-dialog-content>
<mat-list> <mat-list>
<ng-container *ngFor="let client of clients"> <ng-container *ngFor="let client of clients">
<mat-list-item > <mat-list-item>
<div class="list-item-content"> <div class="list-item-content">
<mat-icon matListItemIcon [ngClass]="{'red-icon': client.pxeSync === false || !client.pxeSync, 'green-icon': client.pxeSync === true}">computer</mat-icon> <mat-icon matListItemIcon [ngClass]="{'red-icon': client.pxeSync === false || !client.pxeSync, 'green-icon': client.pxeSync === true}">
computer
</mat-icon>
<div class="text-content"> <div class="text-content">
<div matListItemTitle>{{ client.name }}</div> <div matListItemTitle>{{ client.name }}</div>
<div matListItemLine>{{ client.mac }}</div> <div matListItemLine>{{ client.mac }}</div>
</div> </div>
<div class="icon-container"> <div class="icon-container">
<button mat-icon-button color="info" (click)="showInfo(client)" i18n="@@editImage"> <mat-icon>visibility</mat-icon></button> <button mat-icon-button color="info" (click)="showInfo(client)">
<button mat-icon-button color="primary" (click)="addClientToTemplate(client)" i18n="@@editImage"> <mat-icon>sync</mat-icon></button> <mat-icon>{{ 'viewIcon' | translate }}</mat-icon>
</button>
<button mat-icon-button color="primary" (click)="addClientToTemplate(client)">
<mat-icon>{{ 'syncIcon' | translate }}</mat-icon>
</button>
<button mat-icon-button color="warn" class="right-icon" (click)="deleteClient(client)"> <button mat-icon-button color="warn" class="right-icon" (click)="deleteClient(client)">
<mat-icon>delete</mat-icon> <mat-icon>{{ 'deleteIcon' | translate }}</mat-icon>
</button> </button>
</div> </div>
</div> </div>
@ -22,5 +28,5 @@
</mat-list> </mat-list>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button type="button" (click)="onCancel()">Cancelar</button> <button mat-button type="button" (click)="onCancel()">{{ 'cancelButton' | translate }}</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,31 +1,55 @@
<<<<<<< Updated upstream
<h2 mat-dialog-title>{{ isEditMode ? 'Editar' : 'Añadir' }} plantilla </h2> <h2 mat-dialog-title>{{ isEditMode ? 'Editar' : 'Añadir' }} plantilla </h2>
=======
<h2 mat-dialog-title>{{ isEditMode ? ('editTemplateTitle' | translate) : ('addTemplateTitle' | translate) }}</h2>
>>>>>>> Stashed changes
<mat-dialog-content> <mat-dialog-content>
<div class="spacing-container"> <div class="spacing-container">
<form [formGroup]="templateForm" (ngSubmit)="onSave()"> <form [formGroup]="templateForm" (ngSubmit)="onSave()">
<mat-form-field appearance="fill"> <mat-form-field appearance="fill">
<mat-label>Nombre de la Plantilla</mat-label> <mat-label>{{ 'templateNameLabel' | translate }}</mat-label>
<input matInput formControlName="name" placeholder="Introduce el nombre de la plantilla"> <input matInput formControlName="name" [placeholder]="'templateNamePlaceholder' | translate">
<mat-error *ngIf="templateForm.get('name')?.hasError('required')"> <mat-error *ngIf="templateForm.get('name')?.hasError('required')">
El nombre de la plantilla es requerido. {{ 'templateNameError' | translate }}
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill"> <mat-form-field appearance="fill">
<mat-label>Contenido de la Plantilla</mat-label> <mat-label>{{ 'templateContentLabel' | translate }}</mat-label>
<textarea matInput formControlName="templateContent" rows="20" placeholder="Introduce el contenido de la plantilla"></textarea> <textarea matInput formControlName="templateContent" rows="20" [placeholder]="'templateContentPlaceholder' | translate"></textarea>
<mat-error *ngIf="templateForm.get('templateContent')?.hasError('required')"> <mat-error *ngIf="templateForm.get('templateContent')?.hasError('required')">
El contenido de la plantilla es requerido. {{ 'templateContentError' | translate }}
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
</form> </form>
</div> </div>
</mat-dialog-content> </mat-dialog-content>
<<<<<<< Updated upstream
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button type="button" (click)="onCancel()">Cancelar</button> <button mat-button type="button" (click)="onCancel()">Cancelar</button>
<button mat-raised-button color="primary" type="submit" (click)="onSave()" [disabled]="!templateForm.valid"> <button mat-raised-button color="primary" type="submit" (click)="onSave()" [disabled]="!templateForm.valid">
{{ isEditMode ? 'Actualizar' : 'Crear' }} {{ isEditMode ? 'Actualizar' : 'Crear' }}
</button> </button>
=======
<mat-dialog-actions>
<div class="actions-container">
<button mat-flat-button color="accent" [matMenuTriggerFor]="templateMenu">
{{ 'loadTemplateModelButton' | translate }}
</button>
<mat-menu #templateMenu="matMenu">
<button mat-menu-item (click)="loadTemplateModel('ogLive')">{{ 'ogLiveModel' | translate }}</button>
<button mat-menu-item (click)="loadTemplateModel('disco')">{{ 'diskModel' | translate }}</button>
</mat-menu>
<div class="action-buttons">
<button mat-button type="button" (click)="onCancel()">{{ 'cancelButton' | translate }}</button>
<button mat-raised-button color="primary" type="submit" (click)="onSave()" [disabled]="!templateForm.valid">
{{ isEditMode ? ('updateButton' | translate) : ('createButton' | translate) }}
</button>
</div>
</div>
>>>>>>> Stashed changes
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,32 +1,56 @@
<mat-accordion class="example-headers-align"> <mat-accordion class="example-headers-align">
<mat-expansion-panel hideToggle> <mat-expansion-panel hideToggle>
<<<<<<< Updated upstream
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> Información en servidor ogBoot </mat-panel-title> <mat-panel-title> Información en servidor ogBoot </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div class="example-button-row"> <div class="example-button-row">
<button mat-flat-button color="primary" (click)="syncTemplates()"> Sincronizar base de datos</button> <button mat-flat-button color="primary" (click)="syncTemplates()"> Sincronizar base de datos</button>
=======
<mat-expansion-panel-header joyrideStep="serverInfoStep" text="{{ 'serverInfoDescription' | translate }}">
<mat-panel-title>{{ 'serverInfoTitle' | translate }}</mat-panel-title>
</mat-expansion-panel-header>
<div class="example-button-row">
<button mat-flat-button color="primary" (click)="syncTemplates()">{{ 'syncDatabaseButton' | translate }}</button>
>>>>>>> Stashed changes
</div> </div>
<div class="example-button-row"> <div class="example-button-row">
<button mat-flat-button color="accent" (click)="openSubnetInfoDialog()">Ver Información</button> <button mat-flat-button color="accent" (click)="openSubnetInfoDialog()">{{ 'viewInfoButton' | translate }}</button>
</div> </div>
</mat-expansion-panel> </mat-expansion-panel>
</mat-accordion> </mat-accordion>
<div class="header-container"> <div class="header-container">
<<<<<<< Updated upstream
<h2 class="title" i18n="@@adminPXETitle">Administrar plantillas PXE</h2> <h2 class="title" i18n="@@adminPXETitle">Administrar plantillas PXE</h2>
<div class="pxe-button-row"> <div class="pxe-button-row">
<button mat-flat-button color="primary" (click)="addPxeTemplate()">Añadir plantilla PXE</button> <button mat-flat-button color="primary" (click)="addPxeTemplate()">Añadir plantilla PXE</button>
=======
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<h2 class="title" joyrideStep="titleStep" text="{{ 'adminPxeDescription' | translate }}">{{ 'adminPxeTitle' | translate }}</h2>
<div class="pxe-button-row">
<button mat-flat-button color="primary" (click)="addPxeTemplate()" joyrideStep="addTemplateStep" text="{{ 'addTemplateButtonDescription' | translate }}">{{ 'addTemplateButton' | translate }}</button>
>>>>>>> Stashed changes
</div> </div>
</div> </div>
<mat-divider class="divider"></mat-divider> <mat-divider class="divider"></mat-divider>
<div class="search-container"> <div class="search-container">
<<<<<<< Updated upstream
<mat-form-field appearance="fill" class="search-string"> <mat-form-field appearance="fill" class="search-string">
<mat-label i18n="@@searchLabel">Buscar nombre de plantilla</mat-label> <mat-label i18n="@@searchLabel">Buscar nombre de plantilla</mat-label>
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder"> <input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder">
=======
<mat-form-field appearance="fill" class="search-string" joyrideStep="searchNameStep" text="{{ 'searchNameDescription' | translate }}">
<mat-label>{{ 'searchLabel' | translate }}</mat-label>
<input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()">
>>>>>>> Stashed changes
<mat-icon matSuffix>search</mat-icon> <mat-icon matSuffix>search</mat-icon>
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint> <mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field> </mat-form-field>
<<<<<<< Updated upstream
<mat-form-field appearance="fill" class="search-boolean"> <mat-form-field appearance="fill" class="search-boolean">
<mat-label i18n="@@searchLabel">Creada en ogBoot</mat-label> <mat-label i18n="@@searchLabel">Creada en ogBoot</mat-label>
<mat-select [(ngModel)]="filters['synchronized']" (selectionChange)="search()" placeholder="Seleccionar opción" > <mat-select [(ngModel)]="filters['synchronized']" (selectionChange)="search()" placeholder="Seleccionar opción" >
@ -40,33 +64,69 @@
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef"> <ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th> <th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
<td mat-cell *matCellDef="let image" > <td mat-cell *matCellDef="let image" >
=======
<mat-form-field appearance="fill" class="search-boolean" joyrideStep="searchSyncStep" text="{{ 'searchSyncDescription' | translate }}">
<mat-label>{{ 'createdInOgbootLabel' | translate }}</mat-label>
<mat-select [(ngModel)]="filters['synchronized']" (selectionChange)="search()" placeholder="{{ 'selectOptionPlaceholder' | translate }}">
<mat-option [value]="''">{{ 'allOption' | translate }}</mat-option>
<mat-option [value]="true">{{ 'yesOption' | translate }}</mat-option>
<mat-option [value]="false">{{ 'noOption' | translate }}</mat-option>
</mat-select>
</mat-form-field>
</div>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" joyrideStep="tableStep" text="{{ 'tableDescription' | translate }}">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef>{{ column.header }}</th>
<td mat-cell *matCellDef="let image">
>>>>>>> Stashed changes
<ng-container *ngIf="column.columnDef === 'synchronized'"> <ng-container *ngIf="column.columnDef === 'synchronized'">
<mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'"> <mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'">
{{ image[column.columnDef] ? 'check_circle' : 'cancel' }} {{ image[column.columnDef] ? 'check_circle' : 'cancel' }}
</mat-icon> </mat-icon>
</ng-container> </ng-container>
<ng-container *ngIf="column.columnDef !== 'synchronized'"> <ng-container *ngIf="column.columnDef !== 'synchronized'">
{{ column.cell(image) }} {{ column.cell(image) }}
</ng-container> </ng-container>
</td> </td>
</ng-container> </ng-container>
<<<<<<< Updated upstream
<ng-container matColumnDef="actions" > <ng-container matColumnDef="actions" >
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th> <th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
<td mat-cell *matCellDef="let template" style="text-align: center;"> <td mat-cell *matCellDef="let template" style="text-align: center;">
<button mat-icon-button color="info" (click)="showTemplate($event, template)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button> <button mat-icon-button color="info" (click)="showTemplate($event, template)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button>
<button mat-icon-button color="info" [disabled]="template.clientsLength === 0" (click)="editClients($event, template)"><mat-icon i18n="@@deleteElementTooltip">computer</mat-icon></button> <button mat-icon-button color="info" [disabled]="template.clientsLength === 0" (click)="editClients($event, template)"><mat-icon i18n="@@deleteElementTooltip">computer</mat-icon></button>
<button mat-icon-button color="primary" (click)="editPxeTemplate(template)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button> <button mat-icon-button color="primary" (click)="editPxeTemplate(template)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
=======
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef>{{ 'actionsColumn' | translate }}</th>
<td mat-cell *matCellDef="let template">
<button mat-icon-button color="info" (click)="showTemplate($event, template)">
<mat-icon>visibility</mat-icon>
</button>
<button mat-icon-button color="info" [disabled]="template.clientsLength === 0" (click)="editClients($event, template)">
<mat-icon>computer</mat-icon>
</button>
<button mat-icon-button color="primary" (click)="editPxeTemplate(template)">
<mat-icon>edit</mat-icon>
</button>
>>>>>>> Stashed changes
<button mat-icon-button [matMenuTriggerFor]="menu"> <button mat-icon-button [matMenuTriggerFor]="menu">
<mat-icon>menu</mat-icon> <mat-icon>menu</mat-icon>
</button> </button>
<mat-menu #menu="matMenu"> <mat-menu #menu="matMenu">
<<<<<<< Updated upstream
<button mat-menu-item (click)="toggleAction(template, 'create')">Crear en servidor ogBoot</button> <button mat-menu-item (click)="toggleAction(template, 'create')">Crear en servidor ogBoot</button>
<button mat-menu-item (click)="addClientsToPxe(template)">Añadir cliente</button> <button mat-menu-item (click)="addClientsToPxe(template)">Añadir cliente</button>
<button mat-menu-item (click)="toggleAction(template, 'sync')">Sincronizar base de datos</button> <button mat-menu-item (click)="toggleAction(template, 'sync')">Sincronizar base de datos</button>
<button mat-menu-item (click)="toggleAction(template, 'delete')">Eliminar</button> <button mat-menu-item (click)="toggleAction(template, 'delete')">Eliminar</button>
=======
<button mat-menu-item (click)="toggleAction(template, 'create')">{{ 'createServerButton' | translate }}</button>
<button mat-menu-item (click)="addClientsToPxe(template)">{{ 'addClientButton' | translate }}</button>
<button mat-menu-item (click)="toggleAction(template, 'sync')">{{ 'syncDatabaseButton' | translate }}</button>
<button mat-menu-item (click)="toggleAction(template, 'delete')">{{ 'deleteButton' | translate }}</button>
>>>>>>> Stashed changes
</mat-menu> </mat-menu>
</td> </td>
</ng-container> </ng-container>
@ -74,7 +134,12 @@
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table> </table>
<<<<<<< Updated upstream
<div class="paginator-container"> <div class="paginator-container">
=======
<div class="paginator-container" joyrideStep="paginationStep" text="{{ 'paginationDescription' | translate }}">
>>>>>>> Stashed changes
<mat-paginator [length]="length" <mat-paginator [length]="length"
[pageSize]="itemsPerPage" [pageSize]="itemsPerPage"
[pageIndex]="page" [pageIndex]="page"

View File

@ -1,4 +1,4 @@
<div class="info-container"> <div class="info-container">
<h3>Detalles de {{ data.data.name }}</h3> <h3>{{ 'detailsTitle' | translate: { name: data.data.name } }}</h3>
<pre class="code-block">{{ data.data.templateContent }}</pre> <pre class="code-block">{{ data.data.templateContent }}</pre>
</div> </div>

View File

@ -0,0 +1,51 @@
<div class="header-container">
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<h2 class="title" joyrideStep="titleStep" text="Desde esta pantalla podrás ver y administrar los respositioros exitentes.">Administrar repositorios</h2>
<div class="images-button-row">
<button mat-flat-button color="primary" (click)="addImage()" joyrideStep="addStep" text="Utiliza este botón para añadir un nuevo repositorio.">Añadir repositorio</button>
</div>
</div>
<mat-divider class="divider"></mat-divider>
<div class="search-container">
<mat-form-field appearance="fill" class="search-string">
<mat-label>Buscar nombre de imagen</mat-label>
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder">
<mat-icon matSuffix>search</mat-icon>
<mat-hint>Pulsar 'enter' para buscar</mat-hint>
</mat-form-field>
</div>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
<td mat-cell *matCellDef="let repository" >
<ng-container>
{{ column.cell(repository) }}
</ng-container>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
<td mat-cell *matCellDef="let client" style="text-align: center;">
<button mat-icon-button color="primary" (click)="editRepository($event, client)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
<button mat-icon-button color="warn" (click)="deleteRepository($event, client)">
<mat-icon i18n="@@deleteElementTooltip">delete</mat-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<div class="paginator-container">
<mat-paginator [length]="length"
[pageSize]="itemsPerPage"
[pageIndex]="page"
[pageSizeOptions]="[5, 10, 20, 40, 100]"
(page)="onPageChange($event)">
</mat-paginator>
</div>

View File

@ -0,0 +1,134 @@
import { Component } from '@angular/core';
import {MatTableDataSource} from "@angular/material/table";
import {DatePipe} from "@angular/common";
import {MatDialog} from "@angular/material/dialog";
import {HttpClient} from "@angular/common/http";
import {ToastrService} from "ngx-toastr";
import {CreateImageComponent} from "../images/create-image/create-image.component";
import {DeleteModalComponent} from "../../shared/delete_modal/delete-modal/delete-modal.component";
import {CreateRepositoryComponent} from "./create-repository/create-repository.component";
import { JoyrideService } from 'ngx-joyride';
@Component({
selector: 'app-repositories',
templateUrl: './repositories.component.html',
styleUrl: './repositories.component.css'
})
export class RepositoriesComponent {
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
dataSource = new MatTableDataSource<any>();
length: number = 0;
itemsPerPage: number = 10;
page: number = 0;
loading: boolean = false;
filters: { [key: string]: string } = {};
datePipe: DatePipe = new DatePipe('es-ES');
columns = [
{
columnDef: 'id',
header: 'Id',
cell: (repository: any) => `${repository.id}`
},
{
columnDef: 'name',
header: 'Nombre de repositorio',
cell: (repository: any) => `${repository.name}`
},
{
columnDef: 'ip',
header: 'Ip',
cell: (repository: any) => `${repository.ip}`
},
{
columnDef: 'createdAt',
header: 'Fecha de creación',
cell: (repository: any) => `${this.datePipe.transform(repository.createdAt, 'dd/MM/yyyy hh:mm:ss')}`
}
];
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
private apiUrl = `${this.baseUrl}/image-repositories`;
constructor(
public dialog: MatDialog,
private http: HttpClient,
private toastService: ToastrService,
private joyrideService: JoyrideService
) {}
ngOnInit(): void {
this.search();
}
addImage(): void {
const dialogRef = this.dialog.open(CreateRepositoryComponent, {
width: '600px'
});
dialogRef.afterClosed().subscribe(() => {
this.search();
});
}
search(): void {
this.loading = true;
this.http.get<any>(`${this.apiUrl}?page=${this.page +1 }&itemsPerPage=${this.itemsPerPage}`, { params: this.filters }).subscribe(
data => {
this.dataSource.data = data['hydra:member'];
this.length = data['hydra:totalItems'];
this.loading = false;
},
error => {
console.error('Error fetching images', error);
this.loading = false;
}
);
}
editRepository(event: MouseEvent, repository: any): void {
event.stopPropagation();
this.dialog.open(CreateRepositoryComponent, {
width: '600px',
data: repository['@id']
}).afterClosed().subscribe(() => this.search());
}
deleteRepository(event: MouseEvent,command: any): void {
event.stopPropagation();
this.dialog.open(DeleteModalComponent, {
width: '300px',
data: { name: command.name },
}).afterClosed().subscribe((result) => {
if (result) {
this.http.delete(`${this.apiUrl}/${command.uuid}`).subscribe({
next: () => {
this.toastService.success('Imagen eliminada con éxito');
this.search();
},
error: (error) => {
console.error('Error al eliminar la imagen:', error);
}
});
}
});
}
onPageChange(event: any): void {
this.page = event.pageIndex;
this.itemsPerPage = event.pageSize;
this.length = event.length;
this.search();
}
iniciarTour(): void {
this.joyrideService.startTour({
steps: [
'titleStep',
'addStep',
],
showPrevButton: true,
themeColor: '#3f51b5'
});
}
}

View File

@ -0,0 +1,47 @@
{
"loginlabelUsername": "Enter your username",
"loginlabelPassword": "Enter your password",
"buttonLogin": "Login",
"welcomeMessage": "Welcome {{username}}",
"loginError": "Login error: {{error}}",
"labelUsers": "Users",
"labelRoles": "Roles",
"adminImagesTitle": "Manage Users",
"addUser": "Add Users",
"searchLabel": "Search Username",
"searchPlaceholder": "Search",
"searchHint": "Press 'enter' to search",
"columnActions": "Actions",
"dialogTitleAddUser": "Add User",
"addUserlabelUsername": "Username",
"addUserlabelPassword": "Password",
"labelRole": "Role",
"labelOrganizationalUnit": "Organizational Unit",
"buttonCancel": "Cancel",
"buttonAdd": "Add",
"dialogTitleEditUser": "Edit User",
"labelCurrentPassword": "Current Password",
"labelNewPassword": "New Password",
"labelRepeatPassword": "Repeat Password",
"errorPasswordMismatch": "Passwords do not match",
"buttonEdit": "Edit",
"adminRolesTitle": "Manage Roles",
"addRole": "Add Role",
"searchRoleLabel": "Search Role Name",
"dialogTitleAddRole": "Add Role",
"labelRoleName": "Name",
"sectionTitlePermissions": "Permissions:",
"checkboxSuperAdmin": "Super Admin",
"checkboxOrgAdmin": "Organizational Unit Admin",
"checkboxOrgOperator": "Organizational Unit Operator",
"checkboxOrgMinimal": "Minimal Organizational Unit",
"checkboxUserRole": "User",
"titleStepText": "On this screen, you can manage the calendars of remote teams connected with the UDS service",
"adminCalendarsTitle": "Manage Calendars",
"addButtonStepText": "Click here to add a new calendar.",
"addCalendar": "Add Calendar",
"searchStepText": "Use this search bar to filter existing calendars.",
"searchCalendarLabel": "Search Calendar Name",
"tableStepText": "Here are the existing calendars with their characteristics and settings.",
"actionsStepText": "Access the available actions for each calendar here."
}

View File

@ -0,0 +1,450 @@
{
"loginlabelUsername": "Introduce tu usuario",
"loginlabelPassword": "Introduce tu contraseña",
"buttonLogin": "Login",
"welcomeMessage": "Bienvenido {{username}}",
"loginError": "Login error: {{error}}",
"labelUsers": "Usuarios",
"labelRoles": "Roles",
"adminImagesTitle": "Administrar usuarios",
"addUser": "Añadir usuarios",
"searchLabel": "Buscar nombre de usuario",
"searchPlaceholder": "Búsqueda",
"searchHint": "Pulsar 'enter' para buscar",
"columnActions": "Acciones",
"dialogTitleAddUser": "Añadir Usuario",
"addUserlabelUsername": "Nombre de usuario",
"addUserlabelPassword": "Contraseña",
"labelRole": "Rol",
"labelOrganizationalUnit": "Unidad organizativa",
"buttonCancel": "Cancelar",
"buttonAdd": "Añadir",
"dialogTitleEditUser": "Editar Usuario",
"labelCurrentPassword": "Contraseña actual",
"labelNewPassword": "Nueva contraseña",
"labelRepeatPassword": "Repite la contraseña",
"errorPasswordMismatch": "Las contraseñas no coinciden",
"buttonEdit": "Editar",
"adminRolesTitle": "Administrar Roles",
"addRole": "Añadir rol",
"searchRoleLabel": "Buscar nombre de rol",
"dialogTitleAddRole": "Añadir Rol",
"labelRoleName": "Nombre",
"sectionTitlePermissions": "Permisos:",
"checkboxSuperAdmin": "Super Admin",
"checkboxOrgAdmin": "Admin de Unidad Organizativa",
"checkboxOrgOperator": "Operador de Unidad Organizativa",
"checkboxOrgMinimal": "Unidad Organizativa Mínima",
"checkboxUserRole": "Usuario",
"titleStepText": "En esta pantalla, puedes gestionar los calendarios de los equipos remotos conectados con el servicio UDS",
"adminCalendarsTitle": "Administrar calendarios",
"addButtonStepText": "Haz clic aquí para añadir un nuevo calendario.",
"addCalendar": "Añadir calendario",
"searchStepText": "Utiliza esta barra de búsqueda para filtrar los calendarios existentes.",
"searchCalendarLabel": "Buscar nombre de calendario",
"tableStepText": "Aquí se muestran los calendarios existentes con sus características y configuraciones.",
"actionsStepText": "Accede a las acciones disponibles para cada calendario aquí.",
"editCalendar": "Editar calendario",
"remoteAvailability": "¿Disponibilidad remota?",
"selectWeekDays": "Selecciona los días de la semana",
"startTime": "Hora de inicio",
"startTimePlaceholder": "Selecciona la hora de inicio",
"endTime": "Hora de fin",
"endTimePlaceholder": "Selecciona la hora de fin",
"reasonLabel": "Razón",
"reasonPlaceholder": "Razón para la excepción",
"startDate": "Fecha de inicio",
"endDate": "Fecha de fin",
"buttonSave": "Guardar",
"adminCommandGroupsTitle": "Administrar Grupos de Comandos",
"addCommandGroupStepText": "Haz clic para añadir un nuevo grupo de comandos.",
"addCommandGroup": "Añadir Grupo de Comandos",
"searchGroupNameLabel": "Buscar nombre de grupo",
"loadingStepText": "Espera mientras se cargan los grupos de comandos.",
"viewCommands": "Ver comandos",
"paginationStepText": "Navega entre las páginas de grupos de comandos usando el paginador.",
"commandGroupDetailsTitle": "Detalles del Grupo de Comandos",
"createdBy": "Creado por",
"groupId": "ID del Grupo",
"creationDate": "Fecha de Creación",
"includedCommands": "Comandos Incluidos",
"nameColumn": "Nombre",
"selectClients": "Selecciona los clientes:",
"clientsLabel": "Clientes",
"selectAtLeastOneClient": "Debes seleccionar al menos un cliente.",
"execute": "Ejecutar",
"scheduleExecution": "Programar Ejecución",
"editCommandGroup": "Editar grupo de comando",
"createCommandGroup": "Crear grupo de comando",
"groupNameLabel": "Nombre del Grupo",
"enabledToggle": "Habilitado",
"availableCommandsTitle": "Comandos Disponibles",
"selectedCommandsTitle": "Comandos Seleccionados",
"manageTasksTitle": "Administrar Tareas",
"addTaskStepText": "Haz clic para añadir una nueva tarea.",
"addTask": "Añadir Tarea",
"searchTaskLabel": "Buscar tarea",
"idColumn": "Id",
"infoColumn": "Info",
"createdByColumn": "Creado por",
"executionDateColumn": "Fecha de Ejecución",
"statusColumn": "Estado",
"enabled": "Habilitado",
"disabled": "Deshabilitado",
"adminCommandsTitle": "Trazas de comandos y procedimientos",
"resetFiltersStepText": "Haz clic para reiniciar los filtros aplicados y ver todas las trazas.",
"resetFilters": "Reiniciar filtros",
"clientSelectStepText": "Selecciona un cliente para ver las trazas asociadas.",
"selectClientPlaceholder": "Seleccione un cliente",
"commandSelectStepText": "Selecciona un comando para ver las trazas específicas de ese comando.",
"selectCommandPlaceholder": "Seleccione un comando",
"taskDetailsTitle": "Detalles de la Tarea",
"taskId": "ID de la Tarea",
"status": "Estado",
"notes": "Notas",
"includedCommandGroups": "Grupos de Comandos Incluidos",
"commandGroupColumn": "Grupo de Comandos",
"commandsToExecute": "Comandos a ejecutar",
"group": "Grupo",
"commandColumn": "Comando",
"editTask": "Editar Tarea",
"createTask": "Crear Tarea",
"informationSectionTitle": "Información",
"informationLabel": "Información",
"notesPlaceholder": "Ingresa tus notas aquí",
"commandSelectionSectionTitle": "Selección de comandos",
"selectCommandsLabel": "Selecciona Comandos",
"requiredFieldError": "Este campo es obligatorio",
"executionDateTimeSectionTitle": "Fecha y hora de ejecución",
"executionDateLabel": "Fecha de Ejecución",
"selectDatePlaceholder": "Selecciona una fecha",
"executionTimeLabel": "Hora de Ejecución",
"selectTimePlaceholder": "Selecciona una hora",
"destinationSelectionSectionTitle": "Selecciona destino",
"selectOrganizationalUnitLabel": "Selecciona Unidad Organizacional",
"selectClassroomLabel": "Selecciona Aula",
"selectAllClients": "Seleccionar todos",
"addCommand": "Añadir Comando",
"searchCommandLabel": "Buscar nombre de comando",
"executeCommandTitle": "Ejecutar Comando",
"subOrganizationalUnitLabel": "Subunidad Organizativa",
"noClientsAvailable": "No hay clientes disponibles",
"buttonExecute": "Ejecutar",
"commandDetailsTitle": "Detalles del Comando",
"nameLabel": "Nombre",
"commentsLabel": "Comentarios",
"createdByLabel": "Creado por",
"creationDateLabel": "Fecha de Creación",
"scriptLabel": "Script",
"selectClientsTitle": "Selecciona los clientes:",
"selectAtLeastOneClientError": "Debes seleccionar al menos un cliente.",
"editCommandTitle": "Editar Comando",
"createCommandTitle": "Crear Comando",
"commandNamePlaceholder": "Nombre del comando",
"commandScriptPlaceholder": "Script del comando",
"readOnlyLabel": "Solo lectura",
"enabledLabel": "Habilitado",
"generalTabLabel": "General",
"tabsStepText": "Utiliza las pestañás para acceder a las diferentes opciones de visualización y busqueda de unidades organizativas y clientes.",
"adminGroupsTitle": "Administrar grupos",
"newOrganizationalUnitTooltip": "Abrir modal para crear unidades organizativas de cualquier tipo (Centro, Aula, Grupo de aulas o Grupo de clientes)",
"newOrganizationalUnitButton": "Nueva Unidad Organizativa",
"newClientButton": "Nuevo Cliente",
"keyStepText": "La leyenda te mostrará los tipos de unidades organizativas y sus iconos correspondientes",
"legendButton": "Leyenda",
"unitStepText": "Esta es la sección donde se mostrarán las unidades organizativas de tipo 'Centro'",
"organizationalUnitTitle": "Centros",
"elementsStepText": "Esta es la sección para visualizar unidades internas del centro seleccionado y navegar por ellas.",
"internalElementsTitle": "Elementos internos",
"noInternalElementsMessage": "No hay elementos internos",
"viewTreeTooltip": "Visualizar unidad en forma de árbol",
"viewTreeMenu": "Ver organigrama",
"editUnitTooltip": "Editar esta unidad organizativa",
"viewUnitTooltip": "Ver detalles de la unidad organizativa",
"viewUnitMenu": "Ver datos",
"addInternalUnitTooltip": "Crear una nueva unidad organizativa interna",
"addClientTooltip": "Registrar un cliente en esta unidad organizativa",
"deleteElementTooltip": "Eliminar este elemento",
"deleteElementMenu": "Eliminar elemento",
"executeCommandTooltip": "Ejecutar comando en este elemento",
"advancedSearchTabLabel": "Búsqueda avanzada",
"clientsTabLabel": "Clientes",
"organizationalUnitsTabLabel": "Unidades organizativas",
"viewTreeTitle": "Visualizar árbol unidad Organizativa",
"toggleNodeAriaLabel": "Alternar nodo",
"closeButton": "Cerrar",
"orgUnitPropertiesTitle": "Propiedades unidad organizativa",
"generalDataTab": "Datos generales",
"propertyHeader": "Propiedad",
"valueHeader": "Valor",
"classroomNetworkPropertiesTab": "Propiedades aula y de red",
"editOrgUnitTitle": "Editar Unidad Organizativa",
"generalStepLabel": "General",
"typeLabel": "Tipo",
"editOrgUnitParentLabel": "Padre",
"descriptionLabel": "Descripción",
"nextButton": "Siguiente",
"classroomInfoStepLabel": "Información del Aula",
"locationLabel": "Ubicación",
"projectorToggle": "Proyector",
"boardToggle": "Pizarra",
"capacityLabel": "Aforo",
"associatedCalendarLabel": "Calendario Asociado",
"backButton": "Atrás",
"additionalInfoStepLabel": "Información Adicional",
"networkSettingsStepLabel": "Configuración de Red",
"proxyUrlLabel": "Url servidor Proxy",
"dnsIpLabel": "IP servidor DNS",
"netmaskLabel": "Máscara de Red",
"routerLabel": "Router",
"ntpIpLabel": "IP servidor NTP",
"p2pModeLabel": "Modo P2P",
"p2pTimeLabel": "Tiempo P2P",
"mcastIpLabel": "IP Multicast",
"mcastSpeedLabel": "Velocidad Multicast",
"mcastPortLabel": "Puerto Multicast",
"mcastModeLabel": "Modo Multicast",
"menuUrlLabel": "Menú URL",
"hardwareProfileLabel": "Perfil de Hardware",
"urlFormatError": "Formato de URL inválido.",
"validationToggle": "Validación",
"submitButton": "Añadir",
"addOrgUnitTitle": "Añadir Unidad Organizativa",
"createOrgUnitparentLabel": "Unidad organizativa padre",
"noParentOption": "--",
"nextServerLabel": "NextServer",
"bootFileNameLabel": "bootFileName",
"orgUnitTitle": "Unidad organizativa",
"classroomGroupsTitle": "Grupos de aula",
"classroomTitle": "Aula",
"clientGroupsTitle": "Grupos de clientes",
"clientTitle": "Cliente",
"executeCommandOrGroupTitle": "Ejecutar Comando o Grupo de Comandos",
"selectCommandLabel": "Seleccione Comando",
"selectCommandGroupLabel": "Seleccione Grupo de Comandos",
"noClientsMessage": "No hay clientes disponibles",
"editClientDialogTitle": "Editar Cliente",
"organizationalUnitLabel": "Padre",
"ogLiveLabel": "OgLive",
"serialNumberLabel": "Número de Serie",
"netifaceLabel": "Interfaz de red",
"netDriverLabel": "Controlador de red",
"macLabel": "MAC",
"macError": "Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55",
"ipLabel": "Dirección IP",
"ipError": "Formato de dirección IP inválido. Ejemplo válido: 127.0.0.1",
"templateLabel": "Plantilla PXE",
"digitalBoard": "Pizarra digital",
"projectorAlt": "Proyector",
"clientAlt": "Cliente",
"saveDispositionButton": "Guardar disposición",
"actionsModalTitle": "Acciones",
"adminOuTitle": "Administrar unidades organizativas",
"resetFiltersButton": "Reiniciar filtros",
"addOUButton": "Añadir OU",
"searchLabelOu": "Buscar nombre de OU",
"typeLabel": "Tipo",
"allOption": "Todos",
"centerOption": "Centro",
"classroomsGroupOption": "Grupos de aulas",
"classroomOption": "Aula",
"clientsGroupOption": "Grupos de PCs",
"columnActions": "Acciones",
"roomMapOption": "Plano de aula",
"viewTreeMenu": "Ver organigrama",
"adminImagesTitle": "Administrar clientes",
"resetFiltersButton": "Reiniciar filtros",
"addClientButton": "Añadir cliente",
"searchClientNameLabel": "Buscar nombre de cliente",
"searchIPLabel": "Buscar IP",
"searchMACLabel": "Buscar MAC",
"organizationalUnitLabel": "U. Organizativa",
"searchPlaceholder": "Búsqueda",
"searchHint": "Pulsar 'enter' para buscar",
"columnActions": "Acciones",
"clientDetailsTitle": "Datos de cliente",
"commandsButton": "Comandos",
"generalDataTab": "Datos generales",
"networkPropertiesTab": "Propiedades de red",
"disksPartitionsTitle": "Discos/Particiones",
"diskTitle": "Disco",
"diskUsedLabel": "Usado",
"diskTotalLabel": "Total",
"diskImageAssistantTitle": "Asistente de imágenes en disco",
"diskLabel": "Disco",
"partitionColumn": "Partición",
"isoImageColumn": "Imagen ISO",
"ogliveColumn": "OgLive",
"selectImageOption": "Seleccionar imagen",
"selectOgLiveOption": "Seleccionar OgLive",
"saveAssociationsButton": "Guardar Asociaciones",
"partitionAssistantTitle": "Asistente de particionado",
"saveButton": "Guardar",
"diskLabel": "Disco",
"diskSizeLabel": "Tamaño",
"partitionColumn": "Partición",
"partitionTypeColumn": "Tipo partición",
"partitionSizeColumn": "Tamaño (MB)",
"usageColumn": "Uso (%)",
"formatColumn": "Formatear",
"deleteColumn": "Eliminar",
"ntfsOption": "NTFS",
"linuxOption": "LINUX",
"cacheOption": "CACHE",
"deleteButton": "Eliminar",
"searchTitle": "Búsqueda avanzada",
"selectFilterLabel": "Seleccione filtro",
"gridViewButton": "Cuadrícula",
"listViewButton": "Lista",
"selectOptionLabel": "Selecciona una opción",
"organizationalUnitsOption": "Unidades organizativas",
"clientsOption": "Clientes",
"nameLabel": "Nombre",
"namePlaceholder": "Unidad organizativa",
"selectAllButton": "Seleccionar/Deseleccionar Todos",
"saveFiltersButton": "Guardar Filtros",
"sendFiltersButton": "Enviar Acción",
"addPxeButton": "Añadir fichero PXE",
"internalUnits": "Unidades internas",
"clients": "Clientes",
"noResultsMessage": "No hay resultados para mostrar.",
"imagesTitle": "Administrar imágenes",
"addImageButton": "Añadir imagen",
"searchLabel": "Buscar nombre de imagen",
"searchPlaceholder": "Búsqueda",
"searchHint": "Pulsar 'enter' para buscar",
"columnActions": "Acciones",
"editButtonIcon": "edit",
"deleteButtonIcon": "delete",
"addImageTitle": "Añadir nueva imagen",
"imageNameLabel": "Nombre de la imagen",
"repositoryLabel": "Repositorio",
"descriptionLabel": "Descripción",
"commentsLabel": "Comentarios",
"softwareProfileLabel": "Perfil de software",
"remotePcLabel": "Remote Pc",
"cancelButton": "Cancelar",
"saveButton": "Guardar",
"ogBootServerStatus": "OgBoot Server Status",
"diskUsageDescription": "Visualize the server's disk usage.",
"diskUsageTitle": "Disk Usage",
"totalLabel": "Total",
"usedLabel": "Used",
"availableLabel": "Available",
"freeLabel": "Free",
"servicesStatusDescription": "View the status of critical server services.",
"servicesTitle": "Services",
"oglivesDescription": "Check the details of installed OgLives on the server.",
"installedOglivesTitle": "Installed OgLives",
"idLabel": "ID",
"kernelLabel": "Kernel",
"architectureLabel": "Architecture",
"revisionLabel": "Revision",
"serverInfoDescription": "Accede a información y opciones de sincronización en el servidor OgBoot.",
"serverInfoTitle": "Información en servidor ogBoot",
"syncDatabaseButton": "Sincronizar base de datos",
"viewInfoButton": "Ver Información",
"adminPxeDescription": "Desde aquí puedes gestionar las plantillas PXE configuradas en el servidor OgBoot.",
"adminPxeTitle": "Administrar plantillas PXE",
"addTemplateButtonDescription": "Haz clic para añadir una nueva plantilla PXE.",
"addTemplateButton": "Añadir plantilla PXE",
"searchNameDescription": "Busca plantillas PXE por nombre para localizar rápidamente una plantilla específica.",
"searchLabel": "Buscar nombre de plantilla",
"searchPlaceholder": "Búsqueda",
"searchHint": "Pulsar 'enter' para buscar",
"searchSyncDescription": "Filtra para ver solo las plantillas creadas en el servidor OgBoot.",
"createdInOgbootLabel": "Creada en ogBoot",
"selectOptionPlaceholder": "Seleccionar opción",
"allOption": "Todos",
"yesOption": "Sí",
"noOption": "No",
"tableDescription": "Aquí se muestra la lista de plantillas PXE disponibles para administrar.",
"actionsColumn": "Acciones",
"createServerButton": "Crear en servidor OgBoot",
"addClientButton": "Añadir cliente",
"deleteButton": "Eliminar",
"paginationDescription": "Navega entre las páginas de plantillas PXE usando el paginador.",
"detailsTitle": "Detalles de {{ name }}",
"editTemplateTitle": "Editar plantilla",
"addTemplateTitle": "Añadir plantilla",
"templateNameLabel": "Nombre de la Plantilla",
"templateNamePlaceholder": "Introduce el nombre de la plantilla",
"templateNameError": "El nombre de la plantilla es requerido.",
"templateContentLabel": "Contenido de la Plantilla",
"templateContentPlaceholder": "Introduce el contenido de la plantilla",
"templateContentError": "El contenido de la plantilla es requerido.",
"loadTemplateModelButton": "Cargar plantilla modelo",
"ogLiveModel": "ogLive",
"diskModel": "Arranque por disco",
"cancelButton": "Cancelar",
"updateButton": "Actualizar",
"createButton": "Crear",
"manageClientsTitle": "Gestionar clientes",
"viewIcon": "visibility",
"syncIcon": "sync",
"deleteIcon": "delete",
"addClientsTitle": "Añade clientes a {{ subnetName }}",
"selectClientPlaceholder": "Seleccione un cliente",
"selectedClientsTitle": "Clientes seleccionados:",
"deleteIcon": "delete",
"cancelButton": "Cancelar",
"addButton": "Añadir",
"editClientTitle": "Editar Cliente",
"addClientTitle": "Añadir Cliente",
"selectPxeTemplateLabel": "Seleccione una plantilla PXE",
"cancelButton": "Cancelar",
"saveButton": "Guardar",
"addButton": "Añadir",
"advancedNetbootTitle": "Netboot avanzado",
"advancedNetbootDescription": "Esta sección permite la asignación masiva de plantillas de arranque a clientes.",
"selectUnitLabel": "Selecciona Unidad Organizacional",
"selectUnitDescription": "Selecciona la Unidad Organizacional para listar las aulas disponibles.",
"loadingUnitsOption": "Cargando unidades...",
"requiredFieldError": "Este campo es obligatorio",
"selectClassLabel": "Selecciona aula",
"selectClassDescription": "Selecciona el aula para configurar las plantillas en sus dispositivos.",
"noClassesOption": "No hay aulas disponibles",
"applyToAllLabel": "Seleccione plantilla para aplicar a todos los clientes",
"applyToAllDescription": "Selecciona una plantilla para aplicarla a todos los clientes de esta aula.",
"saveButtonLabel": "Guardar",
"saveButtonDescription": "Haz clic para guardar la configuración actual de plantillas.",
"tableDescription": "Administra las plantillas de Netboot para cada cliente en esta tabla.",
"idColumnHeader": "Id",
"nameColumnHeader": "Nombre",
"templateColumnHeader": "Plantilla",
"selectTemplateLabel": "Seleccione una plantilla",
"selectTemplateDescription": "Selecciona una plantilla específica para cada cliente.",
"noTemplateOption": "Ninguna",
"pxeImageTitle": "Información en servidor ogBoot",
"serverInfoDescription": "Accede a información y opciones de sincronización en el servidor OgBoot.",
"serverInfoTitle": "Información en servidor OgBoot",
"syncDatabaseButton": "Sincronizar base de datos",
"viewInfoButton": "Ver Información",
"adminImagesDescription": "Desde aquí puedes gestionar las imágenes configuradas en el servidor OgBoot.",
"adminImagesTitle": "Administrar imágenes",
"addImageButtonDescription": "Haz clic para añadir una nueva imagen.",
"addImageButton": "Añadir imagen",
"searchNameDescription": "Busca imágenes por nombre para encontrar rápidamente una imagen específica.",
"searchLabel": "Buscar nombre de imagen",
"searchPlaceholder": "Búsqueda",
"searchHint": "Pulsar 'enter' para buscar",
"searchDefaultDescription": "Filtra las imágenes para mostrar solo las imágenes por defecto o no por defecto.",
"searchDefaultLabel": "Imagen por defecto",
"selectOptionPlaceholder": "Seleccionar opción",
"allOption": "Todos",
"yesOption": "Sí",
"noOption": "No",
"searchInstalledDescription": "Filtra las imágenes para mostrar solo las instaladas en el servidor OgBoot.",
"searchInstalledLabel": "Instalado servidor OgBoot",
"tableDescription": "Aquí se muestra la lista de imágenes disponibles para administrar.",
"actionsColumnHeader": "Acciones",
"actionsDescription": "Administra cada imagen con opciones para ver, editar, eliminar y más.",
"viewIcon": "visibility",
"editIcon": "edit",
"deleteIcon": "delete",
"installOption": "Instalar",
"uninstallOption": "Desinstalar",
"setDefaultOption": "Cambiar a imagen por defecto",
"paginationDescription": "Navega entre las páginas de imágenes usando el paginador."
}

View File

@ -1,221 +0,0 @@
{
"locale": "en",
"translations": {
"actions-modal-title": "Actions",
"power-on-button": "Power On",
"power-off-button": "Power Off",
"reset-button": "Reset",
"other-actions-1": "Other Actions 1",
"other-actions-2": "Other Actions 2",
"other-actions-3": "Other Actions 3",
"digital-board": "Digital Board",
"projector-alt": "Projector",
"client-image-alt": "Client",
"save-disposition-button": "Save Disposition",
"client-properties-title": "Client Properties",
"property-header": "Property",
"value-header": "Value",
"close-button": "Close",
"add-client-dialog-title": "Add Client",
"organizational-unit-label": "Parent",
"name-label": "Name",
"serial-number-label": "Serial Number",
"netiface-label": "Network Interface",
"net-driver-label": "Network Driver",
"mac-label": "MAC",
"mac-hint": "Example: 00:11:22:33:44:55",
"mac-error": "Invalid MAC format. Valid example: 00:11:22:33:44:55",
"ip-label": "IP Address",
"ip-hint": "Example: 127.0.0.1",
"ip-error": "Invalid IP address format. Valid example: 127.0.0.1",
"menu-url-label": "Menu URL",
"menu-url-error": "Invalid URL format.",
"hardware-profile-label": "Hardware Profile",
"hardware-profile-error": "Invalid URL format.",
"cancel-button": "Cancel",
"add-button": "Add",
"edit-client-dialog-title": "Edit Client",
"delete-dialog-title": "Delete",
"delete-dialog-content": "Do you want to delete the clients located in {$INTERPOLATION} or do you want to relocate them to the higher level?",
"delete-all-clients-button": "Delete all clients",
"reposition-clients-button": "Relocate",
"deleteDialogTitle": "Delete",
"deleteConfirmationMessage": "Are you sure you want to delete {$INTERPOLATION}?",
"cancelButton": "Cancel",
"confirmButton": "Delete",
"adminGroupsTitle": "Manage Groups",
"newOrganizationalUnitButton": "New Organizational Unit",
"newClientButton": "New Client",
"legendButton": "Legend",
"classroomMapButton": "Classroom Map",
"searchLabel": "Search",
"searchPlaceholder": "Search",
"searchHint": "Press 'enter' to search among organizational units",
"organizationalUnitTitle": "Organizational Unit",
"viewTreeTooltip": "account_tree ",
"viewTreeMenu": "View Organizational Chart",
"editUnitTooltip": "edit ",
"editUnitMenu": "Edit",
"viewUnitTool": "visibility ",
"viewUnitMenu": "View Data",
"addInternalUnitTool": "add_home_work ",
"addInternalUnitMenu": "Add Organizational Unit",
"addClientDevice": "devices ",
"addClientMenu": "Create Client",
"internalElementsTitle": "Internal Elements",
"noInternalElementsMessage": "No internal elements",
"editElementTooltip": "edit",
"editElementMenu": "Edit",
"viewUnitTooltip": "visibility",
"addInternalUnitTooltip": "add_home_work",
"addClientTooltip": "devices",
"deleteElementTooltip": "delete",
"deleteElementMenu": "Delete Element",
"7122753603772512402": "Advanced Search",
"searchTitle": "Search",
"selectFilterLabel": "Select Filter",
"selectOptionLabel": "Select an Option",
"organizationalUnitsOption": "Organizational Units",
"clientsOption": "Clients",
"nameLabel": "Name",
"namePlaceholder": "Organizational Unit",
"unitTypeLabel": "Unit Type",
"organizationalUnitOption": "Organizational Unit",
"classroomsGroupOption": "Classroom Groups",
"classroomOption": "Classrooms",
"clientGroupOption": "Client Groups",
"floorLabel": "Floor",
"noneOption": "None",
"option1": "Floor 1",
"option2": "Floor 2",
"option3": "Floor 3",
"selectAnotherOptionLabel": "Operating System",
"selectStateLabel": "State",
"offOption": "off",
"initializingOption": "initializing",
"ogliveOption": "oglive",
"busyOption": "busy",
"linuxOption": "linux",
"linuxSessionOption": "linux_session",
"macosOption": "macos",
"windowsOption": "windows",
"windowsSessionOption": "windows_session",
"saveFiltersButton": "Save Filters",
"sendFiltersButton": "Send Action",
"internalUnits": "Internal units: {$INTERPOLATION}",
"clients": "Clients: {$INTERPOLATION}",
"noResultsMessage": "No results to display.",
"orgUnitTitle": "Organizational Unit",
"classroomGroupsTitle": "Classroom Groups",
"classroomTitle": "Classroom",
"clientGroupsTitle": "Client Groups",
"clientTitle": "Client",
"addOrgUnitTitle": "Add Organizational Unit",
"generalStepLabel": "General",
"typeLabel": "Type",
"createOrgUnitparentLabel": "Parent Organizational Unit",
"noParentOption": "--",
"descriptionLabel": "Description",
"nextButton": "Next",
"classroomInfoStepLabel": "Classroom Information",
"locationLabel": "Location",
"projectorToggle": "Projector",
"boardToggle": "Board",
"capacityLabel": "Capacity",
"backButton": "Back",
"additionalInfoStepLabel": "Additional Information",
"commentsLabel": "Comments",
"networkSettingsStepLabel": "Network Settings",
"proxyUrlLabel": "Proxy Server URL",
"dnsIpLabel": "DNS Server IP",
"netmaskLabel": "Netmask",
"routerLabel": "Router",
"ntpIpLabel": "NTP Server IP",
"p2pModeLabel": "P2P Mode",
"p2pTimeLabel": "P2P Time",
"mcastIpLabel": "Multicast IP",
"mcastSpeedLabel": "Multicast Speed",
"mcastPortLabel": "Multicast Port",
"mcastModeLabel": "Multicast Mode",
"menuUrlLabel": "Menu URL",
"hardwareProfileLabel": "Hardware Profile",
"urlFormatError": "Invalid URL format.",
"submitButton": "Add",
"editOrgUnitTitle": "Edit Organizational Unit",
"editOrgUnitParentLabel": "Parent",
"validationToggle": "Validation",
"orgUnitPropertiesTitle": "Organizational Unit Properties",
"generalDataTab": "General Data",
"classroomNetworkPropertiesTab": "Classroom and Network Properties",
"actionsTab": "Actions",
"2366056895545879062": "Power On",
"7368908909686115507": "Power Off",
"7760171369336053154": "Reset",
"6799187990933478083": "Other Actions 1",
"8971534271481971645": "Other Actions 2",
"3300614831699539964": "Other Actions 3",
"viewTreeTitle": "View Organizational Unit Tree",
"closeButton": "Close",
"webConsoleTitle": "Opengnsys Webconsole",
"admin": "Administration",
"editUser": "Edit User",
"usersMenuItem": "Users",
"rolesMenuItem": "Roles",
"logout": "Logout",
"welcomeUser": "Welcome {$INTERPOLATION}",
"groups": "Groups",
"actions": "Actions",
"images": "Images",
"components": "Components",
"repositories": "Repositories",
"menus": "Menus",
"search": "Search",
"calendars": "Calendars",
"headerOpengnsys": "Opengnsys",
"loginlabelUsername": "Enter your username",
"loginlabelPassword": "Enter your password",
"buttonLogin": "Login",
"labelUsers": "Users",
"labelRoles": "Roles",
"dialogTitleAddRole": "Add Role (TBD)",
"labelRoleName": "Name",
"sectionTitlePermissions": "Permissions:",
"checkboxManageUsers": "Manage Users",
"checkboxPXEConfig": "PXE Configuration",
"checkboxConsoleImages": "Web Console Images",
"checkboxManageComponents": "Manage Different Components",
"checkboxCreateImages": "Create Images",
"checkboxServerConfigScript": "Server Configuration Script",
"checkboxOther": "...",
"buttonCancel": "Cancel",
"buttonAdd": "Add",
"dialogTitleDeleteRole": "Delete Role",
"dialogContentDeleteRole": "Are you sure you want to delete the role {$INTERPOLATION}?",
"buttonDelete": "Delete",
"headerRoleManagement": "Role Management",
"buttonAddRole": "+ Add",
"headerActions": "Actions",
"dialogTitleAddUser": "Add User",
"addUserlabelUsername": "Username",
"addUserlabelPassword": "Password",
"labelRole": "Role",
"labelOrganizationalUnit": "Organizational Unit",
"dialogTitleEditUser": "Edit User",
"labelCurrentPassword": "Current Password",
"labelNewPassword": "New Password",
"labelRepeatPassword": "Repeat Password",
"errorPasswordMismatch": " Passwords do not match ",
"errorUpdate": " {$INTERPOLATION} ",
"buttonEdit": "Edit",
"dialogTitleDeleteUser": "Delete User",
"dialogContentDeleteUser": "Are you sure you want to delete {$INTERPOLATION}?",
"editUserlabelUsername": "Username",
"editUserlabelPassword": "Password",
"labelOrgUnit": "Organizational Unit",
"headerUserManagement": "User Management",
"buttonAddUser": "+ Add",
"columnActions": "Actions",
"buttonEditUser": "Edit",
"buttonDeleteUser": "Delete"
}
}

View File

@ -1,221 +0,0 @@
{
"locale": "es",
"translations": {
"actions-modal-title": "Acciones",
"power-on-button": "Encender",
"power-off-button": "Apagar",
"reset-button": "Resetear",
"other-actions-1": "Otras acciones 1",
"other-actions-2": "Otras acciones 2",
"other-actions-3": "Otras acciones 3",
"digital-board": "Pizarra digital",
"projector-alt": "Proyector",
"client-image-alt": "Client",
"save-disposition-button": "Guardar disposición",
"client-properties-title": "Propiedades cliente",
"property-header": "Propiedad",
"value-header": "Valor",
"close-button": "Cerrar",
"add-client-dialog-title": "Añadir Cliente",
"organizational-unit-label": "Padre",
"name-label": "Nombre",
"serial-number-label": "Número de Serie",
"netiface-label": "Interfaz de red",
"net-driver-label": "Controlador de red",
"mac-label": "MAC",
"mac-hint": "Ejemplo: 00:11:22:33:44:55",
"mac-error": "Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55",
"ip-label": "Dirección IP",
"ip-hint": "Ejemplo: 127.0.0.1",
"ip-error": "Formato de dirección IP inválido. Ejemplo válido: 127.0.0.1",
"menu-url-label": "Menú URL",
"menu-url-error": "Formato de URL inválido.",
"hardware-profile-label": "Perfil de Hardware",
"hardware-profile-error": "Formato de URL inválido.",
"cancel-button": "Cancelar",
"add-button": "Añadir",
"edit-client-dialog-title": "Editar Cliente",
"delete-dialog-title": "Eliminar",
"delete-dialog-content": "¿Quiere borrar los clientes situados en {$INTERPOLATION} o quiere resituarlos en el nivel superior?",
"delete-all-clients-button": "Borrar todos los clientes",
"reposition-clients-button": "Resituar",
"deleteDialogTitle": "Eliminar",
"deleteConfirmationMessage": "¿Estás seguro que deseas eliminar {$INTERPOLATION}?",
"cancelButton": "Cancelar",
"confirmButton": "Eliminar",
"adminGroupsTitle": "Administrar grupos",
"newOrganizationalUnitButton": "Nueva Unidad Organizativa",
"newClientButton": "Nuevo Cliente",
"legendButton": "Leyenda",
"classroomMapButton": "Plano de aula",
"searchLabel": "Búsqueda",
"searchPlaceholder": "Búsqueda",
"searchHint": "Pulsar 'enter' para buscar entre las unidades organizativas",
"organizationalUnitTitle": "Unidad organizativa",
"viewTreeTooltip": "account_tree ",
"viewTreeMenu": "Ver organigrama",
"editUnitTooltip": "edit ",
"editUnitMenu": "Editar",
"viewUnitTool": "visibility ",
"viewUnitMenu": "Visualizar datos",
"addInternalUnitTool": "add_home_work ",
"addInternalUnitMenu": "Añadir unidad organizativa",
"addClientDevice": "devices ",
"addClientMenu": "Crear cliente",
"internalElementsTitle": "Elementos internos",
"noInternalElementsMessage": "No hay elementos internos",
"editElementTooltip": "edit",
"editElementMenu": "Editar",
"viewUnitTooltip": "visibility",
"addInternalUnitTooltip": "add_home_work",
"addClientTooltip": "devices",
"deleteElementTooltip": "delete",
"deleteElementMenu": "Borrar elemento",
"7122753603772512402": "Búsqueda avanzada",
"searchTitle": "Búsqueda",
"selectFilterLabel": "Seleccione filtro",
"selectOptionLabel": "Selecciona una opción",
"organizationalUnitsOption": "Unidades organizativas",
"clientsOption": "Clientes",
"nameLabel": "Nombre",
"namePlaceholder": "Unidad organizativa",
"unitTypeLabel": "Tipo de unidad",
"organizationalUnitOption": "Unidad organizativa",
"classroomsGroupOption": "Grupos de aulas",
"classroomOption": "Aulas",
"clientGroupOption": "Grupos de clientes",
"floorLabel": "Planta",
"noneOption": "Ninguno",
"option1": "Planta 1",
"option2": "Planta 2",
"option3": "Planta 3",
"selectAnotherOptionLabel": "Sistema Operativo",
"selectStateLabel": "Estado",
"offOption": "off",
"initializingOption": "initializing",
"ogliveOption": "oglive",
"busyOption": "busy",
"linuxOption": "linux",
"linuxSessionOption": "linux_session",
"macosOption": "macos",
"windowsOption": "windows",
"windowsSessionOption": "windows_session",
"saveFiltersButton": "Guardar Filtros",
"sendFiltersButton": "Enviar Acción",
"internalUnits": "Unidades internas: {$INTERPOLATION}",
"clients": "Clientes: {$INTERPOLATION}",
"noResultsMessage": "No hay resultados para mostrar.",
"orgUnitTitle": "Unidad organizativa",
"classroomGroupsTitle": "Grupos de aula",
"classroomTitle": "Aula",
"clientGroupsTitle": "Grupos de clientes",
"clientTitle": "Cliente",
"addOrgUnitTitle": "Añadir Unidad Organizativa",
"generalStepLabel": "General",
"typeLabel": "Tipo",
"createOrgUnitparentLabel": "Unidad organizativa padre",
"noParentOption": "--",
"descriptionLabel": "Descripción",
"nextButton": "Siguiente",
"classroomInfoStepLabel": "Información del Aula",
"locationLabel": "Ubicación",
"projectorToggle": "Proyector",
"boardToggle": "Pizarra",
"capacityLabel": "Aforo",
"backButton": "Atrás",
"additionalInfoStepLabel": "Información Adicional",
"commentsLabel": "Comentarios",
"networkSettingsStepLabel": "Configuración de Red",
"proxyUrlLabel": "Url servidor Proxy",
"dnsIpLabel": "IP servidor DNS",
"netmaskLabel": "Máscara de Red",
"routerLabel": "Router",
"ntpIpLabel": "IP servidor NTP",
"p2pModeLabel": "Modo P2P",
"p2pTimeLabel": "Tiempo P2P",
"mcastIpLabel": "IP Multicast",
"mcastSpeedLabel": "Velocidad Multicast",
"mcastPortLabel": "Puerto Multicast",
"mcastModeLabel": "Modo Multicast",
"menuUrlLabel": "Menú URL",
"hardwareProfileLabel": "Perfil de Hardware",
"urlFormatError": "Formato de URL inválido.",
"submitButton": "Añadir",
"editOrgUnitTitle": "Editar Unidad Organizativa",
"editOrgUnitParentLabel": "Padre",
"validationToggle": "Validación",
"orgUnitPropertiesTitle": "Propiedades unidad organizativa",
"generalDataTab": "Datos generales",
"classroomNetworkPropertiesTab": "Propiedades aula y de red",
"actionsTab": "Acciones",
"2366056895545879062": "Encender",
"7368908909686115507": "Apagar",
"7760171369336053154": "Resetear",
"6799187990933478083": "Otras acciones 1",
"8971534271481971645": "Otras acciones 2",
"3300614831699539964": "Otras acciones 3",
"viewTreeTitle": "Visualizar árbol unidad Organizativa",
"closeButton": "Cerrar",
"webConsoleTitle": "Opengnsys webconsole",
"admin": "Administración",
"editUser": "Editar usuario",
"usersMenuItem": "Usuarios",
"rolesMenuItem": "Roles",
"logout": "Salir",
"welcomeUser": "Bienvenido {$INTERPOLATION}",
"groups": "Grupos",
"actions": "Acciones",
"images": "Imágenes",
"components": "Componentes",
"repositories": "Repositorios",
"menus": "Menús",
"search": "Buscar",
"calendars": "Calendarios",
"headerOpengnsys": "Opengnsys",
"loginlabelUsername": "Introduce tu usuario",
"loginlabelPassword": "Introduce tu contraseña",
"buttonLogin": "Iniciar sesión",
"labelUsers": "Usuarios",
"labelRoles": "Roles",
"dialogTitleAddRole": "Añadir Rol (TBD)",
"labelRoleName": "Nombre",
"sectionTitlePermissions": "Permisos:",
"checkboxManageUsers": "Gestionar los usuarios",
"checkboxPXEConfig": "Configuración PXE",
"checkboxConsoleImages": "Imágenes de la consola web",
"checkboxManageComponents": "Gestionar los distintos componentes",
"checkboxCreateImages": "Crear imágenes",
"checkboxServerConfigScript": "script de configuración del servidor",
"checkboxOther": "...",
"buttonCancel": "Cancelar",
"buttonAdd": "Añadir",
"dialogTitleDeleteRole": "Eliminar Rol",
"dialogContentDeleteRole": "¿Estás seguro que deseas eliminar el rol {$INTERPOLATION}?",
"buttonDelete": "Eliminar",
"headerRoleManagement": "Gestión de roles",
"buttonAddRole": "+ Añadir",
"headerActions": "Acciones",
"dialogTitleAddUser": "Añadir Usuario",
"addUserlabelUsername": "Nombre de usuario",
"addUserlabelPassword": "Contraseña",
"labelRole": "Rol",
"labelOrganizationalUnit": "Unidad organiativa",
"dialogTitleEditUser": "Editar Usuario",
"labelCurrentPassword": "Contraseña actual",
"labelNewPassword": "Nueva contraseña",
"labelRepeatPassword": "Repite la contraseña",
"errorPasswordMismatch": " Las contraseñas no coinciden ",
"errorUpdate": " {$INTERPOLATION} ",
"buttonEdit": "Editar",
"dialogTitleDeleteUser": "Eliminar Usuario",
"dialogContentDeleteUser": "¿Estás seguro que deseas eliminar a {$INTERPOLATION}?",
"editUserlabelUsername": "Nombre de usuario",
"editUserlabelPassword": "Contraseña",
"labelOrgUnit": "Unidad organizativa",
"headerUserManagement": "Gestión de usuarios",
"buttonAddUser": "+ Añadir",
"columnActions": "Acciones",
"buttonEditUser": "Editar",
"buttonDeleteUser": "Eliminar"
}
}