summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordevega <ma.devega@globunet.com>2019-05-13 10:58:04 +0200
committerdevega <ma.devega@globunet.com>2019-05-13 10:58:04 +0200
commitd619dddd6bc80694096090337e331dc51e7c5ea4 (patch)
treebe46a3b2acce9b617f77eca5fc4c06315be8f82f
parentd624c25993a589197a09ca7998764bd7727eaf08 (diff)
parent992e7e507c33cde23b494cc3d5b3e1e24fab0480 (diff)
Merge remote-tracking branch 'origin/webconsole3' into webconsole3
-rw-r--r--admin/Sources/Clients/ogagent/oglive/Makefile21
-rw-r--r--admin/Sources/Clients/ogagent/oglive/debian/ogagent-oglive.postinst.debhelper5
-rw-r--r--admin/Sources/Clients/ogagent/oglive/debian/ogagent-oglive.postrm.debhelper12
-rw-r--r--admin/Sources/Clients/ogagent/oglive/scripts/OGAgentTool6
-rw-r--r--admin/Sources/Clients/ogagent/oglive/scripts/OGAgentTool-startup10
-rw-r--r--admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py78
-rw-r--r--admin/Sources/Clients/ogagent/src/opengnsys/oglive/operations.py8
-rw-r--r--admin/WebConsole/comandos/CrearImagen.php3
-rw-r--r--admin/WebConsole/comandos/jscripts/Configurar.js2
-rw-r--r--admin/WebConsole/comandos/jscripts/RestaurarImagenBasica.js2
-rw-r--r--admin/WebConsole/comandos/jscripts/RestaurarSoftIncremental.js2
-rw-r--r--admin/WebConsole/jscripts/consolaremota.js2
-rw-r--r--admin/WebConsole3/frontend/package.json3
-rw-r--r--admin/WebConsole3/frontend/src/app/api/command.service.ts52
-rw-r--r--admin/WebConsole3/frontend/src/app/api/software-component.service.ts40
-rw-r--r--admin/WebConsole3/frontend/src/app/api/software-profile.service.ts40
-rw-r--r--admin/WebConsole3/frontend/src/app/api/software-type.service.ts40
-rw-r--r--admin/WebConsole3/frontend/src/app/app-routing.module.ts77
-rw-r--r--admin/WebConsole3/frontend/src/app/app.component.html12
-rw-r--r--admin/WebConsole3/frontend/src/app/app.module.ts72
-rw-r--r--admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html22
-rw-r--r--admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.ts2
-rw-r--r--admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.html2
-rw-r--r--admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.ts22
-rw-r--r--admin/WebConsole3/frontend/src/app/form-type/menu.form-type.ts16
-rw-r--r--admin/WebConsole3/frontend/src/app/form-type/repository.form-type.ts20
-rw-r--r--admin/WebConsole3/frontend/src/app/model/client.ts16
-rw-r--r--admin/WebConsole3/frontend/src/app/model/command.ts22
-rw-r--r--admin/WebConsole3/frontend/src/app/model/image.ts45
-rw-r--r--admin/WebConsole3/frontend/src/app/model/menu.ts24
-rw-r--r--admin/WebConsole3/frontend/src/app/model/repository.ts42
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/client/client.component.html103
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/client/client.component.ts96
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.html139
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.scss5
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.ts223
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.html98
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.scss3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.ts188
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.html62
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.scss3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.ts120
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.html146
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.scss3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.ts137
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.html95
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.scss3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.ts142
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.html96
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.scss3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.ts150
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.html81
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.scss3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.ts80
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.html164
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.scss22
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.ts618
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/common/directive/col-resizable.directive.ts81
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/common/og-options/og-commands-options/og-commands-options.component.html14
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.html11
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.ts3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.html24
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.ts11
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/common/table-action/ng2-table-action.component.css6
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/dashboard/dashboard.component.ts4
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.html9
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.ts65
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/hardware-profiles-group.component.html (renamed from admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/profiles-group.component.html)94
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/hardware-profiles-group.component.ts (renamed from admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/profiles-group.component.ts)28
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/hardware-profiles-table.component.html (renamed from admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/profiles-table.component.html)122
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/hardware-profiles-table.component.ts (renamed from admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/profiles-table.component.ts)202
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/image/edit/image-edit.component.ts176
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/image/image.component.html6
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/image/image.component.ts292
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.html37
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.scss3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.ts78
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/menu/menu.component.html52
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/menu/menu.component.ts122
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/organizational-unit/organizational-unit.component.ts5
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.html6
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.scss11
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.ts20
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-group/ou-group.component.ts14
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/profile/profile.component.html9
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/profile/profile.component.ts1
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/repository/repository.component.html200
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.html45
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.ts10
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.html43
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.ts84
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.css0
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.html1
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.ts17
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.html47
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.ts14
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.html61
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.ts100
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.css0
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.html3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.ts19
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.css0
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.html66
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.ts26
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software.component.html66
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software.component.scss3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software.component.ts84
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/trace/trace.component.ts524
-rw-r--r--admin/WebConsole3/frontend/src/app/serializer/image.serializer.ts21
-rw-r--r--admin/WebConsole3/frontend/src/app/service/og-commands.service.ts471
-rw-r--r--admin/WebConsole3/frontend/src/app/service/og-common.service.ts28
-rw-r--r--admin/WebConsole3/frontend/src/assets/i18n/es.json2
-rw-r--r--admin/WebConsole3/frontend/src/environments/environment.ts4
-rw-r--r--admin/WebConsole3/frontend/src/styles.scss21
-rwxr-xr-xclient/boot-tools/boottoolsfunctions.lib9
-rw-r--r--client/boot-tools/includes/etc/initramfs-tools/scripts/VERSION.txt2
-rw-r--r--client/boot-tools/includes/usr/bin/boot-tools/listpackages/sw.basic3
-rwxr-xr-xclient/shared/etc/init/default.sh27
-rwxr-xr-xclient/shared/scripts/poweroff8
-rwxr-xr-xclient/shared/scripts/reboot9
-rwxr-xr-xinstaller/opengnsys_installer.sh287
-rwxr-xr-xinstaller/opengnsys_update.sh2
-rwxr-xr-xserver/bin/checkperms12
-rwxr-xr-xserver/bin/setsmbpass10
-rw-r--r--server/etc/apache-console3.conf.tmpl58
-rw-r--r--server/etc/apache.conf.tmpl52
126 files changed, 5676 insertions, 1772 deletions
diff --git a/admin/Sources/Clients/ogagent/oglive/Makefile b/admin/Sources/Clients/ogagent/oglive/Makefile
index 832e2dc7..84e06107 100644
--- a/admin/Sources/Clients/ogagent/oglive/Makefile
+++ b/admin/Sources/Clients/ogagent/oglive/Makefile
@@ -30,28 +30,13 @@ install-ogagent:
cp -r $(SOURCEDIR)/opengnsys $(LIBDIR)/opengnsys
cp -r $(SOURCEDIR)/cfg $(LIBDIR)/cfg
+ ln -fs $(LIBDIR)/cfg/ogagent.cfg $(CFGDIR)
+ ln -fs $(LIBDIR)/cfg/ogclient.cfg $(CFGDIR)
- # scripts
cp scripts/ogagent $(BINDIR)
- cp scripts/OGAgentTool-startup $(BINDIR)
- cp scripts/OGAgentTool $(BINDIR)
-
- # Fix permissions
chmod 755 $(BINDIR)/ogagent
- chmod 755 $(BINDIR)/OGAgentTool-startup
- chmod 600 $(LIBDIR)/cfg/ogagent.cfg
-
- # If for red hat based, copy init.d
-ifeq ($(DISTRO),rh)
- mkdir -p $(INITDIR)
- cp debian/ogagent.init $(INITDIR)/ogagent
- chmod +x $(INITDIR)/ogagent
- ln -fs /usr/share/OGAgent/cfg/ogagent.cfg $(CFGDIR)
- ln -fs /usr/share/OGAgent/cfg/ogclient.cfg $(CFGDIR)
-endif
- # chmod 0755 $(BINDIR)/ogagent
uninstall:
rm -rf $(LIBDIR)
- # rm -f $(BINDIR)/ogagent
+ rm -f $(BINDIR)/ogagent
rm -rf $(CFGDIR)
diff --git a/admin/Sources/Clients/ogagent/oglive/debian/ogagent-oglive.postinst.debhelper b/admin/Sources/Clients/ogagent/oglive/debian/ogagent-oglive.postinst.debhelper
deleted file mode 100644
index e75924dc..00000000
--- a/admin/Sources/Clients/ogagent/oglive/debian/ogagent-oglive.postinst.debhelper
+++ /dev/null
@@ -1,5 +0,0 @@
-# Automatically added by dh_installinit
-if [ -x "/etc/init.d/ogagent" ]; then
- update-rc.d ogagent defaults >/dev/null || exit $?
-fi
-# End automatically added section
diff --git a/admin/Sources/Clients/ogagent/oglive/debian/ogagent-oglive.postrm.debhelper b/admin/Sources/Clients/ogagent/oglive/debian/ogagent-oglive.postrm.debhelper
deleted file mode 100644
index 3167f1f8..00000000
--- a/admin/Sources/Clients/ogagent/oglive/debian/ogagent-oglive.postrm.debhelper
+++ /dev/null
@@ -1,12 +0,0 @@
-# Automatically added by dh_installinit
-if [ "$1" = "purge" ] ; then
- update-rc.d ogagent remove >/dev/null
-fi
-
-
-# In case this system is running systemd, we make systemd reload the unit files
-# to pick up changes.
-if [ -d /run/systemd/system ] ; then
- systemctl --system daemon-reload >/dev/null || true
-fi
-# End automatically added section
diff --git a/admin/Sources/Clients/ogagent/oglive/scripts/OGAgentTool b/admin/Sources/Clients/ogagent/oglive/scripts/OGAgentTool
deleted file mode 100644
index 5b300523..00000000
--- a/admin/Sources/Clients/ogagent/oglive/scripts/OGAgentTool
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/sh
-
-FOLDER=/usr/share/OGAgent
-
-cd $FOLDER
-python OGAgentUser.py $@
diff --git a/admin/Sources/Clients/ogagent/oglive/scripts/OGAgentTool-startup b/admin/Sources/Clients/ogagent/oglive/scripts/OGAgentTool-startup
deleted file mode 100644
index bb3a848e..00000000
--- a/admin/Sources/Clients/ogagent/oglive/scripts/OGAgentTool-startup
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-
-# Simple hack to wait for systray to be present
-# Exec tool if not already runned by session manager
-ps -ef | grep "$USER" | grep -v grep | grep -v OGAgentTool-startup | grep 'OGAgentTool' -q
-# If not already running
-if [ $? -eq 1 ]; then
- sleep 5
- exec /usr/bin/OGAgentTool
-fi \ No newline at end of file
diff --git a/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py b/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py
index 8aed2a8b..035ed9b4 100644
--- a/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py
+++ b/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py
@@ -123,6 +123,8 @@ class OpenGnSysWorker(ServerWorker):
# Replacing server IP if its running on ogLive client
logger.debug('Activating on ogLive client, new server is {}'.format(os.environ['oglive']))
url = parse.urlsplit(url)._replace(netloc=os.environ['oglive']).geturl()
+ if not url.endswith(os.path.sep):
+ url += os.path.sep
self.REST = REST(url)
# Get network interfaces until they are active or timeout (5 minutes)
for t in range(0, 300):
@@ -148,10 +150,10 @@ class OpenGnSysWorker(ServerWorker):
pass
# Copy file "HostsFile.FirstOctetOfIPAddress" to "HostsFile", if it exists
# (used in "exam mode" from the University of Seville)
- # hostsFile = os.path.join(operations.get_etc_path(), 'hosts')
- # newHostsFile = hostsFile + '.' + self.interface.ip.split('.')[0]
- # if os.path.isfile(newHostsFile):
- # shutil.copyfile(newHostsFile, hostsFile)
+ hosts_file = os.path.join(operations.get_etc_path(), 'hosts')
+ new_file = hosts_file + '.' + self.interface.ip.split('.')[0]
+ if os.path.isfile(new_file):
+ shutil.copy2(new_file, hosts_file)
# Generate random secret to send on activation
self.random = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(self.length))
# Compose login route
@@ -170,53 +172,51 @@ class OpenGnSysWorker(ServerWorker):
self.REST = REST(self.service.config.get('opengnsys', 'altremote'))
response = self.REST.sendMessage(login_route)
except:
- logger.error('Initialization error')
+ raise Exception('Initialization error: Cannot connect to the server')
finally:
- if response['access_token'] is not None:
- self.access_token = response['access_token']
- self.refresh_token = response['refresh_token']
- # Once authenticated with the server, change the API URL for private request
- self.REST = REST(url + '/api/private')
- # Set authorization tokens in the REST object, so in each request this token will be used
- self.REST.set_authorization_headers(self.access_token, self.refresh_token)
- # Create HTML file (TEMPORARY)
- message = """
+ if response['access_token'] is None:
+ raise Exception('Initialization error: Cannot obtain access token')
+ self.access_token = response['access_token']
+ self.refresh_token = response['refresh_token']
+ # Once authenticated with the server, change the API URL for private request
+ self.REST = REST(url + 'api/private')
+ # Set authorization tokens in the REST object, so in each request this token will be used
+ self.REST.set_authorization_headers(self.access_token, self.refresh_token)
+ # Completing ogLive initialization process
+ os_type = operations.os_type.lower()
+ if os_type == 'oglive':
+ # Create HTML file (TEMPORARY)
+ message = """
<html>
<head></head>
<body>
<h1>Initializing...</h1>
</body>
-</html>
-"""
- f = open('/tmp/init.html', 'w')
- f.write(message)
- f.close()
- # Launch browser
- subprocess.Popen(['browser', '-qws', '/tmp/init.html'])
- self.REST.sendMessage('clients/statuses', {'mac': self.interface.mac, 'ip': self.interface.ip,
- 'status': 'initializing'})
-
- def cfg():
- """
- Subprocess to send configuration and status
- """
- config = operations.get_configuration()
- self.REST.sendMessage('clients/configs', {'mac': self.interface.mac, 'ip': self.interface.ip,
- 'config': config})
- self.REST.sendMessage('clients/statuses', {'mac': self.interface.mac, 'ip': self.interface.ip,
- 'status': 'oglive'})
-
- threading.Thread(target=cfg()).start()
- else:
- logger.error("Initialization error: Can't obtain access token")
+</html>"""
+ f = open('/tmp/init.html', 'w')
+ f.write(message)
+ f.close()
+ # Launching Browser
+ pid = subprocess.Popen(['browser', '-qws', '/tmp/init.html'])
+ self.REST.sendMessage('clients/statuses', {'mac': self.interface.mac, 'ip': self.interface.ip,
+ 'status': 'initializing'})
+ # Send configuration message
+ self.REST.sendMessage('clients/configs', {'mac': self.interface.mac, 'ip': self.interface.ip,
+ 'config': operations.get_configuration()})
+ # Launching new Browser with client's menu
+ pid.kill()
+ # menu_url = self.REST.sendMessage('menus?mac' + self.interface.mac + '&ip=' + self.interface.ip)
+ menu_url = '/opt/opengnsys/log/' + self.interface.ip + '.info.html' # TEMPORARY menu
+ subprocess.Popen(['browser', '-qws', menu_url])
+ # Return status message
+ self.REST.sendMessage('clients/statuses', {'mac': self.interface.mac, 'ip': self.interface.ip,
+ 'status': os_type})
def onDeactivation(self):
"""
Sends OGAgent stopping notification to OpenGnsys server
"""
logger.debug('onDeactivation')
- # self.REST.sendMessage('ogagent/stopped', {'mac': self.interface.mac, 'ip': self.interface.ip,
- # 'ostype': operations.os_type, 'osversion': operations.os_version})
self.REST.sendMessage('clients/statuses', {'mac': self.interface.mac, 'ip': self.interface.ip,
'ostype': operations.os_type, 'osversion': operations.os_version,
'status': 'off'})
diff --git a/admin/Sources/Clients/ogagent/src/opengnsys/oglive/operations.py b/admin/Sources/Clients/ogagent/src/opengnsys/oglive/operations.py
index 342cfb06..3cdeef09 100644
--- a/admin/Sources/Clients/ogagent/src/opengnsys/oglive/operations.py
+++ b/admin/Sources/Clients/ogagent/src/opengnsys/oglive/operations.py
@@ -33,6 +33,7 @@ from __future__ import unicode_literals
import socket
import platform
+import os
import fcntl
import subprocess
import struct
@@ -174,6 +175,13 @@ def poweroff():
_exec_ogcommand('/opt/opengnsys/scripts/poweroff')
+def get_etc_path():
+ """
+ Returns etc directory path.
+ """
+ return os.sep + 'etc'
+
+
def get_configuration():
"""
Returns client's configuration
diff --git a/admin/WebConsole/comandos/CrearImagen.php b/admin/WebConsole/comandos/CrearImagen.php
index 532a589a..1944872a 100644
--- a/admin/WebConsole/comandos/CrearImagen.php
+++ b/admin/WebConsole/comandos/CrearImagen.php
@@ -122,7 +122,8 @@ function HTMLSELECT_imagenes($cmd,$idrepositorio,$idperfilsoft,$disk,$particion,
$cmd->texto="SELECT DISTINCT imagenes.idimagen,imagenes.descripcion,imagenes.nombreca,
imagenes.idperfilsoft, repositorios.nombrerepositorio, repositorios.ip
FROM imagenes INNER JOIN repositorios USING (idrepositorio)
- WHERE repositorios.idrepositorio = (SELECT idrepositorio FROM ordenadores WHERE ordenadores.ip='".$masterip."')
+ WHERE imagenes.tipo=".$IMAGENES_MONOLITICAS."
+ AND repositorios.idrepositorio IN (SELECT idrepositorio FROM ordenadores WHERE ordenadores.ip='".$masterip."')
OR repositorios.ip='".$masterip."' ORDER BY imagenes.descripcion";
$rs=new Recordset;
diff --git a/admin/WebConsole/comandos/jscripts/Configurar.js b/admin/WebConsole/comandos/jscripts/Configurar.js
index 4dfd1ce5..8e11615b 100644
--- a/admin/WebConsole/comandos/jscripts/Configurar.js
+++ b/admin/WebConsole/comandos/jscripts/Configurar.js
@@ -81,7 +81,7 @@ function addParticion(objImg,cc)
function Confirmar(cc)
{
if(comprobarDatos(cc)){
- if(document.fdatosejecucion.ambito.value!==AMBITO_ORDENADORES){
+ if(document.fdatosejecucion.ambito.value!=AMBITO_ORDENADORES){
var tbOrd= document.getElementById("tbOrd_"+cc); // Recupera tabla de ordenadores de la configuración
var idordenadores=tbOrd.getAttribute('value'); // Toma identificadores de los ordenadores
var cadenaid=document.fdatos.cadenaid.value; // Cadena de identificadores de todos los ordenadores del ámbito
diff --git a/admin/WebConsole/comandos/jscripts/RestaurarImagenBasica.js b/admin/WebConsole/comandos/jscripts/RestaurarImagenBasica.js
index c72851bb..960cd8ce 100644
--- a/admin/WebConsole/comandos/jscripts/RestaurarImagenBasica.js
+++ b/admin/WebConsole/comandos/jscripts/RestaurarImagenBasica.js
@@ -55,7 +55,7 @@
if(chrChk.checked) atributos+="cmp=1"+RC; else atributos+="cmp=0"+RC;
var cc=ochecks[i].getAttribute('idcfg'); // Toma identificador del bloque de configuración
- if(document.fdatosejecucion.ambito.value!==AMBITO_ORDENADORES){
+ if(document.fdatosejecucion.ambito.value!=AMBITO_ORDENADORES){
var tbOrd=document.getElementById("tbOrd_"+cc);
var idordenadores=tbOrd.getAttribute('value'); // Toma identificadores de los ordenadores
var cadenaid=document.fdatos.cadenaid.value; // Cadena de identificadores de todos los ordenadores del ámbito
diff --git a/admin/WebConsole/comandos/jscripts/RestaurarSoftIncremental.js b/admin/WebConsole/comandos/jscripts/RestaurarSoftIncremental.js
index f3f95219..88ecd6e1 100644
--- a/admin/WebConsole/comandos/jscripts/RestaurarSoftIncremental.js
+++ b/admin/WebConsole/comandos/jscripts/RestaurarSoftIncremental.js
@@ -58,7 +58,7 @@
if(chrChk.checked) atributos+="cmp=1"+RC; else atributos+="cmp=0"+RC;
var cc=ochecks[i].getAttribute('idcfg'); // Toma identificador del bloque de configuración
- if(document.fdatosejecucion.ambito.value!==AMBITO_ORDENADORES){
+ if(document.fdatosejecucion.ambito.value!=AMBITO_ORDENADORES){
var tbOrd=document.getElementById("tbOrd_"+cc);
var idordenadores=tbOrd.getAttribute('value'); // Toma identificadores de los ordenadores
var cadenaid=document.fdatos.cadenaid.value; // Cadena de identificadores de todos los ordenadores del ámbito
diff --git a/admin/WebConsole/jscripts/consolaremota.js b/admin/WebConsole/jscripts/consolaremota.js
index 7255e769..36473353 100644
--- a/admin/WebConsole/jscripts/consolaremota.js
+++ b/admin/WebConsole/jscripts/consolaremota.js
@@ -37,7 +37,7 @@ function enviaMsg(cmd)
}
//______________________________________________________________________________________________________
function resultadocmd(resul){
- if(resul===1){ // Si todo va bien se llama a la función que recupera elfichero de eco
+ if(resul==1){ // Si todo va bien se llama a la función que recupera elfichero de eco
//alert(TbMsg[1])
if(ambito===AMBITO_ORDENADORES){
sw=2;
diff --git a/admin/WebConsole3/frontend/package.json b/admin/WebConsole3/frontend/package.json
index fd197606..a2f353f5 100644
--- a/admin/WebConsole3/frontend/package.json
+++ b/admin/WebConsole3/frontend/package.json
@@ -34,6 +34,7 @@
"angular-loading-page": "^0.6.0",
"bootstrap-css-only": "^3.3.7",
"chart.js": "^2.7.3",
+ "chartjs-plugin-datalabels": "^0.6.0",
"core-js": "^2.5.4",
"font-awesome": "^4.7.0",
"ionicons": "^4.5.5",
@@ -58,8 +59,6 @@
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "~4.3.0",
- "globunet-angular": "git+https://gitlab.globunet.com/globunet/angular2-shared.git",
- "globunet-schematics": "git+https://gitlab.globunet.com/globunet/globunet-angular-schematics.git",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~3.0.0",
diff --git a/admin/WebConsole3/frontend/src/app/api/command.service.ts b/admin/WebConsole3/frontend/src/app/api/command.service.ts
index fe77bda3..28b18520 100644
--- a/admin/WebConsole3/frontend/src/app/api/command.service.ts
+++ b/admin/WebConsole3/frontend/src/app/api/command.service.ts
@@ -1,26 +1,26 @@
-import { Injectable } from '@angular/core';
-import { HttpClient} from '@angular/common/http';
-
-import { environment } from '../../environments/environment';
-import { Command } from '../model/command';
-import { CommandSerializer } from '../serializer/command.serializer';
-
-import {ResourceService} from 'globunet-angular/core/providers/api/resource.service';
-import {Observable} from 'rxjs';
-
-
-@Injectable({
- providedIn: 'root'
-})
-export class CommandService extends ResourceService<Command> {
-
- constructor(http: HttpClient) {
- super(http, environment.API_URL, 'commands', new CommandSerializer());
- }
-
- execute(params): Observable<any> {
- const url = this.url + 'executes.json';
- return this.httpClient.post(url, params);
- }
-
-}
+import {Injectable} from '@angular/core';
+import {HttpClient} from '@angular/common/http';
+
+import {environment} from '../../environments/environment';
+import {Command} from '../model/command';
+import {CommandSerializer} from '../serializer/command.serializer';
+
+import {ResourceService} from 'globunet-angular/core/providers/api/resource.service';
+import {Observable} from 'rxjs';
+
+
+@Injectable({
+ providedIn: 'root'
+})
+export class CommandService extends ResourceService<Command> {
+
+ constructor(http: HttpClient) {
+ super(http, environment.API_URL, 'commands', new CommandSerializer());
+ }
+
+ execute(params): Observable<any> {
+ const url = this.url + '/commands/executes.json';
+ return this.httpClient.post(url, params);
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/api/software-component.service.ts b/admin/WebConsole3/frontend/src/app/api/software-component.service.ts
index 6b794109..b154d41a 100644
--- a/admin/WebConsole3/frontend/src/app/api/software-component.service.ts
+++ b/admin/WebConsole3/frontend/src/app/api/software-component.service.ts
@@ -1,20 +1,20 @@
-import { Injectable } from '@angular/core';
-import { HttpClient} from '@angular/common/http';
-
-import { environment } from '../../environments/environment';
-import { SoftwareComponent } from "../model/software-component";
-import { SoftwareComponentSerializer } from "../serializer/software-component.serializer";
-
-import {ResourceService} from "globunet-angular/core/providers/api/resource.service";
-
-
-@Injectable({
- providedIn: 'root'
-})
-export class SoftwareComponentService extends ResourceService<SoftwareComponent> {
-
- constructor(http: HttpClient){
- super(http, environment.API_URL,"softwareComponents", new SoftwareComponentSerializer());
- }
-
-}
+import { Injectable } from '@angular/core';
+import { HttpClient} from '@angular/common/http';
+
+import { environment } from '../../environments/environment';
+import { SoftwareComponent } from "../model/software-component";
+import { SoftwareComponentSerializer } from "../serializer/software-component.serializer";
+
+import {ResourceService} from "globunet-angular/core/providers/api/resource.service";
+
+
+@Injectable({
+ providedIn: 'root'
+})
+export class SoftwareComponentService extends ResourceService<SoftwareComponent> {
+
+ constructor(http: HttpClient){
+ super(http, environment.API_URL,"softwarecomponents", new SoftwareComponentSerializer());
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/api/software-profile.service.ts b/admin/WebConsole3/frontend/src/app/api/software-profile.service.ts
index 442d97a7..92b09e23 100644
--- a/admin/WebConsole3/frontend/src/app/api/software-profile.service.ts
+++ b/admin/WebConsole3/frontend/src/app/api/software-profile.service.ts
@@ -1,20 +1,20 @@
-import { Injectable } from '@angular/core';
-import { HttpClient} from '@angular/common/http';
-
-import { environment } from '../../environments/environment';
-import { SoftwareProfile } from "../model/software-profile";
-import { SoftwareProfileSerializer } from "../serializer/software-profile.serializer";
-
-import {ResourceService} from "globunet-angular/core/providers/api/resource.service";
-
-
-@Injectable({
- providedIn: 'root'
-})
-export class SoftwareProfileService extends ResourceService<SoftwareProfile> {
-
- constructor(http: HttpClient){
- super(http, environment.API_URL,"softwareProfiles", new SoftwareProfileSerializer());
- }
-
-}
+import { Injectable } from '@angular/core';
+import { HttpClient} from '@angular/common/http';
+
+import { environment } from '../../environments/environment';
+import { SoftwareProfile } from "../model/software-profile";
+import { SoftwareProfileSerializer } from "../serializer/software-profile.serializer";
+
+import {ResourceService} from "globunet-angular/core/providers/api/resource.service";
+
+
+@Injectable({
+ providedIn: 'root'
+})
+export class SoftwareProfileService extends ResourceService<SoftwareProfile> {
+
+ constructor(http: HttpClient){
+ super(http, environment.API_URL,"softwareprofiles", new SoftwareProfileSerializer());
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/api/software-type.service.ts b/admin/WebConsole3/frontend/src/app/api/software-type.service.ts
index aa2e457e..ccc6eb8f 100644
--- a/admin/WebConsole3/frontend/src/app/api/software-type.service.ts
+++ b/admin/WebConsole3/frontend/src/app/api/software-type.service.ts
@@ -1,20 +1,20 @@
-import { Injectable } from '@angular/core';
-import { HttpClient} from '@angular/common/http';
-
-import { environment } from '../../environments/environment';
-import { SoftwareType } from "../model/software-type";
-import { SoftwareTypeSerializer } from "../serializer/software-type.serializer";
-
-import {ResourceService} from "globunet-angular/core/providers/api/resource.service";
-
-
-@Injectable({
- providedIn: 'root'
-})
-export class SoftwareTypeService extends ResourceService<SoftwareType> {
-
- constructor(http: HttpClient){
- super(http, environment.API_URL,"softwareTypes", new SoftwareTypeSerializer());
- }
-
-}
+import { Injectable } from '@angular/core';
+import { HttpClient} from '@angular/common/http';
+
+import { environment } from '../../environments/environment';
+import { SoftwareType } from "../model/software-type";
+import { SoftwareTypeSerializer } from "../serializer/software-type.serializer";
+
+import {ResourceService} from "globunet-angular/core/providers/api/resource.service";
+
+
+@Injectable({
+ providedIn: 'root'
+})
+export class SoftwareTypeService extends ResourceService<SoftwareType> {
+
+ constructor(http: HttpClient){
+ super(http, environment.API_URL,"softwaretypes", new SoftwareTypeSerializer());
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/app-routing.module.ts b/admin/WebConsole3/frontend/src/app/app-routing.module.ts
index 7e5c4c63..f91738a4 100644
--- a/admin/WebConsole3/frontend/src/app/app-routing.module.ts
+++ b/admin/WebConsole3/frontend/src/app/app-routing.module.ts
@@ -17,6 +17,19 @@ import {ImageEditComponent} from './pages/image/edit/image-edit.component';
import {ProfileComponent} from './pages/profile/profile.component';
import {OrganizationalUnitEditComponent} from './pages/organizational-unit/edit/organizational-unit-edit.component';
import {ClientComponent} from './pages/client/client.component';
+import {ClientDhcpComponent} from './pages/client/dhcp/client-dhcp.component';
+import {DeployImageCommandComponent} from './pages/command/deploy-image-command/deploy-image-command.component';
+import {MenuComponent} from './pages/menu/menu.component';
+import {MenuEditComponent} from './pages/menu/edit/menu-edit.component';
+import {SoftwareProfileComponent} from './pages/software-profile/software-profile.component';
+import {SoftwareComponentComponent} from './pages/software-component/software-component.component';
+import {SoftwareComponent} from './pages/software/software.component';
+import {LoginCommandComponent} from './pages/command/login-command/login-command.component';
+import {ExecuteCommandComponent} from './pages/command/execute-command/execute-command.component';
+import {CreateImageCommandComponent} from './pages/command/create-image-command/create-image-command.component';
+import {DeleteCacheImageCommandComponent} from './pages/command/delete-cache-image-command/delete-cache-image-command.component';
+import {FormatCommandComponent} from './pages/command/format-command/format-command.component';
+import {PartitionFormatCommandComponent} from './pages/command/partition-format-command/partition-format-command.component';
const routes: Routes = [
@@ -59,14 +72,18 @@ const routes: Routes = [
},
{
path: 'clients/dhcp',
- component: ClientComponent
+ component: ClientDhcpComponent
},
{
path: 'images',
component: ImageComponent
},
{
- path: 'images/create',
+ path: 'images/create/monolithic',
+ component: ImageEditComponent
+ },
+ {
+ path: 'images/create/basic',
component: ImageEditComponent
},
{
@@ -94,10 +111,66 @@ const routes: Routes = [
component: HardwareProfileComponent
},
{
+ path: 'software',
+ component: SoftwareComponent,
+ },
+ {
+ path: 'software/profile/create',
+ component: SoftwareProfileComponent
+ },
+ {
+ path: 'software/component/create',
+ component: SoftwareComponentComponent
+ },
+ {
+ path: 'software/profile/:id',
+ component: SoftwareProfileComponent
+ },
+ {
+ path: 'menus',
+ component: MenuComponent
+ },
+ {
+ path: 'menus/create',
+ component: MenuEditComponent
+ },
+ {
+ path: 'menus/edit/:id',
+ component: MenuEditComponent
+ },
+ {
path: 'commands',
component: CommandComponent
},
{
+ path: 'commands/partition_format',
+ component: PartitionFormatCommandComponent
+ },
+ {
+ path: 'commands/deploy_image',
+ component: DeployImageCommandComponent
+ },
+ {
+ path: 'commands/login',
+ component: LoginCommandComponent
+ },
+ {
+ path: 'commands/execute',
+ component: ExecuteCommandComponent
+ },
+ {
+ path: 'commands/create_image',
+ component: CreateImageCommandComponent
+ },
+ {
+ path: 'commands/delete_cache_image',
+ component: DeleteCacheImageCommandComponent
+ },
+ {
+ path: 'commands/format',
+ component: FormatCommandComponent
+ },
+ {
path: 'commands/:id',
component: EditCommandComponent
},
diff --git a/admin/WebConsole3/frontend/src/app/app.component.html b/admin/WebConsole3/frontend/src/app/app.component.html
index 8e5b9670..d6c88664 100644
--- a/admin/WebConsole3/frontend/src/app/app.component.html
+++ b/admin/WebConsole3/frontend/src/app/app.component.html
@@ -4,8 +4,8 @@
<ng-template #layoutEnabled>
<mk-layout-wrapper>
<mk-layout-header logoLink="/">
- <mk-layout-header-logo><b>Angular </b>AdminLTE</mk-layout-header-logo>
- <mk-layout-header-logo-mini><b>A</b>LTE</mk-layout-header-logo-mini>
+ <mk-layout-header-logo>Open<b>GnSys</b> 3</mk-layout-header-logo>
+ <mk-layout-header-logo-mini>O<b>G</b>3</mk-layout-header-logo-mini>
<app-header-inner></app-header-inner>
</mk-layout-header>
<mk-layout-sidebar-left>
@@ -15,12 +15,12 @@
<app-sidebar-right-inner></app-sidebar-right-inner>
</mk-layout-sidebar-right>
<mk-layout-content>
- <div mk-layout-content-before-header>
- <div *mkLoadingPage="{checkPendingHttp: true, checkPendingRoute: true}">
- <mk-material-bar></mk-material-bar>
+ <router-outlet></router-outlet>
+ <div>
+ <div class="loader" *mkLoadingPage="{checkPendingHttp: true, checkPendingRoute: true}">
+ <mk-circle></mk-circle>
</div>
</div>
- <router-outlet></router-outlet>
</mk-layout-content>
<mk-layout-footer>
<mk-layout-footer-left>
diff --git a/admin/WebConsole3/frontend/src/app/app.module.ts b/admin/WebConsole3/frontend/src/app/app.module.ts
index 3dd55fe6..34af2cb2 100644
--- a/admin/WebConsole3/frontend/src/app/app.module.ts
+++ b/admin/WebConsole3/frontend/src/app/app.module.ts
@@ -10,7 +10,7 @@ import {AuthModule, TokenInterceptorService} from 'globunet-angular/core';
import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule} from '@angular/common/http';
import {LoginComponent} from './pages/login/login.component';
import {ImageComponent} from './pages/image/image.component';
-import { LoadingPageModule, MaterialBarModule } from 'angular-loading-page';
+import { LoadingPageModule, CircleModule } from 'angular-loading-page';
import { DashboardComponent } from './pages/dashboard/dashboard.component';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
import {TranslateLoader, TranslateModule, TranslateService} from '@ngx-translate/core';
@@ -26,8 +26,8 @@ import { HardwareComponent } from './pages/hardware/hardware.component';
import { HardwareComponentsComponent } from './pages/hardware/hardware-components/hardware-components.component';
import { HardwareProfilesComponent } from './pages/hardware/hardware-profiles/hardware-profiles.component';
import { HardwareTypesComponent } from './pages/hardware/hardware-types/hardware-types.component';
-import {ProfilesTableComponent} from './pages/hardware/hardware-profiles/profiles-table/profiles-table.component';
-import {ProfilesGroupComponent} from './pages/hardware/hardware-profiles/profiles-group/profiles-group.component';
+import {HardwareProfilesTableComponent} from './pages/hardware/hardware-profiles/profiles-table/hardware-profiles-table.component';
+import {HardwareProfilesGroupComponent} from './pages/hardware/hardware-profiles/profiles-group/hardware-profiles-group.component';
import {HardwareComponentsTableComponent} from './pages/hardware/hardware-components/hardware-components-table/hardware-components-table.component';
import {HardwareComponentsGroupComponent} from './pages/hardware/hardware-components/hardware-components-group/hardware-components-group.component';
import {HardwareProfileComponent} from './pages/hardware-profile/hardware-profile.component';
@@ -58,6 +58,27 @@ import {OrganizationalUnitEditComponent} from './pages/organizational-unit/edit/
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {ClientComponent} from './pages/client/client.component';
import {ChartsModule} from 'ng2-charts';
+import {ClientDhcpComponent} from './pages/client/dhcp/client-dhcp.component';
+import {DeployImageCommandComponent} from './pages/command/deploy-image-command/deploy-image-command.component';
+import {MenuComponent} from './pages/menu/menu.component';
+import {MenuEditComponent} from './pages/menu/edit/menu-edit.component';
+import {SoftwareComponentComponent} from './pages/software-component/software-component.component';
+import {SoftwareComponent} from './pages/software/software.component';
+import {SoftwareComponentsComponent} from './pages/software/software-components/software-components.component';
+import {SoftwareProfilesComponent} from './pages/software/software-profiles/software-profiles.component';
+import {SoftwareProfileComponent} from './pages/software-profile/software-profile.component';
+import {SoftwareTypesComponent} from './pages/software/software-types/software-types.component';
+import {SoftwareProfilesTableComponent} from './pages/software/software-profiles/software-profiles-table/software-profiles-table.component';
+import {SoftwareProfilesGroupComponent} from './pages/software/software-profiles/software-profiles-group/software-profiles-group.component';
+import {SoftwareComponentsTableComponent} from './pages/software/software-components/software-components-table/software-components-table.component';
+import {SoftwareComponentsGroupComponent} from './pages/software/software-components/software-components-group/software-components-group.component';
+import {LoginCommandComponent} from './pages/command/login-command/login-command.component';
+import {ExecuteCommandComponent} from './pages/command/execute-command/execute-command.component';
+import {CreateImageCommandComponent} from './pages/command/create-image-command/create-image-command.component';
+import {DeleteCacheImageCommandComponent} from './pages/command/delete-cache-image-command/delete-cache-image-command.component';
+import {FormatCommandComponent} from './pages/command/format-command/format-command.component';
+import {PartitionFormatCommandComponent} from './pages/command/partition-format-command/partition-format-command.component';
+import {ColResizableDirective} from './pages/common/directive/col-resizable.directive';
@@ -67,6 +88,8 @@ import {ChartsModule} from 'ng2-charts';
LoginComponent,
ImageComponent,
ImageEditComponent,
+ MenuComponent,
+ MenuEditComponent,
DashboardComponent,
RepositoryComponent,
OrganizationalUnitComponent,
@@ -79,17 +102,36 @@ import {ChartsModule} from 'ng2-charts';
HardwareProfilesComponent,
HardwareProfileComponent,
HardwareTypesComponent,
- ProfilesTableComponent,
- ProfilesGroupComponent,
+ HardwareProfilesTableComponent,
+ HardwareProfilesGroupComponent,
HardwareComponentsTableComponent,
HardwareComponentsGroupComponent,
+ SoftwareComponentComponent,
+ SoftwareComponent,
+ SoftwareComponentsComponent,
+ SoftwareProfilesComponent,
+ SoftwareProfileComponent,
+ SoftwareTypesComponent,
+ SoftwareProfilesTableComponent,
+ SoftwareProfilesGroupComponent,
+ SoftwareComponentsTableComponent,
+ SoftwareComponentsGroupComponent,
OuGroupComponent,
OuClientComponent,
ClientComponent,
+ ClientDhcpComponent,
CommandComponent,
+ DeployImageCommandComponent,
+ LoginCommandComponent,
+ ExecuteCommandComponent,
+ CreateImageCommandComponent,
+ DeleteCacheImageCommandComponent,
+ FormatCommandComponent,
+ PartitionFormatCommandComponent,
EditCommandComponent,
IcheckDirective,
FixedToolboxBarDirective,
+ ColResizableDirective,
OgInformationOptionsComponent,
OgCommandsOptionsComponent,
OgExecuteCommandOptionsComponent,
@@ -110,17 +152,31 @@ import {ChartsModule} from 'ng2-charts';
LoginComponent,
ImageComponent,
ImageEditComponent,
+ MenuComponent,
+ MenuEditComponent,
OrganizationalUnitComponent,
OrganizationalUnitEditComponent,
Ng2TableActionComponent,
- ProfilesTableComponent,
- ProfilesGroupComponent,
+ HardwareProfilesTableComponent,
+ HardwareProfilesGroupComponent,
HardwareComponentsTableComponent,
HardwareComponentsGroupComponent,
+ SoftwareProfilesTableComponent,
+ SoftwareProfilesGroupComponent,
+ SoftwareComponentsTableComponent,
+ SoftwareComponentsGroupComponent,
OuGroupComponent,
OuClientComponent,
ClientComponent,
+ ClientDhcpComponent,
CommandComponent,
+ DeployImageCommandComponent,
+ LoginCommandComponent,
+ ExecuteCommandComponent,
+ CreateImageCommandComponent,
+ DeleteCacheImageCommandComponent,
+ FormatCommandComponent,
+ PartitionFormatCommandComponent,
EditCommandComponent,
OgOuGeneralOptionsComponent,
TraceComponent,
@@ -134,7 +190,7 @@ import {ChartsModule} from 'ng2-charts';
CoreModule,
DropdownModule,
LayoutModule.forRoot(AdminLteConf.staticConf),
- LoadingPageModule, MaterialBarModule,
+ LoadingPageModule, CircleModule,
BrowserAnimationsModule,
HttpClientModule,
AuthModule.forRoot(environment),
diff --git a/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html b/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html
index ad565376..31b4286d 100644
--- a/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html
+++ b/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html
@@ -2,20 +2,16 @@
<ul class="nav navbar-nav">
<li mk-dropdown type="list" [isWrapper]="false" class="notifications-menu">
<mk-dropdown-toggle>
- <a [routerLink]="'/app/traces'" *ngIf="executionTasks.length == 0" #toggleElement>
- <i class="fa fa-bell-o"></i>
- </a>
- <a *ngIf="executionTasks.length > 0" #toggleElement>
- <i class="fa fa-bell-o"></i>
- <span class="label label-warning" *ngIf="executionTasks.length > 0">{{executionTasks.length}}</span>
- </a>
+ <a #toggleElement>
+ <i class="fa fa-bell-o"></i>
+ <span class="label label-warning" *ngIf="executionTasks.length > 0">{{executionTasks.length}}</span>
+ </a>
</mk-dropdown-toggle>
- <mk-dropdown-menu *ngIf="executionTasks.length > 0">
- <li class="header">You have 10 notifications</li>
- <li class="header">
+ <mk-dropdown-menu>
+ <li class="header" *ngIf="executionTasks.length > 0">
<span translate="you_have_x_exectution_taks" translate-values="{values: executionTasks.length}"></span>
</li>
- <li>
+ <li *ngIf="executionTasks.length > 0">
<!-- inner menu: contains the actual data -->
<ul class="menu" *ngFor="let task of executionTasks">
<li>
@@ -25,7 +21,7 @@
</a>
<a href="javascript:void(0)" (click)="relaunchExecutionTask(task)" class="btn btn-sm pull-right small-box-footer">
<i class="fa fa-refresh"></i>
- </a>
+ </a>A
</div>
<a href="javascript:void(0)" (click)="ogCommandsService.execute('REALTIME_LOG', {clientIp: task.client.ip})">
<i class="fa fa-warning text-yellow"></i> {{task.client.name}} ({{task.client.ip}})<br>{{task.commandType|translate}}
@@ -36,7 +32,7 @@
<li class="footer">
<a href="javascript:void(0)" translate="view_all" [routerLink]="['/app/traces']"></a>
</li>
- </mk-dropdown-menu>
+ </mk-dropdown-menu>
</li>
<!-- Tasks: style can be found in dropdown.less -->
<li mk-dropdown type="list" [isWrapper]="false" class="tasks-menu">
diff --git a/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.ts b/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.ts
index d009ebe7..8aaef052 100644
--- a/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.ts
+++ b/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.ts
@@ -62,7 +62,7 @@ export class HeaderInnerComponent implements OnInit {
self.getExectutionTasks();
},
function(error) {
- this.toaster.pop({type: 'error', title: 'error', body: error});
+ self.toaster.pop({type: 'error', title: 'error', body: error});
}
);
diff --git a/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.html b/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.html
index 7b2b79b6..68bebc52 100644
--- a/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.html
+++ b/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.html
@@ -3,7 +3,7 @@
<img src="assets/img/no-image.png" class="img-circle" alt="User Image">
</div>
<div class="pull-left info">
- <p>Alexander Pierce</p>
+ <p>{{user.username}}</p>
<a href="#"><i class="fa fa-circle text-success"></i> Online</a>
</div>
</div>
diff --git a/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.ts b/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.ts
index 036da6cb..991abdb2 100644
--- a/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.ts
+++ b/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.ts
@@ -1,7 +1,15 @@
-import { Component } from '@angular/core';
-
-@Component({
- selector: 'app-sidebar-left-inner',
- templateUrl: './sidebar-left-inner.component.html'
-})
-export class SidebarLeftInnerComponent {}
+import { Component } from '@angular/core';
+import {AuthModule} from 'globunet-angular/core';
+
+@Component({
+ selector: 'app-sidebar-left-inner',
+ templateUrl: './sidebar-left-inner.component.html'
+})
+export class SidebarLeftInnerComponent {
+ user: any;
+
+ constructor(private authModule: AuthModule) {
+ this.user = this.authModule.getLoggedUser();
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/form-type/menu.form-type.ts b/admin/WebConsole3/frontend/src/app/form-type/menu.form-type.ts
new file mode 100644
index 00000000..b17cc7a0
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/form-type/menu.form-type.ts
@@ -0,0 +1,16 @@
+import {GlobunetFormType} from './globunet.form-type';
+import {Menu} from '../model/menu';
+
+
+export class MenuFormType extends GlobunetFormType {
+ getForm() {
+ const form: any[] = GlobunetFormType.getForm(new Menu());
+ this.setFieldType(form, 'description', 'textarea');
+ this.setFieldType(form, 'comments', 'textarea');
+ this.setFieldType(form, 'resolution', 'select');
+ this.getField(form, 'resolution').options = {
+ items: []
+ };
+ return form;
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/form-type/repository.form-type.ts b/admin/WebConsole3/frontend/src/app/form-type/repository.form-type.ts
index 15b1b9f8..c0a8fffd 100644
--- a/admin/WebConsole3/frontend/src/app/form-type/repository.form-type.ts
+++ b/admin/WebConsole3/frontend/src/app/form-type/repository.form-type.ts
@@ -1,9 +1,11 @@
-import {Repository} from '../model/repository';
-import {GlobunetFormType} from './globunet.form-type';
-
-
-export class RepositoryFormType {
- getForm() {
- return GlobunetFormType.getForm(new Repository());
- }
-}
+import {Repository} from '../model/repository';
+import {GlobunetFormType} from './globunet.form-type';
+
+
+export class RepositoryFormType extends GlobunetFormType{
+ getForm() {
+ const form = GlobunetFormType.getForm(new Repository());
+ this.setFieldType(form, 'description', 'textarea');
+ return form;
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/model/client.ts b/admin/WebConsole3/frontend/src/app/model/client.ts
index dbc9976e..8977e168 100644
--- a/admin/WebConsole3/frontend/src/app/model/client.ts
+++ b/admin/WebConsole3/frontend/src/app/model/client.ts
@@ -2,6 +2,20 @@ import { Resource } from 'globunet-angular/core/models/api/resource';
import {Repository} from './repository';
import {HardwareProfile} from './hardware-profile';
import {Netboot} from './netboot';
+import {PartitionInfo} from './image';
+
+export class Partition {
+ cacheContent: string;
+ filesystem: string;
+ id: number;
+ image: any;
+ numDisk: number;
+ numPartition: number;
+ osName: string;
+ partitionCode: string;
+ size: number;
+ usage: number;
+}
export class Client extends Resource {
public name = '';
@@ -15,8 +29,10 @@ export class Client extends Resource {
public oglive = null;
public netboot: Netboot = null;
public organizationalUnit: number;
+ public partitions?: PartitionInfo[]
// Variables temporales para la vista, no vienen del servidor
public status?: string;
public selected?: boolean;
+ public disksConfig?: any[];
}
diff --git a/admin/WebConsole3/frontend/src/app/model/command.ts b/admin/WebConsole3/frontend/src/app/model/command.ts
index 2f3639ba..2c5697aa 100644
--- a/admin/WebConsole3/frontend/src/app/model/command.ts
+++ b/admin/WebConsole3/frontend/src/app/model/command.ts
@@ -1,8 +1,14 @@
-import { Resource } from 'globunet-angular/core/models/api/resource';
-
-export class Command extends Resource {
- public title = '';
- public script = '';
- public parameters = false;
-
-}
+import { Resource } from 'globunet-angular/core/models/api/resource';
+
+export class Excecution {
+ script = '';
+ clients = '';
+ type = '';
+}
+
+export class Command extends Resource {
+ public title = '';
+ public script = '';
+ public parameters = false;
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/model/image.ts b/admin/WebConsole3/frontend/src/app/model/image.ts
index 2a85299f..5df31b74 100644
--- a/admin/WebConsole3/frontend/src/app/model/image.ts
+++ b/admin/WebConsole3/frontend/src/app/model/image.ts
@@ -1,20 +1,25 @@
-import { Resource } from 'globunet-angular/core/models/api/resource';
-import {Repository} from './repository';
-
-export class PartitionInfo {
- numDisk: number;
- numPartition: number;
- partitionCode: string;
- filesystem: string;
- osName: string;
-}
-
-export class Image extends Resource {
- public canonicalName: string = '';
- public repository: Repository = new Repository();
- public description: string = '';
- public comments: string = '';
- public revision: string;
- public createdAt: Date;
- public partitionInfo: PartitionInfo;
-}
+import { Resource } from 'globunet-angular/core/models/api/resource';
+import {Repository} from './repository';
+import {Client} from './client';
+import {SoftwareProfile} from './software-profile';
+
+export class PartitionInfo {
+ numDisk: number;
+ numPartition: number;
+ partitionCode: string;
+ filesystem: string;
+ osName: string;
+ type: string;
+}
+
+export class Image extends Resource {
+ public canonicalName = '';
+ public repository: Repository = new Repository();
+ public description = '';
+ public comments = '';
+ public revision: string;
+ public createdAt: Date;
+ public softwareProfile: SoftwareProfile;
+ public partitionInfo: PartitionInfo;
+ public client?: Client;
+}
diff --git a/admin/WebConsole3/frontend/src/app/model/menu.ts b/admin/WebConsole3/frontend/src/app/model/menu.ts
index e8928976..1d19bd44 100644
--- a/admin/WebConsole3/frontend/src/app/model/menu.ts
+++ b/admin/WebConsole3/frontend/src/app/model/menu.ts
@@ -1,12 +1,12 @@
-import { Resource } from 'globunet-angular/core/models/api/resource';
-
-export class Menu extends Resource {
- public title: string;
- public resolution: string;
- public description: string;
- public comments: string;
- public publicColumns: number;
- public publicUrl: string;
- public privateColumns: number;
- public privateUrl: string;
-}
+import { Resource } from 'globunet-angular/core/models/api/resource';
+
+export class Menu extends Resource {
+ public title = '';
+ public resolution = '';
+ public description = '';
+ public comments = '';
+ public publicUrl = ''
+ public privateUrl = '';
+ public publicColumns: number;
+ public privateColumns: number;
+}
diff --git a/admin/WebConsole3/frontend/src/app/model/repository.ts b/admin/WebConsole3/frontend/src/app/model/repository.ts
index 5b6756d2..36838128 100644
--- a/admin/WebConsole3/frontend/src/app/model/repository.ts
+++ b/admin/WebConsole3/frontend/src/app/model/repository.ts
@@ -1,25 +1,17 @@
-import { Resource } from 'globunet-angular/core/models/api/resource';
-
-export class Repository extends Resource {
- name: string;
- ip: string;
- port: number;
- password: string;
- configurationpath: string;
- adminpath: string;
- pxepath: string;
- description: string;
- info: any;
-
- constructor() {
- super();
- this.name = '';
- this.ip = '';
- this.port = 0;
- this.password = '';
- this.configurationpath = '';
- this.adminpath = '';
- this.pxepath = '';
- this.description = '';
- }
-}
+import { Resource } from 'globunet-angular/core/models/api/resource';
+
+export class Repository extends Resource {
+ name: string;
+ ip: string;
+ password: string;
+ description: string;
+ info: any;
+
+ constructor() {
+ super();
+ this.name = '';
+ this.ip = '';
+ this.password = '';
+ this.description = '';
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/client/client.component.html b/admin/WebConsole3/frontend/src/app/pages/client/client.component.html
index 0ba00d7d..81c0a3ac 100644
--- a/admin/WebConsole3/frontend/src/app/pages/client/client.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/client/client.component.html
@@ -3,7 +3,7 @@
</h1>
<ol class="breadcrumb">
<li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li>
- <li><a [routerLink]="'/app/ous'" ><i class="fa fa-th"></i> {{'ous'|translate}}</a></li>
+ <li><a [routerLink]="'/app/ous'"><i class="fa fa-th"></i> {{'ous'|translate}}</a></li>
<li class="active" translate="client"></li>
</ol>
</section>
@@ -24,18 +24,18 @@
<h3 class="box-title" translate="client_data"></h3>
<div class="box-tools pull-right">
<div class="btn-group" *ngIf="client.id !== 0">
- <app-og-information-options ></app-og-information-options>
+ <app-og-information-options></app-og-information-options>
<app-og-commands-options></app-og-commands-options>
</div>
</div>
</mk-box-header>
<mk-box-content>
<form role="form" name="Form">
- <app-form-input [formType]="form" [cols]="2" [model]="client" ></app-form-input>
+ <app-form-input [formType]="form" [cols]="2" [model]="client"></app-form-input>
</form>
</mk-box-content>
- <mk-box-footer >
- <mk-box class="box box-default box-solid" *ngFor="let diskConfig of client.diskConfig">
+ <mk-box-footer>
+ <mk-box class="box box-default box-solid" [isRemovable]="false" *ngFor="let diskConfig of client.disksConfig">
<mk-box-header class="box-header with-border">
<div class="row">
<div class="col-md-4">
@@ -48,10 +48,6 @@
<span translate="size"></span>: <b>{{getSizeInGB(diskConfig.size)}} GB</b>
</div>
</div>
- <div class="box-tools pull-right">
- <button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i>
- </button>
- </div>
<!-- /.box-tools -->
</mk-box-header>
<!-- /.box-header -->
@@ -69,47 +65,62 @@
<th translate="os"></th>
</tr>
</tbody>
- <ng-template *ngIf="partition.size > 0">
- <tbody *ngFor="let partition of diskConfig.partitions" >
- <tr ng-class="{'odd': $index%2 == 0, 'even': $index%2 != 0}">
- <td>{{partition.numPartition}}</td>
- <td>{{partition.parttype}}</td>
- <td>{{partition.filesystem}}</td>
- <td>{{getSizeInGB(partition.size)}} GB</td>
- <td><span class="badge" ng-class="{'bg-green': partition.usage < 60, 'bg-yellow': partition.usage >= 60 && partition.usage < 80, 'bg-red': partition.usage >= 80}">{{partition.usage}}%</span></td>
- <td>{{partition.osName}}</td>
- </tr>
- <tr *ngIf="partition.partitionCode == 'ca' && partition.cacheContent.files.length > 0" class="client-cache-info" ng-class="{'odd': $index%2 == 0, 'even': $index%2 != 0}">
- <td colspan="6">
- <span style="font-weight: bold" translate="cache_content"></span>
- <table class="table">
- <thead>
- <tr>
- <th translate="type"></th>
- <th translate="name"></th>
- <th translate="size"></th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let file of partition.cacheContent.files">
- <td>{{file.type}}</td>
- <td>{{file.name}}</td>
- <td>{{file.size}}</td>
- </tr>
- <tr>
- <td style="font-weight: bold" translate="free_space" colspan="2"></td>
- <td>{{partition.cacheContent.freeSpace}}</td>
- </tr>
- </tbody>
- </table>
- </td>
- </tr>
- </tbody>
- </ng-template>
+ <ng-container *ngFor="let partition of diskConfig.partitions">
+ <tbody *ngIf="partition.size > 0">
+ <tr ng-class="{'odd': $index%2 == 0, 'even': $index%2 != 0}">
+ <td>{{partition.numPartition}}</td>
+ <td>{{partition.parttype}}</td>
+ <td>{{partition.filesystem}}</td>
+ <td>{{getSizeInGB(partition.size)}} GB</td>
+ <td><span class="badge"
+ [ngClass]="getPartitionUsageClass(partition.usage)">{{partition.usage}}
+ %</span></td>
+ <td>{{partition.osName}}</td>
+ </tr>
+ <tr *ngIf="partition.partitionCode == 'ca' && partition.cacheContent.files.length > 0"
+ class="client-cache-info"
+ ng-class="{'odd': $index%2 == 0, 'even': $index%2 != 0}">
+ <td colspan="6">
+ <span style="font-weight: bold" translate="cache_content"></span>
+ <table class="table">
+ <thead>
+ <tr>
+ <th translate="type"></th>
+ <th translate="name"></th>
+ <th translate="size"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let file of partition.cacheContent.files">
+ <td>{{file.type}}</td>
+ <td>{{file.name}}</td>
+ <td>{{file.size}}</td>
+ </tr>
+ <tr>
+ <td style="font-weight: bold" translate="free_space"
+ colspan="2"></td>
+ <td>{{partition.cacheContent.freeSpace}}</td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ </tbody>
+ </ng-container>
</table>
</div>
<div class="col-md-4">
<!--flot dataset="diskConfig.diskChartData" options="diskConfig.diskChartOptions" height="200px"></flot-->
+ <div class="chart" >
+ <canvas baseChart
+ [data]="diskConfig.diskChartData"
+ [labels]="diskConfig.diskChartLabels"
+ [colors]="diskConfig.diskPieChartColors"
+ [chartType]="'pie'"
+ [plugins]="pluginDataLabels"
+ [options]="diskConfig.diskChartOptions">
+ </canvas>
+ </div>
</div>
</div>
</mk-box-content>
diff --git a/admin/WebConsole3/frontend/src/app/pages/client/client.component.ts b/admin/WebConsole3/frontend/src/app/pages/client/client.component.ts
index 50346ffd..0611d6dc 100644
--- a/admin/WebConsole3/frontend/src/app/pages/client/client.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/client/client.component.ts
@@ -12,7 +12,8 @@ import {Repository} from '../../model/repository';
import {HardwareProfile} from '../../model/hardware-profile';
import {OgCommonService} from '../../service/og-common.service';
import {ClientFormType} from '../../form-type/client.form-type';
-import {GlobunetFormType} from '../../form-type/globunet.form-type';
+import * as pluginDataLabels from 'chartjs-plugin-datalabels';
+import {ChartOptions} from 'chart.js';
@Component({
selector: 'app-client',
@@ -27,6 +28,7 @@ export class ClientComponent implements OnInit {
public oglives: any[] = [];
private formType: ClientFormType;
public form;
+ public pluginDataLabels;
// this tells the tabs component which Pages
// should be each tab's root Page
@@ -39,6 +41,7 @@ export class ClientComponent implements OnInit {
private hardwareProfileService: HardwareProfileService,
private ogCommonService: OgCommonService) {
this.client = new Client();
+ this.client.disksConfig = [];
this.formType = new ClientFormType();
this.form = this.formType.getForm();
}
@@ -57,6 +60,17 @@ export class ClientComponent implements OnInit {
this.clientService.read(id).subscribe(
client => {
this.client = client;
+ this.client.disksConfig = this.ogCommonService.getDisksConfigFromPartitions(this.client.partitions);
+
+ const self = this;
+ this.client.disksConfig.forEach(function(diskConfig) {
+ const chartData = self.getChartData(diskConfig);
+ diskConfig.diskChartData = chartData.diskChartData;
+ diskConfig.diskChartLabels = chartData.diskChartLabels;
+ diskConfig.diskPieChartColors = chartData.diskPieChartColors;
+ diskConfig.diskChartOptions = chartData.diskChartOptions;
+ });
+
}
);
}
@@ -122,6 +136,75 @@ export class ClientComponent implements OnInit {
);
}
+ getChartData(diskConfig) {
+ const diskChartData = [];
+ const diskChartLabels = [];
+ const diskPieChartColors = [{
+ backgroundColor: []
+ }];
+ const self = this;
+ diskConfig.partitions.forEach(function(partition) {
+ if (partition.size > 0) {
+ self.setPartitionPercentOfDisk(diskConfig, partition);
+ diskChartData.push(partition.percentOfDisk);
+ diskChartLabels.push([
+ (partition.os || partition.filesystem),
+ partition.percentOfDisk + '%'
+ ]);
+ diskPieChartColors[0].backgroundColor.push(self.getPartitionColor(partition));
+ }
+ });
+ const diskChartOptions: ChartOptions = {
+ responsive: true,
+ legend: {
+ position: 'bottom'
+ },
+ plugins: {
+ datalabels: {
+ formatter: (value, ctx) => {
+ const label = ctx.chart.data.labels[ctx.dataIndex];
+ return label;
+ },
+ },
+ }
+ };
+
+ return {
+ diskChartData: diskChartData,
+ diskChartLabels: diskChartLabels,
+ diskChartOptions: diskChartOptions,
+ diskPieChartColors: diskPieChartColors
+ };
+ }
+
+ setPartitionPercentOfDisk(diskConfig, partition) {
+ partition.percentOfDisk = Math.round(((partition.size * 100) / diskConfig.size) * 100) / 100;
+ }
+
+ labelFormatter(label, series) {
+ return '<div style="font-size:13px; text-align:center; padding:2px; color: #000; font-weight: 600;">'
+ + '<br>'
+ + series.percentOfDisk + '%</div>';
+ }
+
+ getPartitionColor(partition) {
+ let color = 'rgb(252, 90, 90)';
+
+ // Para la partición de datos se usa un color específico
+ if (partition.osName === 'DATA') {
+ color = 'rgb(237,194,64)';
+ } else if (partition.filesystem === 'NTFS') {
+ color = 'rgb(0,192, 239)';
+ } else if (partition.filesystem.match('EXT')) {
+ color = 'rgb(96, 92, 168)';
+ } else if (partition.filesystem.match('LINUX-SWAP')) {
+ color = 'rgb(84, 84, 84)';
+ } else if (partition.filesystem.match('CACHE')) {
+ color = 'rgb(252, 90, 90)';
+ }
+ return color;
+ }
+
save() {
let request: Observable<Client>;
if (this.client.id !== 0) {
@@ -146,5 +229,16 @@ export class ClientComponent implements OnInit {
}
+ getPartitionUsageClass(usage: number | string | number) {
+ let result = '';
+ if (usage < 60) {
+ result = 'bg-green';
+ } else if (usage >= 60 && usage < 80) {
+ result = 'bg-yellow';
+ } else if (usage >= 80) {
+ result = 'bg-red';
+ }
+ return result;
+ }
}
diff --git a/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.html b/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.html
new file mode 100644
index 00000000..c21f5c8d
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.html
@@ -0,0 +1,139 @@
+<section class="content-header">
+ <h1 translate="dhcp_clients">
+ </h1>
+ <ol class="breadcrumb">
+ <li><a [routerLink]="'app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li>
+ <li><a [routerLink]="'app/ous'" ><i class="fa fa-th"></i> {{'ous'|translate}}</a></li>
+ <li class="active" translate="dhcp_clients"></li>
+ </ol>
+</section>
+<section fixed-toolboxbar class="toolboxbar">
+ <div>
+ <div class="col-md-12">
+ <div class="box-tools pull-right">
+ <button class="btn btn-primary" translate="save" (click)="save()"></button>
+ </div>
+ </div>
+ </div>
+</section>
+<section class="content">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="box box-primary">
+ <div class="box-header with-border">
+ <h3 class="box-title" translate="load_clients_from_dhcp"></h3>
+ <div *ngIf="clients.length == 0" class="btn-group pull-right">
+ <button type="button" name="search" id="search-btn" class="btn btn-flat" (click)="downloadFromServer()">
+ <i class="fa fa-download"></i>
+ <span translate="download_from_server"></span>
+ </button>
+ <button class="btn btn-primary" (click)="proccessDhcp()" translate="proccess_dhcp"></button>
+ </div>
+ <div *ngIf="clients.length > 0" class="pull-right">
+ <button class="btn btn-danger" (click)="clients = []" translate="back"></button>
+ </div>
+ </div>
+ <div *ngIf="clients.length == 0" class="box-body">
+ <div class="row">
+ <div class="col-md-12">
+ <textarea [(ngModel)]="dhcpText" class="og-instructions">
+
+ </textarea>
+ </div>
+ </div>
+ </div>
+ <div class="box-body" *ngIf="clients.length > 0">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="box box-default">
+ <div class="box-header with-border">
+ <h3 class="box-title" translate="common_options"></h3>
+ </div>
+ <div class="box-body">
+ <div class="row">
+ <div class="col-xs-2">
+ <div class="form-group">
+ <label class="control-label" for="repository" translate="repository"></label>
+ <select name="repository" class="form-control" [(ngModel)]="commonProperties.repository">
+ <option *ngFor="let repository of repositories" [value]="repository.id">{{repository.name}}</option>
+ </select>
+ </div>
+ </div>
+ <div class="col-xs-2">
+ <div class="form-group">
+ <label class="control-label" for="hardwareProfile" translate="hardware_profile"></label>
+ <select name="hardwareProfile" class="form-control" [(ngModel)]="commonProperties.hardwareProfile">
+ <option *ngFor="let profile of hardwareProfiles" [value]="profile.id">
+ {{profile.description}}
+ </option>
+ </select>
+ </div>
+ </div>
+ <div class="col-xs-1">
+ <div class="form-group">
+ <label class="control-label" for="netiface" translate="netiface"></label>
+ <input type="text" name="netiface" class="form-control" [(ngModel)]="commonProperties.netiface" />
+ </div>
+ </div>
+ <div class="col-xs-2">
+ <div class="form-group">
+ <label class="control-label" for="netdriver" translate="netdriver"></label>
+ <input type="text" name="netdriver" class="form-control" [(ngModel)]="commonProperties.netdriver" />
+ </div>
+ </div>
+ <div class="form-group col-md-3">
+ <label for="oglive" translate="oglive">
+ <span class="symbol required ng-scope"></span>
+ </label>
+ <select class="form-control" required="true" [(ngModel)]="commonProperties.oglive" name="oglive">
+ <option *ngFor="let item of constants.ogliveinfo" [value]="item.directory">
+ {{item.directory}}
+ </option>
+ </select>
+ </div>
+ <div class="form-group col-md-2">
+ <label for="netboot" translate="netboot">
+ <span class="symbol required ng-scope"></span>
+ </label>
+ <select class="form-control" required="true" [(ngModel)]="commonProperties.netboot" name="netboot">
+ <option *ngFor="let item of netboots" [value]="item.id">{{item.name}}</option>
+ </select>
+ </div>
+ </div>
+ </div>
+ <!-- /.box-body -->
+ </div>
+ </div>
+ <div class="col-md-12">
+ <table class="table table-striped">
+ <thead>
+ <tr>
+ <th>
+ <input icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" (change)="selectedUnselectAll()" [(ngModel)]="selectAll" />
+ <span translate="select"></span>
+ </th>
+ <th translate="name"></th>
+ <th translate="ip"></th>
+ <th translate="mac"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let client of clients">
+ <td>
+ <input icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" [(ngModel)]="client.$$selected" />
+ </td>
+ <td>{{client.name}}</td>
+ <td>{{client.ip}}</td>
+ <td>{{client.mac}}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="box-footer">
+ </div>
+ </div>
+ </div>
+ </div>
+</section>
diff --git a/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.scss b/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.scss
new file mode 100644
index 00000000..0bbea7e4
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.scss
@@ -0,0 +1,5 @@
+::ng-deep app-client {
+ ::ng-deep .box-title {
+ width: 100%;
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.ts b/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.ts
new file mode 100644
index 00000000..70394ba4
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.ts
@@ -0,0 +1,223 @@
+import {Component, OnInit} from '@angular/core';
+
+import {ClientService} from 'src/app/api/client.service';
+import {ActivatedRoute, ParamMap, Router} from '@angular/router';
+import {forkJoin, Observable} from 'rxjs';
+import {NetbootService} from '../../../api/netboot.service';
+import {ToasterService} from '../../../service/toaster.service';
+import {RepositoryService} from '../../../api/repository.service';
+import {HardwareProfileService} from '../../../api/hardware-profile.service';
+import {Repository} from '../../../model/repository';
+import {HardwareProfile} from '../../../model/hardware-profile';
+import {OgCommonService} from '../../../service/og-common.service';
+import {ClientFormType} from '../../../form-type/client.form-type';
+import {TranslateService} from '@ngx-translate/core';
+
+@Component({
+ selector: 'app-client-dhcp',
+ templateUrl: './client-dhcp.component.html',
+ styleUrls: ['./client-dhcp.component.scss']
+})
+export class ClientDhcpComponent implements OnInit {
+ public netboots: any = [];
+ public repositories: Repository[] = [];
+ public hardwareProfiles: HardwareProfile[] = [];
+ public oglives: any[] = [];
+ private formType: ClientFormType;
+ public form;
+ public constants = {};
+ private dhcpFile: string;
+ public commonProperties: any;
+ public dhcpText: string;
+ public clients: any[];
+ public selectAll: boolean;
+
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(private router: Router,
+ private activatedRouter: ActivatedRoute,
+ private clientService: ClientService,
+ private netbootService: NetbootService,
+ private translate: TranslateService,
+ private toaster: ToasterService,
+ private repositoryService: RepositoryService,
+ private hardwareProfileService: HardwareProfileService,
+ private ogCommonService: OgCommonService) {
+
+ this.commonProperties = {};
+ this.clients = [];
+
+ }
+
+ ngOnInit() {
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.constants = data.constants;
+ }
+ );
+ this.dhcpFile = '/etc/dhcp/dhcpd.conf';
+ this.loadNetboots();
+ // Los repositorios vienen cargados ya desde config.router
+ this.repositoryService.list().subscribe(
+ (repositories) => {
+ this.repositories = repositories;
+ this.commonProperties.repository = this.repositories[0].id;
+ if (!this.hardwareProfiles) {
+ this.hardwareProfileService.list().subscribe(
+ (response) => {
+ this.hardwareProfiles = response;
+ this.commonProperties.hardwareProfile = this.hardwareProfiles[0].id;
+ },
+ (error) => {
+ alert(error);
+ }
+ );
+ } else {
+ this.hardwareProfiles = this.hardwareProfiles;
+ }
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+
+ }
+
+ loadNetboots() {
+ this.netbootService.list().subscribe(
+ (result) => {
+ this.netboots = result;
+ this.commonProperties.netboot = this.netboots[0];
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+
+
+ downloadFromServer() {
+ this.dhcpText = 'ddns-update-style none;\n' +
+ 'option domain-name "example.org";\n' +
+ 'log-facility local7;\n' +
+ 'not-authoritative;\n' +
+ '\n' +
+ 'subnet 172.16.140.0 netmask 255.255.255.0 {\n' +
+ ' option domain-name-servers 172.16.3.1;\n' +
+ ' option routers 172.16.140.254;\n' +
+ ' option broadcast-address 172.16.140.255;\n' +
+ ' default-lease-time 600;\n' +
+ ' max-lease-time 7200;\n' +
+ ' next-server 172.16.140.210;\n' +
+ ' filename "grldr";\n' +
+ ' use-host-decl-names on;\n' +
+ '\n' +
+ '# host HOSTNAME1 {\n' +
+ '# hardware ethernet HOSTMAC1;\n' +
+ '# fixed-address HOSTIP1;\n' +
+ '# }\n' +
+ '\n' +
+ ' host pc-pruebas {\n' +
+ ' hardware ethernet 00:1B:21:1F:EE:9D;\n' +
+ ' fixed-address 172.16.140.213;\n' +
+ ' }\n' +
+ ' host pc-virtualbox {\n' +
+ ' hardware ethernet 20:CF:30:BF:9A:39;\n' +
+ ' fixed-address 172.16.140.214;\n' +
+ ' }\n' +
+ '\n' +
+ '\n' +
+ '}\n';
+ /*
+ ServerDchpResource.getDhcp().then(
+ function(response) {
+ this.dhcpText = response.text;
+ this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_loaded')});
+ },
+ function(error) {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ /**/
+ }
+
+ proccessDhcp() {
+ if (typeof this.dhcpText !== 'undefined' && this.dhcpText !== '') {
+ const lines = this.dhcpText.split('\n');
+ this.clients = [];
+ for (let i = 0; i < lines.length; i++) {
+ // Comprobar si la línea actual contiene la palabra "host" sin ninguna # delante que sería comentario
+ if (/^host/.test(lines[i].trim())) {
+ // Unimos las siguientes líneas hasta encontrar "}"
+ let line = '';
+ while(lines[i].indexOf("}") === -1 && i < lines.length){
+ line += lines[i];
+ i++;
+ }
+ // procesar la linea
+ // host pc53-151 { hardware ethernet 00:1E:33:61:49:B8; fixed-address 172.16.53.151; }
+ let parts = line.split('{');
+ const hostname = parts[0].trim().split(' ')[1];
+
+ // Las siguientes partes pueden estar en la linea actual o las siguientes
+ parts = parts[1].trim().split(";");
+ const mac = parts[0].trim().split('ethernet')[1];
+ // lo mismo puede ocurrir con fixed-address puede estar en lineas diferentes
+ parts = parts[1].trim().split('fixed-address');
+ const ip = parts[1];
+ this.clients.push(
+ {
+ name: hostname,
+ ip: ip,
+ mac: mac,
+ $$selected: true
+ }
+ );
+ }
+ }
+ } else {
+ this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('nothing_to_proccess')});
+ }
+ }
+
+ selectedUnselectAll() {
+ for (let c = 0; c < this.clients.length; c++) {
+ this.clients[c].$$selected = this.selectAll;
+ }
+ }
+
+ save() {
+ const promises = [];
+ let ou = '';
+ this.activatedRouter.queryParams.subscribe(
+ query => {
+ ou = query.ou;
+ }
+ );
+ for (let c = 0; c < this.clients.length; c++) {
+ if (this.clients[c].$$selected === true) {
+ const client = Object.assign({}, this.clients[c]);
+
+ // Si se indicó un padre en la url, se añade dicha propiedad
+ client.organizationalUnit = ou;
+ client.idproautoexec = 0;
+ client.netdriver = this.commonProperties.netdriver;
+ client.netiface = this.commonProperties.netiface;
+ // Propiedades comunes
+ // client.repository = this.commonProperties.repository;
+ // client.hardwareProfile = this.commonProperties.hardwareProfile;
+ promises.push(this.clientService.create(client));
+ }
+ }
+ forkJoin(promises).subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: 'success', body: 'Successfully saved'});
+ this.router.navigate(['/app/ous']);
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.html
new file mode 100644
index 00000000..9534718c
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.html
@@ -0,0 +1,98 @@
+<section class="content-header">
+ <h1 translate="create_image">
+ </h1>
+ <ol class="breadcrumb">
+ <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i>{{'dashboard'|translate}}</a></li>
+ <li><a [routerLink]="'/app/ous'"><i class="fa fa-th"></i>{{'ous'|translate}}</a></li>
+ <li class="active" translate="create_image"></li>
+ </ol>
+</section>
+<section fixed-toolboxbar class="toolboxbar">
+ <div>
+ <div class="col-md-12">
+ <div class="box-tools pull-right">
+ <button class="btn btn-primary" translate="execute" (click)="sendCommand()"></button>
+ </div>
+ </div>
+ </div>
+</section>
+<section style="padding: 0 30px;">
+ <h3 translate="selected_clients"></h3>
+ <app-og-selected-clients></app-og-selected-clients>
+</section>
+<!-- Main content -->
+<section class="content">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="box box-primary">
+ <div class="box-header with-border">
+ </div>
+ <div class="box-body">
+ <form role="form" name="Form">
+ <div class="form-group">
+ <label>
+ <span translate="client"></span>
+ {{client.name}}
+ </label>
+ </div>
+ <div class="form-group" ng-class="{'has-error':Form.images.$dirty && Form.images.$invalid, 'has-success':Form.images.$valid}">
+ <label for="images">
+ <span translate="images"></span>
+ </label>
+ <select (change)="setCanonicalName()" class="form-control" type="text" [(ngModel)]="command.image" name="images">
+ <option [ngValue]="null" translate="----"></option>
+ <option *ngFor="let image of images" [ngValue]="image">{{image.canonicalName}}</option>
+ </select>
+ </div>
+ <div class="form-group" ng-class="{'has-error':Form.canonicalName.$dirty && Form.canonicalName.$invalid, 'has-success':Form.canonicalName.$valid}">
+ <label for="canonicalName">
+ <span translate="canonicalName"></span>
+ <span class="symbol required"></span>
+ </label>
+ <input type="text" class="form-control" type="text" required="true" [(ngModel)]="command.canonicalName" name="canonicalName">
+ </div>
+ <div>
+ <table class="table">
+ <thead>
+ <tr>
+ <th translate="select">
+ </th>
+ <th translate="disk">
+ </th>
+ <th translate="partition">
+ </th>
+ <th translate="filesystem">
+ </th>
+ <th translate="osname">
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <ng-container *ngFor="let partition of client.partitions; let index = index;">
+ <tr *ngIf="isClonable(partition)">
+ <td>
+ <input icheck type="radio" [name]="'partition_'+partition.numPartition" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="selectedPartition" [value]="index" />
+ </td>
+ <td>
+ {{partition.numDisk}}
+ </td>
+ <td>
+ {{partition.numPartition}}
+ </td>
+ <td>
+ {{partition.filesystem}}
+ </td>
+ <td>
+ {{partition.osName}}
+ </td>
+ </tr>
+ </ng-container>
+ </tbody>
+ </table>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+</section>
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.scss
new file mode 100644
index 00000000..08b1082b
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.scss
@@ -0,0 +1,3 @@
+app-execute-command {
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.ts
new file mode 100644
index 00000000..8f018e33
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.ts
@@ -0,0 +1,188 @@
+import {Component, OnInit} from '@angular/core';
+
+import {ToasterService} from '../../../service/toaster.service';
+import {ActivatedRoute, Router} from '@angular/router';
+import {TranslateService} from '@ngx-translate/core';
+import {OgCommonService} from '../../../service/og-common.service';
+import {OgSweetAlertService} from '../../../service/og-sweet-alert.service';
+import {AuthModule} from 'globunet-angular/core';
+import {User} from '../../../model/user';
+import {OGCommandsService} from '../../../service/og-commands.service';
+import {CommandService} from '../../../api/command.service';
+import {Image} from '../../../model/image';
+import {Command, Excecution} from '../../../model/command';
+import {Client, Partition} from '../../../model/client';
+import {Repository} from '../../../model/repository';
+import {RepositoryService} from '../../../api/repository.service';
+import {ImageService} from '../../../api/image.service';
+import {forkJoin} from 'rxjs';
+
+@Component({
+ selector: 'app-create-image-command',
+ templateUrl: './create-image-command.component.html',
+ styleUrls: [ './create-image-command.component.scss' ]
+})
+export class CreateImageCommandComponent implements OnInit {
+ private readonly user: User;
+ private constants: any;
+ public repositories: Repository[];
+ public execution = new Excecution();
+ public commands: Command[] = [];
+ public client: Client;
+ public images = [];
+ public command = {canonicalName: '', image: new Image()};
+ public selectedPartition: number;
+
+
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(public ogCommandsService: OGCommandsService,
+ private authModule: AuthModule,
+ private router: Router,
+ private activatedRoute: ActivatedRoute,
+ private ogCommonService: OgCommonService,
+ private commandService: CommandService,
+ private imageService: ImageService,
+ private repositoryService: RepositoryService,
+ private ogSweetAlert: OgSweetAlertService,
+ private toaster: ToasterService,
+ private translate: TranslateService) {
+ this.user = this.authModule.getLoggedUser();
+ }
+
+
+
+ ngOnInit() {
+ if (this.user && this.ogCommonService.selectedClients) {
+ const clientId = Object.keys(this.ogCommonService.selectedClients)[0];
+ this.client = this.ogCommonService.selectedClients[clientId];
+ this.execution.clients = clientId;
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.constants = data.constants;
+ }
+ );
+ this.loadRepositories();
+ this.loadImages();
+ } else {
+ // TODO - dar error?
+ this.ogSweetAlert.error(this.translate.instant('opengnsys_error'), this.translate.instant('not_clients_selected'));
+ this.router.navigate(['app.ous']);
+ }
+ }
+
+
+ sendCommand() {
+ if (!this.selectedPartition) {
+ this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('you_must_select_partition')});
+ } else {
+ const disk = this.client.partitions[this.selectedPartition].numDisk;
+ const partition = this.client.partitions[this.selectedPartition].numPartition;
+ // Al crear la imagen, le asociamos un perfil software
+ // @ts-ignore
+ this.execution.script = this.constants.commands.SOFTWARE_INVENTORY + ' ' + disk + ' ' + partition + '\n';
+ this.execution.script += this.constants.commands.CREATE_IMAGE + ' ' + disk + ' ' + partition + ' ' + this.command.canonicalName + ' REPO ';
+ // @ts-ignore
+ this.execution.script = this.execution.script.replace(/\"/g, '\\"').replace(/\$/g, '\\\$');
+
+ let image: Image = this.command.image;
+ let newImage = false;
+
+ let result = true;
+ // Crear la imagen si no existe
+ if (!image) {
+ newImage = true;
+ // Comprobar que exista el repositorio, sino no podemos crear la nueva imagen
+ if (!this.repositories) {
+ result = false;
+ this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('no_repository_exist')});
+ } else {
+ // Usar el repositorio por defecto
+ const repository = this.repositories[0];
+ image = new Image();
+ image.canonicalName = this.command.canonicalName;
+ image.description = this.translate.instant('image_created_automatically');
+ image.repository = repository;
+ }
+ }
+
+ // Asignar a la imagen los atributos del sistema operativo elegido
+ image.client = this.client;
+
+ // Si no hubo ningun error se guardan todas las pgms
+ if (result === true) {
+ const promises = [];
+ if (newImage === true) {
+ promises.push(this.imageService.create(image));
+ } else {
+ const imageCopy = Object.assign({}, image);
+ delete imageCopy.id;
+ delete imageCopy.softwareProfile;
+ promises.push(this.imageService.update(imageCopy));
+ }
+ this.execution.type = 'CREATE_IMAGE';
+ promises.push(this.commandService.execute(this.execution));
+ forkJoin(promises).subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_executed')});
+ this.router.navigate(['app.ous']);
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+ }
+ }
+
+ setCanonicalName() {
+ if (this.command.image !== null) {
+ this.command.canonicalName = this.command.image.canonicalName;
+ } else {
+ this.command.canonicalName = '';
+ }
+ }
+
+ private loadImages() {
+ this.imageService.list().subscribe(
+ (response) => {
+ this.images = response;
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+ private loadRepositories() {
+ this.repositoryService.list().subscribe(
+ (response) => {
+ this.repositories = response;
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+
+ isClonable(partition) {
+ let clonable = false;
+ let index = 0;
+ const code = partition.partitionCode;
+
+ if (partition.numPartition !== 0) {
+ // Buscar el codigo entre las constantes
+ while (index < this.constants.partitiontable.length && !clonable) {
+ // para cada tabla de particiones, buscamos el codigo de la particion
+ const elements = this.constants.partitiontable[index].partitions.filter(function(part) {
+ return (part.id === partition.partitionCode.padStart(2, '0'));
+ }
+ );
+ clonable = (elements.length > 0 && elements[0].clonable === true);
+ index++;
+ }
+ }
+
+ return clonable;
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.html
new file mode 100644
index 00000000..5d09b0aa
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.html
@@ -0,0 +1,62 @@
+<section class="content-header">
+ <h1 translate="delete_cache_image">
+ </h1>
+ <ol class="breadcrumb">
+ <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i>{{'dashboard'|translate}}</a></li>
+ <li><a [routerLink]="'/app/ous'"><i class="fa fa-th"></i>{{'ous'|translate}}</a></li>
+ <li class="active" translate="delete_cache_image"></li>
+ </ol>
+</section>
+<section fixed-toolboxbar class="toolboxbar">
+ <div>
+ <div class="col-md-12">
+ <div class="box-tools pull-right">
+ <button class="btn btn-primary" translate="execute" (click)="sendCommand()"></button>
+ </div>
+ </div>
+ </div>
+</section>
+<section style="padding: 0 30px;">
+ <h3 translate="selected_clients"></h3>
+ <app-og-selected-clients></app-og-selected-clients>
+</section>
+<!-- Main content -->
+<section class="content">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="box box-primary">
+ <div class="box-header with-border">
+ </div>
+ <div class="box-body">
+ <div>
+ <table class="table">
+ <thead>
+ <tr>
+ <th translate="select">
+ </th>
+ <th translate="type">
+ </th>
+ <th translate="name">
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let image of cacheImages" >
+ <td>
+ <input icheck type="checkbox" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="image.selected" />
+ </td>
+ <td>
+ {{image.type}}
+ </td>
+ <td>
+ {{image.name}}
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</section>
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.scss
new file mode 100644
index 00000000..08b1082b
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.scss
@@ -0,0 +1,3 @@
+app-execute-command {
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.ts
new file mode 100644
index 00000000..efc14d6d
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.ts
@@ -0,0 +1,120 @@
+import {Component, OnInit} from '@angular/core';
+
+import {ToasterService} from '../../../service/toaster.service';
+import {ActivatedRoute, Router} from '@angular/router';
+import {TranslateService} from '@ngx-translate/core';
+import {OgCommonService} from '../../../service/og-common.service';
+import {OgSweetAlertService} from '../../../service/og-sweet-alert.service';
+import {AuthModule} from 'globunet-angular/core';
+import {User} from '../../../model/user';
+import {OGCommandsService} from '../../../service/og-commands.service';
+import {CommandService} from '../../../api/command.service';
+import {Image} from '../../../model/image';
+import {Command, Excecution} from '../../../model/command';
+import {Client} from '../../../model/client';
+import {Repository} from '../../../model/repository';
+import {RepositoryService} from '../../../api/repository.service';
+import {ImageService} from '../../../api/image.service';
+
+@Component({
+ selector: 'app-delete-cache-image-command',
+ templateUrl: './delete-cache-image-command.component.html',
+ styleUrls: [ './delete-cache-image-command.component.scss' ]
+})
+export class DeleteCacheImageCommandComponent implements OnInit {
+ private readonly user: User;
+ private constants: any;
+ public repositories: Repository[];
+ public execution = new Excecution();
+ public commands: Command[] = [];
+ public client: Client;
+ public cacheImages = [];
+ public command = {canonicalName: '', image: new Image()};
+
+
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(public ogCommandsService: OGCommandsService,
+ private authModule: AuthModule,
+ private router: Router,
+ private activatedRoute: ActivatedRoute,
+ private ogCommonService: OgCommonService,
+ private commandService: CommandService,
+ private imageService: ImageService,
+ private repositoryService: RepositoryService,
+ private ogSweetAlert: OgSweetAlertService,
+ private toaster: ToasterService,
+ private translate: TranslateService) {
+ this.user = this.authModule.getLoggedUser();
+ }
+
+
+
+
+ ngOnInit() {
+ if (this.user && this.ogCommonService.selectedClients) {
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.constants = data.constants;
+ }
+ );
+ const clientIds = Object.keys(this.ogCommonService.selectedClients);
+ this.execution.clients = clientIds.join(',');
+ // Capturar para todos los clientes todas las imágenes de cache
+ this.cacheImages = [];
+ for (let index = 0; index < clientIds.length; index++) {
+ const client = this.ogCommonService.selectedClients[clientIds[index]];
+ const diskConfigs = this.ogCommonService.getDisksConfigFromPartitions(client.partitions);
+ for (let dc = 0; dc < diskConfigs.length; dc++) {
+ const diskConfig = diskConfigs[dc];
+ for (let p = 0; p < diskConfig.partitions.length; p++) {
+ const partition = diskConfig.partitions[p];
+ if (partition.partitionCode === 'ca') {
+ // Solo cogemos las imagenes .img, no los .sum
+ for (let f = 0; f < partition.cacheContent.files.length; f++) {
+ const file = partition.cacheContent.files[f];
+ // Si no es un .sum
+ if (!file.name.match('.sum')) {
+ this.cacheImages.push(file);
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // TODO - dar error?
+ this.ogSweetAlert.error(this.translate.instant('opengnsys_error'), this.translate.instant('not_clients_selected'));
+ this.router.navigate(['app.ous']);
+ }
+ }
+
+
+ sendCommand() {
+ this.execution.script = '';
+ for (let f = 0; f < this.cacheImages.length; f++) {
+ if (this.cacheImages[f].selected === true) {
+ if (this.cacheImages[f].type !== 'D') {
+ this.execution.script += 'rm -rf $OGCAC/$OGIMG/' + this.cacheImages[f].name.trim() + '*';
+ } else {
+ this.execution.script += 'rm -rf $OGCAC/$OGIMG/' + this.cacheImages[f].name.trim();
+ }
+ this.execution.script += '\n';
+ }
+ }
+ this.execution.script += this.constants.commands.REFRESH_INFO + '\n';
+ this.execution.script = this.execution.script.replace(/\"/g, '\\"').replace(/\$/g, '\\\$');
+ this.execution.type = 'RUN_SCRIPT';
+
+ this.commandService.execute(this.execution).subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_executed')});
+ this.router.navigate(['/app/ous']);
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.html
new file mode 100644
index 00000000..7dc55c29
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.html
@@ -0,0 +1,146 @@
+<section class="content-header">
+ <h1 translate="deploy_image"></h1>
+ <ol class="breadcrumb">
+ <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li>
+ <li><a [routerLink]="'/app/ous'" ><i class="fa fa-th"></i> {{'ous'|translate}}</a></li>
+ <li class="active" translate="deploy_image"></li>
+ </ol>
+</section>
+<section style="padding: 0 30px;">
+ <h3 translate="selected_clients"></h3>
+ <app-og-selected-clients></app-og-selected-clients>
+</section>
+<section class="content padding-top-30" style="padding-top: 30px">
+ <div class="box box-default box-solid">
+ <div class="box-header with-border">
+ </div>
+ <!-- /.box-header -->
+ <div class="box-body">
+ <form role="form" name="Form">
+ <div class="row">
+ <div class="form-group col-md-3" >
+ <div class="checkbox clip-check check-primary checkbox-inline">
+ <input id="deployImageParameters" name="deployImage" icheck checkbox-class="iradio_square-blue" radio-class="iradio_square-blue" type="radio" class="selection-checkbox" value="true" [(ngModel)]="deployImage" (change)="updateDeployOptions()" />
+ </div>
+ <label for="deployImage">
+ <span translate="deploy_image_update_restore"></span>
+ </label>
+ </div>
+ <div class="form-group col-md-3">
+ <div class="checkbox clip-check check-primary checkbox-inline">
+ <input id="parameters" name="updateCache" icheck checkbox-class="iradio_square-blue" radio-class="iradio_square-blue" type="radio" class="selection-checkbox" value="false" [(ngModel)]="deployImage" (change)="updateDeployOptions()" />
+ </div>
+ <label for="updateCache">
+ <span translate="update_cache_only_download"></span>
+ </label>
+ </div>
+ </div>
+ <div class="row">
+ <div class="form-group col-md-4">
+ <div class="form-group" ng-class="{'has-error':Form.images.$dirty && Form.images.$invalid, 'has-success':Form.images.$valid}">
+ <label>
+ <span translate="images"></span>
+ </label>
+ <select (change)="setCanonicalName()" class="form-control" type="text" [(ngModel)]="image" name="images">
+ <option *ngFor="let image of images" [ngValue]="image">{{image.canonicalName}}</option>
+ </select>
+ </div>
+ </div>
+ <div class="form-group col-md-2">
+ <label for="disk" translate="disk">
+ </label>
+ <input name="disk" type="number" min="1" [(ngModel)]="disk" class="form-control">
+
+ </div>
+ <div class="form-group col-md-2">
+ <label for="partition" translate="partition">
+ </label>
+ <input name="partition" type="number" min="1" [(ngModel)]="partition" class="form-control">
+ </div>
+ <div class="form-group col-md-4">
+ <label for="deployMethod" translate="deploy_method">
+ </label>
+ <select class="form-control" name="deployMethod" [(ngModel)]="deployMethod">
+ <option *ngFor="let deployMethod of deployMethods" [value]="deployMethod">{{deployMethod}}</option>
+ </select>
+ </div>
+ </div>
+ <div *ngIf="deployMethod == 'MULTICAST' || deployMethod == 'MULTICAST-DIRECT'">
+ <div class="row">
+ <div class="form-group col-md-4">
+ <label for="port" translate="port">
+ </label>
+ <input class="form-control" type="text" name="port" [(ngModel)]="multicast.port"/>
+ </div>
+ <div class="form-group col-md-4">
+ <label for="address" translate="address">
+ </label>
+ <input class="form-control" type="text" name="address" [(ngModel)]="multicast.address"/>
+ </div>
+ <div class="form-group col-md-4">
+ <label for="multicastMode" translate="mode">
+ </label>
+ <input class="form-control" type="text" name="multicastMode" [(ngModel)]="multicast.mode"/>
+ </div>
+ </div>
+ <div class="row">
+ <div class="form-group col-md-4">
+ <label for="speed" translate="speed">
+ </label>
+ <input class="form-control" type="text" name="speed" [(ngModel)]="multicast.speed"/>
+ </div>
+ <div class="form-group col-md-4">
+ <label for="maxClients" translate="max_clients">
+ </label>
+ <input class="form-control" type="text" name="maxClients" [(ngModel)]="multicast.maxClients"/>
+ </div>
+ <div class="form-group col-md-4">
+ <label for="maxWaitTime" translate="max_wait_time">
+ </label>
+ <input class="form-control" type="text" name="maxWaitTime" [(ngModel)]="multicast.maxWaitTime"/>
+ </div>
+ </div>
+ </div>
+ <div class="row" *ngIf="deployMethod == 'TORRENT'">
+ <div class="form-group col-md-6">
+ <label for="torrentMode" translate="mode">
+ </label>
+ <input class="form-control" type="text" name="torrentMode" [(ngModel)]="torrent.mode"/>
+ </div>
+ <div class="form-group col-md-6">
+ <label for="seedTime" translate="seed_time">
+
+ </label>
+ <input class="form-control" type="text" name="seedTime" [(ngModel)]="torrent.seedTime"/>
+ </div>
+ </div>
+ </form>
+
+ </div>
+ <!-- /.box-body -->
+ <div class="box-footer">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="btn-group pull-left">
+ <button class="btn btn-primary"(click)="generateOgInstruction()"><span translate="generate_og_instruction"></span></button>
+ <button [class]="editInstructions == false ? 'btn btn-default':'btn btn-success'" *ngIf="ogCommandsService.ogInstructions != ''" (click)="editInstructions = !editInstructions"><span translate="{{editInstructions == false?'edit':'done'}}"></span></button>
+ </div>
+ <div class="btn-group pull-right">
+ <app-og-execute-command-options></app-og-execute-command-options>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-md-12">
+ <div class="box">
+ <div class="box-header"></div>
+ <div class="box-body" >
+ <div *ngIf="editInstructions == false" [innerHTML]="ogCommandsService.ogInstructions|ogCommands"></div>
+ <textarea *ngIf="editInstructions == true" class="og-instructions" [(ngModel)]="ogCommandsService.ogInstructions"></textarea>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</section>
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.scss
new file mode 100644
index 00000000..ccb34440
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.scss
@@ -0,0 +1,3 @@
+command {
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.ts
new file mode 100644
index 00000000..b8312964
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.ts
@@ -0,0 +1,137 @@
+import {Component, OnInit} from '@angular/core';
+
+import {ToasterService} from '../../../service/toaster.service';
+import {ActivatedRoute, Router} from '@angular/router';
+import {TranslateService} from '@ngx-translate/core';
+import {OgCommonService} from '../../../service/og-common.service';
+import {OgSweetAlertService} from '../../../service/og-sweet-alert.service';
+import {AuthModule} from 'globunet-angular/core';
+import {User} from '../../../model/user';
+import {ImageService} from '../../../api/image.service';
+import {OGCommandsService} from '../../../service/og-commands.service';
+
+@Component({
+ selector: 'app-deploy-image-command',
+ templateUrl: './deploy-image-command.component.html',
+ styleUrls: [ './deploy-image-command.component.scss' ]
+})
+export class DeployImageCommandComponent implements OnInit {
+ torrent = {
+ mode: 'peer',
+ seedTime: '60'
+ };
+ multicast = {
+ port: '9000',
+ address: '239.194.16.140',
+ mode: 'full-duplex',
+ speed: 90,
+ maxClients: 50,
+ maxWaitTime: 60
+ };
+ disk = 1;
+ partition = 1;
+
+ images = [];
+ deployMethods = [];
+ deployMethod = 'MULTICAST';
+ private deployImage: string;
+ private user: User;
+ private constants: any;
+ public image: any;
+ public editInstructions = false;
+
+
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(public ogCommandsService: OGCommandsService,
+ private authModule: AuthModule,
+ private router: Router,
+ private activatedRoute: ActivatedRoute,
+ private ogCommonService: OgCommonService,
+ private imageService: ImageService,
+ private ogSweetAlert: OgSweetAlertService,
+ private toaster: ToasterService,
+ private translate: TranslateService) {
+ this.user = this.authModule.getLoggedUser();
+ }
+
+
+ ngOnInit() {
+ this.deployImage = 'true';
+ this.updateDeployOptions();
+ if (this.user) {
+ // Comprobar la selección de clientes
+ if (this.ogCommonService.getSelectionSize() > 0) {
+ this.imageService.list().subscribe(
+ (response) => {
+ this.images = response;
+ },
+ (error) => {
+ this.images = [];
+
+ }
+ );
+
+ } else {
+ // TODO - dar error?
+ this.toaster.pop({type: 'error', body: this.translate.instant('not_clients_selected'), title: this.translate.instant('opengnsys_error')});
+ this.router.navigate(['app.ous']);
+ }
+ }
+ }
+
+ updateDeployOptions() {
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.constants = data.constants;
+ if (this.deployImage === 'true') {
+ this.deployMethods = this.constants.deployMethods.deployImage;
+ } else {
+ // Si es updateCache, se quitan las opciones de deploy direct
+ this.deployMethods = this.constants.deployMethods.updateCache;
+ }
+ }
+ );
+
+ }
+
+ /**/
+ generateOgInstruction() {
+ let script = '';
+ const disk = this.disk;
+ const partition = this.partition;
+ // Capturar ip del repositorio de la imagen elegida
+ let ip = '172.16.140.210';
+ let imgName = this.image.canonicalName;
+ let target = ' ' + disk + ' ' + partition;
+ let log = 'ogEcho log session "[0] $MSG_SCRIPTS_TASK_START ';
+
+ // Modo deploy
+ if (this.deployImage === 'true') {
+ script = 'deployImage ';
+ } else {
+ script = 'updateCache ';
+ ip = 'REPO';
+ imgName += '.img';
+ target = '';
+ }
+ script += ip + ' /' + imgName + target + ' ' + this.deployMethod;
+ log += script + '"\n';
+ script = log + script;
+
+ // Modo
+ let params = '';
+ if (this.deployMethod === 'MULTICAST' || this.deployMethod === 'MULTICAST-DIRECT') {
+ params = this.multicast.port + ':' + this.multicast.mode + ':' + this.multicast.address + ':' + this.multicast.speed + 'M:' + this.multicast.maxClients + ':' + this.multicast.maxWaitTime;
+ } else if (this.deployMethod === 'TORRENT') {
+ params = this.torrent.mode + ':' + this.torrent.seedTime;
+ }
+ script += ' ' + params;
+
+ this.ogCommandsService.ogInstructions = script;
+ }
+
+ setCanonicalName() {
+ //this.command.canonicalName = this.command.image.canonicalName;
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.html
new file mode 100644
index 00000000..37d7f8e2
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.html
@@ -0,0 +1,95 @@
+<section class="content-header">
+ <h1 translate="new_command">
+ </h1>
+ <ol class="breadcrumb">
+ <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li>
+ <li><a [routerLink]="'/app/commands'"><i class="fa fa-terminal"></i> {{'commands'|translate}}</a></li>
+ <li class="active" translate="command"></li>
+ </ol>
+</section>
+<section style="padding: 0 30px;">
+ <h3 translate="selected_clients"></h3>
+ <app-og-selected-clients></app-og-selected-clients>
+</section>
+<section fixed-toolboxbar class="toolboxbar">
+ <div>
+ <div class="col-md-12">
+ <app-og-execute-command-options></app-og-execute-command-options>
+ </div>
+ </div>
+</section>
+<!-- Main content -->
+<section class="content">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="box box-primary">
+ <div class="box-header with-border">
+ <div class="form-inline">
+ <div class="form-group" ng-class="{'has-error':Form.newCommand.$dirty && Form.newCommand.$invalid, 'has-success':Form.newCommand.$valid}">
+ <div class="checkbox clip-check check-primary checkbox-inline">
+ <input id="parameters" name="newCommand" icheck checkbox-class="iradio_square-blue" radio-class="iradio_square-blue" type="radio" class="selection-checkbox" value="true" [(ngModel)]="newCommand" />
+ </div>
+ <label for="newCommand">
+ <span translate="new_command"></span>
+ </label>
+ </div>
+ <div class="form-group" ng-class="{'has-error':Form.savedCommand.$dirty && Form.savedCommand.$invalid, 'has-success':Form.savedCommand.$valid}">
+ <div class="checkbox clip-check check-primary checkbox-inline">
+ <input id="parameters" name="savedCommand" icheck checkbox-class="iradio_square-blue" radio-class="iradio_square-blue" type="radio" class="selection-checkbox" value="false" [(ngModel)]="newCommand" />
+ </div>
+ <label for="savedCommand">
+ <span translate="saved_command"></span>
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="box-body">
+ <form role="form" name="Form" *ngIf="newCommand == 'true'">
+ <div class="form-group" ng-class="{'has-error':Form.script.$dirty && Form.script.$invalid, 'has-success':Form.script.$valid}">
+ <label for="script">
+ <span translate="script"></span>
+ <span *ngIf="required == 'true'" class="symbol required"></span>
+ </label>
+ <textarea class="form-control" class="og-instructions" type="text" required="true" [(ngModel)]="ogCommandsService.ogInstructions" name="script"></textarea>
+ </div>
+ </form>
+ <form role="form" name="Form" *ngIf="newCommand == 'false'">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="form-group">
+ <label translate="commands"></label>
+ <select class="form-control" name="command" [(ngModel)]="selectedCommand" (change)="updateSelectedCommand()">
+ <option *ngFor="let command of commands" [ngValue]="command">{{command.title}}</option>
+ </select>
+ </div>
+ <div class="form-group" *ngIf="selectedCommand.parameters == true">
+ <label translate="parameters"></label>
+ <p class="help-block"><span translate="detected_params"></span> <span style="font-weight: bold" ng-bind-html="selectedCommand.inputs.length"></span></p>
+ <div class="row">
+ <div class="col-md-2" *ngFor="let input of selectedCommand.inputs; let index = index">
+ <label for="param{{index}}">
+ <span translate="parameter"></span> {{index+1}}
+ </label>
+ <input type="text" name="param{{index}}" [value]="selectedCommand.inputs[index]" (change)="updateScript(index, $event)">
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-md-12">
+ <div class="box">
+ <div class="box-header"></div>
+ <div class="box-body" >
+ <div *ngIf="editInstructions == false" [innerHTML]="ogCommandsService.ogInstructions|ogCommands"></div>
+ <textarea *ngIf="editInstructions == true" class="og-instructions" [(ngModel)]="ogCommandsService.ogInstructions"></textarea>
+ </div>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+</section>
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.scss
new file mode 100644
index 00000000..08b1082b
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.scss
@@ -0,0 +1,3 @@
+app-execute-command {
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.ts
new file mode 100644
index 00000000..9560258a
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.ts
@@ -0,0 +1,142 @@
+import {Component, OnInit} from '@angular/core';
+
+import {ToasterService} from '../../../service/toaster.service';
+import {ActivatedRoute, Router} from '@angular/router';
+import {TranslateService} from '@ngx-translate/core';
+import {OgCommonService} from '../../../service/og-common.service';
+import {OgSweetAlertService} from '../../../service/og-sweet-alert.service';
+import {AuthModule} from 'globunet-angular/core';
+import {User} from '../../../model/user';
+import {OGCommandsService} from '../../../service/og-commands.service';
+import {CommandService} from '../../../api/command.service';
+import {CommandFormType} from '../../../form-type/command.form-type';
+import {Command} from '../../../model/command';
+
+@Component({
+ selector: 'app-execute-command',
+ templateUrl: './execute-command.component.html',
+ styleUrls: [ './execute-command.component.scss' ]
+})
+export class ExecuteCommandComponent implements OnInit {
+ execution = {script: '', clients: ''};
+ selectedCommand = {
+ inputs: [],
+ script: ''
+ };
+ newCommand = 'true';
+ private user: User;
+ private selectedClients = [];
+ private form = [];
+ private formType: CommandFormType;
+ public commands: Command[] = [];
+ editInstructions = false;
+
+
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(public ogCommandsService: OGCommandsService,
+ private authModule: AuthModule,
+ private router: Router,
+ private activatedRoute: ActivatedRoute,
+ private ogCommonService: OgCommonService,
+ private commandService: CommandService,
+ private ogSweetAlert: OgSweetAlertService,
+ private toaster: ToasterService,
+ private translate: TranslateService) {
+ this.user = this.authModule.getLoggedUser();
+ }
+
+
+
+
+
+
+ ngOnInit(): void {
+ this.selectedClients = this.ogCommonService.selectedClients;
+ if (this.user && this.selectedClients) {
+ this.loadFormOptions();
+ this.loadCommands();
+ } else {
+ // TODO - dar error?
+ this.ogSweetAlert.error(this.translate.instant('opengnsys_error'), this.translate.instant('not_clients_selected'));
+ this.router.navigate(['/app/ous']);
+ }
+ }
+
+ sendCommand() {
+ let result = true;
+
+ if (!this.execution.script) {
+ result = false;
+ this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('command_not_valid')});
+ } else if (!this.execution.clients) {
+ result = false;
+ this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('not_clients_selected')});
+ }
+ // Si no hubo ningun error
+ if (result === true) {
+ this.execution.script = this.execution.script.replace(/\"/g, '\\"').replace(/\$/g, '\\\$');
+ // Resetar las instrucciones del script opengnsys almacenadas.
+ this.ogCommandsService.ogInstructions = '';
+ this.commandService.execute(this.execution).subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: 'success', body: 'Successfully saved'});
+ this.router.navigate(['/app/ous']);
+ },
+ function(error) {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+ }
+
+ loadFormOptions() {
+ this.formType = new CommandFormType();
+ this.form = this.formType.getForm();
+ }
+
+ loadCommands() {
+ this.commandService.list().subscribe(
+ (result) => {
+ this.commands = result;
+ }
+ );
+ }
+
+
+ executeSelectedCommand() {
+ // Ejecuta el contenido de ogInstructions
+ this.ogCommandsService.execute('RUN_SCRIPT');
+ }
+
+ updateSelectedCommand() {
+ this.getParamsNumber(this.selectedCommand);
+ this.ogCommandsService.ogInstructions = this.selectedCommand.script;
+ }
+
+
+ updateScript(i, value) {
+ this.selectedCommand.inputs[i] = value.target.value;
+ let script = this.selectedCommand.script;
+ for (let index = 0; index < this.selectedCommand.inputs.length; index++) {
+ script = script.replace('@' + (index + 1), this.selectedCommand.inputs[index]);
+ }
+ this.ogCommandsService.ogInstructions = script;
+
+ }
+
+ getParamsNumber(command) {
+ const params = [];
+ if (command.parameters === true) {
+ const allparams = command.script.match(/@[1-9]+/g)||[];
+ for (let index = 0; index < allparams.length; index++) {
+ if (params.indexOf(allparams[index]) === -1) {
+ params.push(allparams[index]);
+ }
+ }
+ this.selectedCommand.inputs = params;
+ }
+ return params.length;
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.html
new file mode 100644
index 00000000..a14c8510
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.html
@@ -0,0 +1,96 @@
+<section class="content-header">
+ <h1 translate="create_image">
+ </h1>
+ <ol class="breadcrumb">
+ <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i>{{'dashboard'|translate}}</a></li>
+ <li><a [routerLink]="'/app/ous'"><i class="fa fa-th"></i>{{'ous'|translate}}</a></li>
+ <li class="active" translate="create_image"></li>
+ </ol>
+</section>
+<section fixed-toolboxbar class="toolboxbar">
+ <div>
+ <div class="col-md-12">
+ <div class="box-tools pull-right">
+ <button class="btn btn-primary" translate="execute" (click)="sendCommand()"></button>
+ </div>
+ </div>
+ </div>
+</section>
+<section style="padding: 0 30px;">
+ <h3 translate="selected_clients"></h3>
+ <app-og-selected-clients></app-og-selected-clients>
+</section>
+<!-- Main content -->
+<section class="content">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="box box-primary" *ngFor="let item of clientGroups | keyvalue">
+ <div class="box-header with-border">
+ </div>
+ <div class="box-body">
+ <div *ngFor="let client of item.value">
+ <div class="form-group">
+ <span translate="clients"></span>
+ <label>
+ {{client.name}}
+ </label>
+ </div>
+ <div>
+ <table class="table">
+ <thead>
+ <tr>
+ <th translate="select">
+ </th>
+ <th translate="disk">
+ </th>
+ <th translate="partition">
+ </th>
+ <th translate="type">
+ </th>
+ <th translate="filesystem">
+ </th>
+ <th translate="size">
+ </th>
+ <th translate="osname">
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <ng-container *ngFor="let partition of client.partitions">
+ <tr *ngIf="partition.numPartition !== 0 && partition.size > 0">
+ <td>
+ <input icheck type="checkbox" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" [(ngModel)]="partition.selected" />
+ </td>
+ <td>
+ {{partition.numDisk}}
+ </td>
+ <td>
+ {{partition.numPartition}}
+ </td>
+ <td>
+ <select [(ngModel)]="partition.partitionCode">
+ <option *ngFor="let type of getPartitionTypes(client.partitions)" [ngValue]="type.id">{{type.type}}</option>
+ </select>
+ </td>
+ <td>
+ <select [(ngModel)]="partition.filesystem">
+ <option [ngValue]="filesystem" *ngFor="let filesystem of constants.filesystems">{{filesystem}}</option>
+ </select>
+ </td>
+ <td>
+ {{ogCommonService.getUnits(partition.size*1024)}}
+ </td>
+ <td>
+ {{partition.osName}}
+ </td>
+ </tr>
+ </ng-container>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</section>
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.scss
new file mode 100644
index 00000000..ccb34440
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.scss
@@ -0,0 +1,3 @@
+command {
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.ts
new file mode 100644
index 00000000..62b733b8
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.ts
@@ -0,0 +1,150 @@
+import {Component, OnInit} from '@angular/core';
+
+import {ToasterService} from '../../../service/toaster.service';
+import {ActivatedRoute, Router} from '@angular/router';
+import {TranslateService} from '@ngx-translate/core';
+import {OgCommonService} from '../../../service/og-common.service';
+import {OgSweetAlertService} from '../../../service/og-sweet-alert.service';
+import {AuthModule} from 'globunet-angular/core';
+import {User} from '../../../model/user';
+import {OGCommandsService} from '../../../service/og-commands.service';
+import {Client, Partition} from '../../../model/client';
+import {CommandService} from '../../../api/command.service';
+import {forkJoin} from 'rxjs';
+
+@Component({
+ selector: 'app-format-command',
+ templateUrl: './format-command.component.html',
+ styleUrls: [ './format-command.component.scss' ]
+})
+export class FormatCommandComponent implements OnInit {
+ execution = {clients: '', script: '', type: ''};
+ command = {};
+ user: User;
+ clientGroups = {};
+ constants: any;
+
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(public ogCommandsService: OGCommandsService,
+ private authModule: AuthModule,
+ private router: Router,
+ private activatedRoute: ActivatedRoute,
+ public ogCommonService: OgCommonService,
+ private commandService: CommandService,
+ private ogSweetAlert: OgSweetAlertService,
+ private toaster: ToasterService,
+ private translate: TranslateService) {
+ this.user = this.authModule.getLoggedUser();
+ }
+
+
+ ngOnInit() {
+ if (this.user && this.ogCommonService.selectedClients) {
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.constants = data.constants;
+ }
+ );
+ const clientIds = Object.keys(this.ogCommonService.selectedClients);
+ // Recorrer todos los clientes y formar los grupos según el partitionCode de sus particiones, deben coincidir todos
+ for (let index = 0; index < clientIds.length; index++) {
+ // Generamos una clave usando disco-particion-code para comparar
+ const client = this.ogCommonService.selectedClients[clientIds[index]];
+ const key = this.getPartitionsCode(client.partitions);
+
+ if (!this.clientGroups[key]) {
+ this.clientGroups[key] = [];
+ }
+ this.clientGroups[key].push(client);
+ }
+ } else {
+ // TODO - dar error?
+ this.ogSweetAlert.error(this.translate.instant('opengnsys_error'), this.translate.instant('not_clients_selected'));
+ this.router.navigate(['/app/ous']);
+ }
+ }
+
+ getPartitionsCode(partitions) {
+ let key = '';
+ for (let p = 0; p < partitions.length; p++) {
+ // Además de calcular la clave, alteramos el partitionCode pasandolo a mayusculas y aplicando padding de "0" a la izquierda si es necesario
+ partitions[p].partitionCode = partitions[p].partitionCode.toUpperCase();
+ if (partitions[p].partitionCode.length === 1) {
+ partitions[p].partitionCode = '0' + partitions[p].partitionCode;
+ }
+ key += partitions[p].numDisk + partitions[p].numPartition + partitions[p].partitionCode;
+ }
+ return key;
+ }
+
+
+ sendCommand() {
+ // Comrobar qué particiones se han seleccionado de qué grupos
+ const executions = {};
+ const groups = Object.keys(this.clientGroups);
+ for (let g = 0; g < groups.length; g++) {
+ if (!executions[g]) {
+ executions[g] = {
+ clients: '',
+ script: ''
+ };
+ }
+ // Recorrer las particiones del primer cliente de la lista y ver si hay alguna seleccionada
+ const found = false;
+ // La partición 0 no se usa, solo indica las propiedades del disco
+ let index = 1;
+ const client = this.clientGroups[groups[g]][0];
+ for (let c = 0; c < this.clientGroups[groups[g]].length; c++) {
+ executions[g].clients += client.id + ',';
+ }
+ while (!found && index < client.partitions.length) {
+ const partition = client.partitions[index];
+ if (partition.selected === true) {
+ if(executions[g].script === '') {
+ executions[g].script = 'ogUnmountAll ' + partition.numDisk + '\n';
+ }
+ // Si la particion es cache
+ if (partition.partitionCode.toUpperCase() === 'CA') {
+ executions[g].script += 'ogFormatCache' + '\n';
+ } else {
+ executions[g].script += 'ogFormat ' + partition.numDisk + ' ' + partition.numPartition + ' ' + partition.filesystem + '\n';
+ }
+ }
+ index++;
+ }
+ }
+
+ // Creamos tantas promises como diferentes grupos de ejecución haya
+ const promises = [];
+ const len = Object.keys(executions).length;
+ for (let index = 0; index < len; index++) {
+ const execution = {
+ type: 'RUN_SCRIPT',
+ script: executions[index].script,
+ clients: executions[index].clients.substring(0, executions[index].clients.length - 1) // Quitar la ultima ","
+ };
+ promises.push(this.commandService.execute(execution));
+ }
+ forkJoin(promises).subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_executed')});
+ this.router.navigate(['/app/ous']);
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+
+ getPartitionTypes(partitions) {
+ let types = [];
+ const infoPart = partitions.filter((partition: Partition) => partition.numPartition === 0);
+ if (infoPart.length === 1) {
+ const partitionTable = this.ogCommonService.getPartitionTable(infoPart[0]);
+ types = partitionTable.partitions;
+ }
+ return types;
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.html
new file mode 100644
index 00000000..e8bcdbc5
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.html
@@ -0,0 +1,81 @@
+<section class="content-header">
+ <h1 translate="login_command">
+ </h1>
+ <ol class="breadcrumb">
+ <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i>{{'dashboard'|translate}}</a></li>
+ <li><a [routerLink]="'/app/ous'"><i class="fa fa-th"></i>{{'ous'|translate}}</a></li>
+ <li class="active" translate="login_command"></li>
+ </ol>
+</section>
+<section fixed-toolboxbar class="toolboxbar">
+ <div>
+ <div class="col-md-12">
+ <div class="box-tools pull-right">
+ <button class="btn btn-primary" translate="execute" (click)="sendCommand()"></button>
+ </div>
+ </div>
+ </div>
+</section>
+<section style="padding: 0 30px;">
+ <h3 translate="selected_clients"></h3>
+ <app-og-selected-clients></app-og-selected-clients>
+</section>
+<!-- Main content -->
+<section class="content">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="box box-primary">
+ <div class="box-header with-border">
+ </div>
+ <div class="box-body">
+ <form role="form" name="vm.Form">
+ <div *ngFor="let client of selectedClients">
+ <table class="table" *ngIf="client && client.id" >
+ <thead>
+ <tr>
+ <th colspan="5">
+ {{client.name}}
+ </th>
+ </tr>
+ <tr>
+ <th translate="select">
+ </th>
+ <th translate="disk">
+ </th>
+ <th translate="partition">
+ </th>
+ <th translate="filesystem">
+ </th>
+ <th translate="osname">
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <ng-container *ngFor="let partition of client.partitions">
+ <tr *ngIf="canLogin(partition)">
+ <td>
+ <input icheck type="radio" name="partition" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="selectedPartition" [value]="partition" />
+ </td>
+ <td>
+ {{partition.numDisk}}
+ </td>
+ <td>
+ {{partition.numPartition}}
+ </td>
+ <td>
+ {{partition.filesystem}}
+ </td>
+ <td>
+ {{partition.osName}}
+ </td>
+ </tr>
+ </ng-container>
+ </tbody>
+ </table>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+</section>
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.scss
new file mode 100644
index 00000000..ccb34440
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.scss
@@ -0,0 +1,3 @@
+command {
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.ts
new file mode 100644
index 00000000..af234984
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.ts
@@ -0,0 +1,80 @@
+import {Component, OnInit} from '@angular/core';
+
+import {ToasterService} from '../../../service/toaster.service';
+import {ActivatedRoute, Router} from '@angular/router';
+import {TranslateService} from '@ngx-translate/core';
+import {OgCommonService} from '../../../service/og-common.service';
+import {OgSweetAlertService} from '../../../service/og-sweet-alert.service';
+import {AuthModule} from 'globunet-angular/core';
+import {User} from '../../../model/user';
+import {ImageService} from '../../../api/image.service';
+import {OGCommandsService} from '../../../service/og-commands.service';
+import {Client} from '../../../model/client';
+import {CommandService} from '../../../api/command.service';
+
+@Component({
+ selector: 'app-login-command',
+ templateUrl: './login-command.component.html',
+ styleUrls: [ './login-command.component.scss' ]
+})
+export class LoginCommandComponent implements OnInit {
+ execution = {clients: '', script: '', type: ''};
+ command = {};
+ user: User;
+ selectedClients: Client[];
+ selectedPartition: any;
+ client: Client;
+
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(public ogCommandsService: OGCommandsService,
+ private authModule: AuthModule,
+ private router: Router,
+ private activatedRoute: ActivatedRoute,
+ private ogCommonService: OgCommonService,
+ private commandService: CommandService,
+ private ogSweetAlert: OgSweetAlertService,
+ private toaster: ToasterService,
+ private translate: TranslateService) {
+ this.user = this.authModule.getLoggedUser();
+ }
+
+
+
+ ngOnInit() {
+ this.selectedClients = this.ogCommonService.selectedClients;
+ if (this.user && this.selectedClients) {
+ this.execution.clients = Object.keys(this.selectedClients).join(',');
+ }
+ }
+
+
+ sendCommand() {
+ if (!this.selectedPartition) {
+ this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('you_must_select_partition')});
+ } else {
+ const disk = this.selectedPartition.numDisk;
+ const partition = this.selectedPartition.numPartition;
+
+ this.execution.script = 'bootOs ' + disk + ' ' + partition + ' &';
+ this.execution.script = this.execution.script.replace(/\"/g, '\\"').replace(/\$/g, '\\\$');
+ this.execution.type = 'RUN_SCRIPT';
+
+ this.commandService.execute(this.execution).subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_executed')});
+ this.router.navigate(['app.ous']);
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+ }
+
+
+ canLogin(partition) {
+ return partition.osName !== '' && partition.osName !== 'DATA';
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.html
new file mode 100644
index 00000000..fab8b8d7
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.html
@@ -0,0 +1,164 @@
+<section class="content-header">
+ <h1 translate="partition_format"></h1>
+ <ol class="breadcrumb">
+ <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li>
+ <li><a [routerLink]="'/app/ous'" ><i class="fa fa-th"></i> {{'ous'|translate}}</a></li>
+ <li class="active" translate="partition_format"></li>
+ </ol>
+</section>
+<section style="padding: 0 30px;">
+ <h3 translate="selected_clients"></h3>
+ <app-og-selected-clients></app-og-selected-clients>
+</section>
+<section class="content padding-top-30" style="padding-top: 30px">
+ <div class="box box-default box-solid">
+ <div class="box-header with-border">
+ <div class="row">
+ <div class="col-md-4">
+ <span translate="num_disk"></span>: <input name="number" type="number" step="1" min="1" [(ngModel)]="diskConfig.disk" >
+ </div>
+ <div class="col-md-4">
+ <span translate="part_table"></span>: <b>
+ <select name="partTableType" [(ngModel)]="diskConfig.parttable.type" (change)="checkPartitionTableType()">
+ <option *ngFor="let partitionTableTypes of partitionTableTypes">{{partitionTableTypes.type}}</option>
+ </select></b>
+ </div>
+ <div class="col-md-4">
+ <span translate="size"></span>: <b>{{getSizeInGB(diskConfig.size)}} GB ({{getSizeInGB(diskConfig.size*diskConfig.remaining/100)}} GB <span translate="free"></span>)</b>
+ </div>
+ </div>
+ <div class="box-tools pull-right">
+ <button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i>
+ </button>
+ </div>
+ <!-- /.box-tools -->
+ </div>
+ <!-- /.box-header -->
+ <div class="box-body">
+ <div class="row">
+ <div class="col-md-12">
+ <table col-resizable class="disk-partitions" [elements]="diskConfig.partitions" cr-update-property="usage" (onResize)="updatePartitionUsage($event)">
+ <tr>
+ <td *ngFor="let partition of diskConfig.partitions" [style]="sanitizer.bypassSecurityTrustStyle('width: '+ partition.usage + '%; background-color:' + getPartitionColor(partition))">
+ <span><span translate="{{partition.type}}"></span> ({{partition.usage}}%)</span>
+ <table *ngIf="partition.partitions && partition.partitions.length > 0" [elements]="partition.partitions" col-resizable class="disk-partitions" cr-update-property="usage" (onResize)="updateExtendedPartitions($event)" cr-force-refresh="refresh-extended-partitions">
+ <tr>
+ <td *ngFor="let extendedPartition of partition.partitions" [style]="sanitizer.bypassSecurityTrustStyle('width: '+extendedPartition.usage+'%; background-color: '+ getPartitionColor(extendedPartition))">
+ <span>{{extendedPartition.type}} ({{extendedPartition.usage}}%)</span>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-md-8">
+ <button translate="add" class="btn btn-primary" (click)="addPartition()"></button>
+ <table class="table table-condensed table-striped partitions">
+ <tbody>
+ <tr>
+ <th translate="partition"></th>
+ <th translate="part_type"></th>
+ <th translate="filesystem"></th>
+ <th><span translate="size"></span> (bytes)</th>
+ <th translate="usage"></th>
+ <th translate="format"></th>
+ <th translate="remove"></th>
+ </tr>
+ </tbody>
+ <tbody *ngFor="let partition of diskConfig.partitions; let index = index;" ng-class="{'extended-partition': partition.partitions.length > 0}">
+ <tr [ngClass]="index%2 == 0 ? 'odd' : 'even'" *ngIf="partition.partition != 0">
+ <td>{{partition.partition}} ({{getSizeInGB(partition.size)}}GB)</td>
+ <td>
+ <select name="partitionType" [disabled]="partTableTypeIsGPT() && index == 0 && isEFI(partition)" [(ngModel)]="partition.type" (change)="checkPartitionType(partition)">
+ <option *ngFor="let partitionType of diskConfig.parttable.partitions">{{partitionType.type}}</option>
+ </select>
+ </td>
+ <td>{{partition.filesystem}}</td>
+ <td>
+ <input step=".01" name="partitionSize" type="number" [(ngModel)]="partition.size" (change)="setPartitionUsage(diskConfig, partition)"/>
+ </td>
+ <td>
+ <input step=".01" name="partitionUsage" type="number" [(ngModel)]="partition.usage" (change)="updatePartitionUsage(partition)">
+ <span>%</span>
+ </td>
+ <td>
+ <div *ngIf="isEXTENDED(partition) != true" class="checkbox clip-check check-primary checkbox-inline" style="margin-top: 0">
+ <input name="format" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" value="true" [(ngModel)]="partition.format" />
+ </div>
+ </td>
+ <td>
+ <button *ngIf="!(partTableTypeIsGPT() && $index == 0 && isEFI(partition))" class="btn btn-danger btn-xs"><i class="fa fa-times" (click)="removePartition(partition)"></i></button>
+ </td>
+ <td *ngIf="isEXTENDED(partition) == true">
+ <button class="btn btn-primary btn-xs"><i class="fa fa-plus" (click)="addExtendedPartition(partition)"></i></button>
+ </td>
+ </tr>
+ <tr *ngFor="let extendedPartition of partition.partitions" class="extended" ng-class="{'odd': $index%2 == 0, 'even': $index%2 != 0}">
+ <td>{{extendedPartition.partition}}</td>
+ <td>
+ <select name="extendedPartitionType" [(ngModel)]="extendedPartition.type" (change)="checkPartitionType(extendedPartition)">
+ <option *ngFor="let partitionType of diskConfig.parttable.partitions">{{partitionType.type}}</option>
+ </select>
+ </td>
+ <td>{{extendedPartition.filesystem}}</td>
+ <td><input step=".01" name="extendedPartitonSize" type="number"[(ngModel)]="extendedPartition.size" (change)="updateExtendedPartitions(extendedPartition)"/></td>
+ <td>
+ <input step=".01" name="extendedPartitionUsage" type="number"[(ngModel)]="extendedPartition.usage" (change)="updateExtendedPartitionsUsage(extendedPartition)">
+ <span>%</span>
+ </td>
+ <td>
+ <div class="checkbox clip-check check-primary checkbox-inline" style="margin-top: 0">
+ <input name="format" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" value="true"[(ngModel)]="extendedPartition.format" />
+ </div>
+ </td>
+ <td>
+ <button class="btn btn-danger btn-xs"><i class="fa fa-times" (click)="removeExtendedPartition(extendedPartition)"></i></button>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <div class="col-md-4">
+ <!--flot dataset="diskConfig.diskChartData" options="diskConfig.diskChartOptions" height="200px"></flot-->
+ <div class="chart" >
+ <canvas baseChart
+ [data]="diskConfig.diskChartData"
+ [labels]="diskConfig.diskChartLabels"
+ [colors]="diskConfig.diskPieChartColors"
+ [chartType]="'doughnut'"
+ [options]="diskConfig.diskChartOptions">
+ </canvas>
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- /.box-body -->
+ <div class="box-footer">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="btn-group pull-left">
+ <button class="btn btn-primary"(click)="generateOgInstruction()"><span translate="generate_og_instruction"></span></button>
+ <button [class]="editInstructions == false ? 'btn btn-default':'btn btn-success'" *ngIf="ogCommandsService.ogInstructions != ''" (click)="editInstructions = !editInstructions"><span translate="{{editInstructions == false?'edit':'done'}}"></span></button>
+ </div>
+ <div class="btn-group pull-right">
+ <app-og-execute-command-options></app-og-execute-command-options>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-md-12">
+ <div class="box">
+ <div class="box-header"></div>
+ <div class="box-body" >
+ <div *ngIf="editInstructions == false" [innerHTML]="ogCommandsService.ogInstructions|ogCommands"></div>
+ <textarea *ngIf="editInstructions == true" class="og-instructions" [(ngModel)]="ogCommandsService.ogInstructions"></textarea>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</section>
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.scss
new file mode 100644
index 00000000..97d2231d
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.scss
@@ -0,0 +1,22 @@
+::ng-deep app-partition-format-command {
+ ::ng-deep table.disk-partitions {
+ min-height: 40px;
+ }
+ ::ng-deep table.disk-partitions td {
+ position: relative;
+ }
+ ::ng-deep span.resizer {
+ display: block;
+ position: absolute;
+ top: 0;
+ right: 0;
+ margin: 0;
+ background-color: black;
+ width: 2px;
+ height: 100%;
+ padding: 0 !important;
+ cursor: col-resize;
+ border: 1px solid transparent;
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.ts
new file mode 100644
index 00000000..8c75fa2e
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.ts
@@ -0,0 +1,618 @@
+import {Component, OnInit} from '@angular/core';
+
+import {ToasterService} from '../../../service/toaster.service';
+import {ActivatedRoute, Router} from '@angular/router';
+import {TranslateService} from '@ngx-translate/core';
+import {OgCommonService} from '../../../service/og-common.service';
+import {OgSweetAlertService} from '../../../service/og-sweet-alert.service';
+import {AuthModule} from 'globunet-angular/core';
+import {User} from '../../../model/user';
+import {OGCommandsService} from '../../../service/og-commands.service';
+import {CommandService} from '../../../api/command.service';
+import {DomSanitizer} from '@angular/platform-browser';
+import {ChartOptions} from 'chart.js';
+import {Client} from '../../../model/client';
+
+@Component({
+ selector: 'app-partition-format-command',
+ templateUrl: './partition-format-command.component.html',
+ styleUrls: [ './partition-format-command.component.scss' ]
+})
+export class PartitionFormatCommandComponent implements OnInit {
+ execution = {clients: '', script: '', type: ''};
+ command = {};
+ user: User;
+ constants: any;
+ diskConfig: any;
+ partitionTableTypes = ['MSDOS', 'GPT'];
+ partitionTypes = [];
+ editInstructions = false;
+
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(public ogCommandsService: OGCommandsService,
+ public sanitizer: DomSanitizer,
+ private authModule: AuthModule,
+ private router: Router,
+ private activatedRoute: ActivatedRoute,
+ public ogCommonService: OgCommonService,
+ private commandService: CommandService,
+ private ogSweetAlert: OgSweetAlertService,
+ private toaster: ToasterService,
+ private translate: TranslateService) {
+ this.user = this.authModule.getLoggedUser();
+ this.diskConfig = {};
+ this.ogCommonService.saveSelection();
+ }
+
+ ngOnInit() {
+ if (this.user) {
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.constants = data.constants;
+ // Comprobar la selección de clientes
+ if (this.ogCommonService.selectedClients) {
+
+ // Recorrer todos los clientes seleccionados y usar el tamaño del disco de menor tamaño
+ const clientsId = Object.keys(this.ogCommonService.selectedClients);
+ let minSize = 0;
+ // por defecto la tabla de particiones msdos
+ let parttable = this.ogCommonService.getPartitionTable({partitionCode: 1});
+ if (this.ogCommonService.selectedClients[clientsId[0]].partitions[0]) {
+ minSize = this.ogCommonService.selectedClients[clientsId[0]].partitions[0].size;
+ parttable = this.ogCommonService.getPartitionTable(this.ogCommonService.selectedClients[clientsId[0]].partitions[0]);
+ }
+
+ for (let c = 1; c < clientsId.length; c++) {
+ if (this.ogCommonService.selectedClients[clientsId[0]].partitions[0].size < minSize) {
+ minSize = this.ogCommonService.selectedClients[clientsId[0]].partitions[0].size;
+
+ }
+ }
+
+ this.diskConfig = {
+ disk: 1,
+ parttable: parttable,
+ size: minSize,
+ partitions: [
+ {
+ partition: 0,
+ type: 'free_space',
+ filesystem: '',
+ size: minSize,
+ usage: 100,
+ }
+ ]
+ };
+ // TODO - Revisar Usamos la tabla de particiones del cliente seleccionado
+ const client: Client = this.ogCommonService.selectedClients[clientsId[0]];
+ const clientPartitions = [];
+ client.partitions.forEach((partition) => {
+ if (partition.numPartition !== 0 && partition.filesystem !== 'EMPTY') {
+
+ // Obtener el tipo de partición según su code
+ if (partition.partitionCode.length === 1) {
+ partition.partitionCode = '0' + partition.partitionCode;
+ }
+ const partTypes = this.diskConfig.parttable.partitions.filter(p => p.id === partition.partitionCode.toUpperCase());
+ if (partTypes.length > 0) {
+ partition.type = partTypes[0].type;
+ }
+ clientPartitions.push(partition);
+ }
+ });
+ this.diskConfig.partitions = clientPartitions.concat((this.diskConfig.partitions));
+ this.reorderPartitions();
+
+ this.setChartData(this.diskConfig);
+ this.partitionTableTypes = this.constants.partitiontable;
+ } else {
+ // TODO - dar error?
+ this.ogSweetAlert.error(this.translate.instant('opengnsys_error'), this.translate.instant('not_clients_selected'));
+ this.router.navigate(['app/ous']);
+ }
+
+ }
+ );
+ }
+ }
+
+
+ partTableTypeIsGPT() {
+ return this.diskConfig.parttable.type === 'GPT';
+ }
+
+ partTableTypeIsMSDOS() {
+ return this.diskConfig.parttable.type === 'MSDOS';
+ }
+
+ partTableTypeIsLVM() {
+ return this.diskConfig.parttable.type === 'LVM';
+ }
+ partTableTypeIsZPOOL() {
+ return this.diskConfig.parttable.type === 'ZPOOL';
+ }
+
+ isEFI(partition) {
+ return partition.type === 'EFI';
+ }
+
+ isCACHE(partition) {
+ return partition.type === 'CACHE';
+ }
+
+ isEXTENDED(partition) {
+ return partition.type === 'EXTENDED';
+ }
+
+ isWINDOWS(partition) {
+ return partition.type === 'NTFS' || partition.type === 'WINDOWS';
+ }
+
+ isLINUX(partition) {
+ return typeof partition.type === 'string' && partition.type.includes('LINUX');
+ }
+
+ isLINUXSWAP(partition) {
+ return partition.type === 'LINUX-SWAP';
+ }
+
+ isDATA(partition) {
+ return partition.type === 'DATA';
+ }
+
+ isUNKNOWN(partition) {
+ return partition.type === 'UNKNOWN';
+ }
+
+ isFreeSpace(partition) {
+ return partition.type === 'free_space';
+ }
+
+
+ convertPartitionType(partition) {
+ if (this.partTableTypeIsMSDOS()) {
+ if (this.isWINDOWS(partition)) {
+ partition.type = 'NTFS';
+ } else if (this.isUNKNOWN(partition)) {
+ partition.type = 'NTFS';
+ }
+ } else if (this.partTableTypeIsGPT()) {
+ if (this.isWINDOWS(partition)) {
+ partition.type = 'WINDOWS';
+ } else if (this.isDATA(partition)) {
+ partition.type = 'UNKNOWN';
+ }
+ } else if (this.partTableTypeIsLVM()) {
+ partition.type = 'LVM-LV';
+ } else if (this.partTableTypeIsZPOOL()) {
+ partition.type = 'ZFS-VOL';
+ }
+ }
+
+ checkPartitionTableType() {
+ const self = this;
+ if (this.partTableTypeIsMSDOS()) {
+ if (this.diskConfig.partitions.length > 5) {
+ this.ogSweetAlert.info('opengnsys_info', 'En MS-DOS sólo puede haber 4 particiones primarias, se creará una extendida con el resto de particiones');
+ const tmpPartitions = [];
+ const extendedPartition = {
+ type: 'EXTENDED',
+ partitions: [],
+ size: 0,
+ usage: 0
+ };
+ const hasCache = (this.diskConfig.partitions.filter((partition) => partition.type === 'CACHE').length > 0);
+ // Si tiene cache se añaden 2 particiones, más la cache y el espacio libre
+ const numParts = hasCache ? 2 : 3;
+ this.diskConfig.partitions.forEach(function(partition, index) {
+ self.convertPartitionType(partition);
+ if (index < numParts || self.isFreeSpace(partition) || self.isCACHE(partition)) {
+ tmpPartitions.push(partition);
+ } else {
+ extendedPartition.partitions.push(partition);
+ extendedPartition.size += partition.size;
+ }
+ });
+ // Actualizar porcentajes de las particiones extendidas
+ for (let p = 0; p < extendedPartition.partitions.length; p++) {
+ self.setPartitionUsage(extendedPartition, extendedPartition.partitions[p]);
+ }
+ tmpPartitions.push(extendedPartition);
+ self.diskConfig.partitions = tmpPartitions;
+ self.updatePartitionUsage(this.diskConfig.partitions[0]);
+ } else {
+ self.diskConfig.partitions.forEach(function(partition, index) {
+ self.convertPartitionType(partition);
+ });
+ }
+
+ } else {
+ const tmpPartitions = [];
+ // Para particiones GPT se crea una particion EFI en primer lugar de 512M
+ if (this.partTableTypeIsGPT()) {
+ // Comprobar si existe ya una partición EFI al principio del disco, sino, crearla
+ if (!this.isEFI(this.diskConfig.partitions[0])) {
+ tmpPartitions.push({
+ type: 'EFI',
+ size: 512000,
+ usage: (512000 / this.diskConfig.size) * 100
+ });
+ }
+ }
+
+ this.diskConfig.partitions.forEach(function(partition) {
+ self.convertPartitionType(partition);
+ if (!self.isEXTENDED(partition)) {
+ tmpPartitions.push(partition);
+ } else {
+ partition.partitions.forEach(function(extPart) {
+ self.convertPartitionType(extPart);
+ tmpPartitions.push(extPart);
+ self.setPartitionUsage(this.diskConfig, extPart);
+ });
+ }
+ });
+ this.diskConfig.partitions = tmpPartitions;
+ this.updatePartitionUsage(this.diskConfig.partitions[0]);
+ }
+ }
+
+ addPartition() {
+ // Si el tipo de tabla de particiones es MSDOS, sólo se admiten 4 particiones
+ if (this.partTableTypeIsGPT() || (this.partTableTypeIsMSDOS() && this.diskConfig.partitions.length < 5)) {
+ this.diskConfig.partitions.push({
+ partition: (this.diskConfig.partitions.length),
+ type: this.partTableTypeIsGPT() ? 'WINDOWS' : 'NTFS',
+ filesystem: '',
+ size: 0,
+ usage: 5
+
+ });
+ this.updatePartitionUsage(this.diskConfig.partitions[this.diskConfig.partitions.length - 1]);
+ } else if (this.partTableTypeIsMSDOS()) {
+ this.ogSweetAlert.warning('opengnsys_warning', 'En MS-DOS sólo puede haber 4 particiones primarias, utilice alguna como extendida si necesita más particiones');
+ }
+ // Actualizar información
+ // setChartData(this.diskConfig);
+ }
+
+ addExtendedPartition(partition) {
+ partition.partitions.push({
+ partition: (partition.partitions.length + 1),
+ type: 'NTFS',
+ filesystem: '',
+ size: 0,
+ usage: 0
+
+ });
+ const extendedPartUsage = Math.round(100 / partition.partitions.length);
+ partition.partitions.forEach(function(extPart) {
+ extPart.usage = extendedPartUsage;
+ });
+ // Actualiza tamaños en funcion del porcentaje de uso
+ this.updateExtendedPartitions(partition);
+ }
+
+ updateExtendedPartitions(extPartition) {
+ const parentPartition = this.diskConfig.partitions.filter((partition) => partition.type === 'EXTENDED')[0];
+ const totalSize = parentPartition.size;
+ parentPartition.partitions.forEach( function(extPart, index) {
+ extPart.partition = (index + 1);
+ extPart.size = Math.round((extPart.usage || 0) * totalSize / 100);
+ });
+ }
+
+ updateExtendedPartitionsUsage(extPartition) {
+ const parentPartition = this.diskConfig.partitions.filter((partition) => partition.type === 'EXTENDED')[0];
+ const index = parentPartition.partitions.indexOf(extPartition);
+ let nextPart = null;
+ // si solo hay una partición el uso es siempre el 100%
+ if (parentPartition.partitions.length === 1) {
+ extPartition.usage = 100;
+ } else {
+ nextPart = null;
+ // el porcentaje que crezca la particion, se le resta a la siguiente o a la anterior si es la ultima
+ if (index === parentPartition.partitions.length - 1) {
+ nextPart = parentPartition.partitions[index - 1];
+ } else {
+ nextPart = parentPartition.partitions[index + 1];
+ }
+ let restPercent = 100;
+ parentPartition.partitions.forEach(function(extPart) {
+ restPercent -= (extPart.usage || 0); // Hay casos en los que se obtiene NaN
+ });
+ // Le quitamos el porcentaje a la particion contigua hasta que quede con un mínimo de 1
+ if (nextPart.usage > (restPercent * -1)) {
+ nextPart.usage += restPercent;
+ } else {
+ // restamos 1 al resto del porcentaje que será lo que ocupe la particion contigua
+ restPercent = Math.abs(restPercent) - (nextPart.usage - 1);
+ nextPart.usage = 1;
+
+ extPartition.usage -= restPercent;
+ }
+ }
+ this.updateExtendedPartitions(extPartition);
+ }
+
+ removeExtendedPartition(extPartition) {
+ const parentPartition = this.diskConfig.partitions.filter((partition) => partition.type === 'EXTENDED')[0];
+ const index = parentPartition.partitions.indexOf(extPartition);
+ if (index !== -1) {
+ parentPartition.partitions.splice(index, 1);
+ }
+ // Comprobamos el % que queda libre ahora
+ const freePercent = Math.round(extPartition.usage / parentPartition.partitions.length);
+ parentPartition.partitions.forEach(function(extPart) {
+ extPart.usage += freePercent;
+ extPart.size = Math.round(extPart.usage * parentPartition.size / 100);
+ });
+ }
+
+
+ reorderPartitions() {
+ const self = this;
+ const tmpPartitions = [];
+ let indexFreeSpace = -1;
+ let indexCache = -1;
+ this.diskConfig.partitions.forEach(function(partition, index) {
+ if (partition.type !== 'free_space' && !self.isCACHE(partition)) {
+ partition.partition = (tmpPartitions.length + 1);
+ tmpPartitions.push(partition);
+ } else if (self.isCACHE(partition)) {
+ indexCache = index;
+ } else if (partition.type === 'free_space') {
+ indexFreeSpace = index;
+ }
+ });
+ // Añadir el espacio libre y la cache
+ if (indexFreeSpace !== -1) {
+ this.diskConfig.partitions[indexFreeSpace].usage = this.calculateFreeSpace(this.diskConfig.partitions[indexFreeSpace]);
+ tmpPartitions.push(this.diskConfig.partitions[indexFreeSpace]);
+ }
+ if (indexCache !== -1) {
+ tmpPartitions.push(this.diskConfig.partitions[indexCache]);
+ }
+ this.diskConfig.partitions = tmpPartitions;
+ }
+
+ setChartData(diskConfig) {
+ const self = this;
+ const diskChartData = [];
+ const diskChartLabels = [];
+ const diskPieChartColors = [{
+ backgroundColor: []
+ }];
+ let usedSpace = 0;
+
+ diskConfig.partitions.forEach( function(partition) {
+ if (partition.size > 0) {
+ self.setPartitionUsage(diskConfig, partition);
+ if (partition.type === 'free_space') {
+ partition.usage = self.calculateFreeSpace(partition);
+ }
+ // El espacio libre solo se añade si es 0
+ if (partition.type !== 'free_space' || (partition.type === 'free_space' && partition.usage > 0)) {
+ diskChartData.push(partition.usage);
+ diskChartLabels.push([
+ self.translate.instant(partition.os || partition.filesystem || partition.type),
+ (partition.usage + '%')
+ ]);
+ diskPieChartColors[0].backgroundColor.push(self.getPartitionColor(partition));
+ }
+ if (partition.type !== 'free_space') {
+ usedSpace += partition.usage;
+ }
+ }
+ });
+
+ this.diskConfig.remaining = Math.round(100 * (100 - usedSpace)) / 100;
+
+ const diskChartOptions: ChartOptions = {
+ responsive: true,
+ legend: {
+ position: 'bottom'
+ },
+ plugins: {
+ datalabels: {
+ formatter: (value, ctx) => {
+ const label = ctx.chart.data.labels[ctx.dataIndex];
+ return label;
+ },
+ },
+ }
+ };
+
+ diskConfig.diskChartData = diskChartData;
+ diskConfig.diskChartOptions = diskChartOptions;
+ diskConfig.diskChartLabels = diskChartLabels;
+ diskConfig.diskPieChartColors = diskPieChartColors;
+ }
+
+ getPartitionColor(partition) {
+ let color = '#c5e72b';
+ // Para la partición de datos se usa un color específico
+ if (this.isDATA(partition)) {
+ color = 'rgb(237,194,64)';
+ } else if (this.isEFI(partition)) {
+ color = '#bfe4e5';
+ } else if (this.isWINDOWS(partition)) {
+ color = '#00c0ef';
+ } else if (this.isLINUXSWAP(partition)) {
+ color = '#545454';
+ } else if (this.isLINUX(partition)) {
+ color = '#605ca8';
+ } else if (this.isCACHE(partition)) {
+ color = '#FC5A5A';
+ } else if (this.isFreeSpace(partition)) {
+ color = '#bcbcbc';
+ }
+ return color;
+ }
+
+ /*
+ * Custom Label formatter
+ * ----------------------
+ */
+ labelFormatter(label, series) {
+ return '<div style="font-size:13px; text-align:center; padding:2px; color: #000; font-weight: 600;">'
+ + '<br>'
+ + series.usage + '%</div>';
+ }
+
+ getSizeInGB(size) {
+ size = size / (1024 * 1024);
+ return Math.round(size * 100) / 100;
+ }
+
+ setPartitionUsage(diskConfig, partition) {
+ partition.usage = Math.round(((partition.size * 100) / diskConfig.size) * 100) / 100;
+ }
+
+ checkPartitionType(partition) {
+ let ok = true;
+ if (this.isCACHE(partition)) {
+ // Comprobar si ya hay alguna partición como CACHE
+ if (this.diskConfig.partitions.filter((p) => p.type === 'CACHE').length > 1) {
+ this.ogSweetAlert.error('opengnsys_error', 'Solo debe haber una CACHE');
+ partition.type = 'NTFS';
+ ok = false;
+ }
+ } else if (this.isEXTENDED(partition)) {
+ // Comprobar si ya hay alguna partición como EXTENDIDA
+ if (this.diskConfig.partitions.filter((p) => p.type === 'EXTENDED').length > 1) {
+ this.ogSweetAlert.error('opengnsys_error', 'Solo debe haber una EXTENDIDA');
+ partition.type = 'NTFS';
+ ok = false;
+ } else {
+ partition.partitions = [
+ {
+ partition: 1,
+ type: 'NTFS',
+ filesystem: '',
+ size: partition.size,
+ usage: 100
+
+ }
+ ];
+ }
+ } else if (typeof partition.partitions !== 'undefined' && partition.partitions.length > 0) {
+ ok = false;
+ const self = this;
+ this.ogSweetAlert.question('opengnsys_question', 'Esta particion contiene otras partitiones!, si continua, dichas particiones serán eliminadas....',
+ function(yes) {
+ partition.partitions = [];
+ self.updatePartitionUsage(partition);
+ },
+ function(cancel) {
+ // Si contesta no se deja el tipo extendido
+ partition.type = 'EXTENDED';
+ }
+ );
+ }
+
+ if (ok) {
+ this.updatePartitionUsage(partition);
+ }
+ }
+
+ updatePartitionUsage(partition) {
+ const remaining = this.calculateFreeSpace(partition);
+ if (partition.usage > remaining) {
+ partition.usage = remaining;
+ }
+ partition.size = Math.round(this.diskConfig.size * partition.usage / 100);
+ this.setChartData(this.diskConfig);
+ this.reorderPartitions();
+ // Si es una partición extendida
+ if (typeof partition.partitions !== 'undefined' && partition.partitions.length > 0) {
+ this.updateExtendedPartitions(partition.partitions[0]);
+ }
+ }
+
+ calculateFreeSpace(asignedPartition) {
+ let usedSpace = 0;
+ this.diskConfig.partitions.forEach(function(partition, index) {
+ if (partition !== asignedPartition && partition.type !== 'free_space') {
+ usedSpace += partition.usage || 0;
+ }
+ });
+ return Math.round(100 * (100 - usedSpace)) / 100;
+ }
+
+ removePartition(partition) {
+ const index = this.diskConfig.partitions.indexOf(partition);
+ if (index !== -1) {
+ this.diskConfig.partitions.splice(index, 1);
+ }
+
+ this.setChartData(this.diskConfig);
+
+ }
+
+
+// var RC='@';
+// document.fdatosejecucion.atributos.value="scp="+escape(document.fdatos.codigo.value)+RC;
+
+
+ /**/
+ generateOgInstruction() {
+ const self = this;
+ let initPartitionTable = 'ogCreatePartitionTable ' + this.diskConfig.disk + ' ' + this.diskConfig.parttable.type + '\n';
+ initPartitionTable += 'ogEcho log session "[0] $MSG_HELP_ogCreatePartitions"\n';
+ initPartitionTable += 'ogEcho session "[10] $MSG_HELP_ogUnmountAll ' + this.diskConfig.disk + '"\n';
+ initPartitionTable += 'ogUnmountAll ' + this.diskConfig.disk + ' 2>/dev/null\n';
+ initPartitionTable += 'ogUnmountCache\n';
+ initPartitionTable += 'ogEcho session "[30] $MSG_HELP_ogUpdatePartitionTable ' + this.diskConfig.disk + '"\n';
+ initPartitionTable += 'ogDeletePartitionTable ' + this.diskConfig.disk + '\n';
+ initPartitionTable += 'ogUpdatePartitionTable ' + this.diskConfig.disk + '\n';
+
+ let createPartitions = 'ogEcho session "[60] $MSG_HELP_ogListPartitions ' + this.diskConfig.disk + '"\n';
+ createPartitions += 'ogExecAndLog command session ogListPartitions ' + this.diskConfig.disk + '\n';
+
+ let cacheInstruction = '';
+ let partitionList = '';
+ let formatInstructions = '';
+ this.diskConfig.partitions.forEach(function(partition, index) {
+ if (partition.type !== 'free_space') {
+ // La unica particion especial es la 4 que es cache, para el resto
+ if (!self.isCACHE(partition)) {
+ partitionList += ' ' + partition.type + ':' + partition.size;
+ if (self.isEXTENDED(partition)) {
+ for (let p = 0; p < partition.partitions.length; p++) {
+ partitionList += ' ' + partition.partitions[p].type + ':' + partition.partitions[p].size;
+ if (partition.partitions[p].format === true) {
+ formatInstructions += 'ogUnmount ' + self.diskConfig.disk + ' ' + (partition.partition + (partition.partitions[p].partition - 1)) + '\n';
+ formatInstructions += 'ogFormat ' + self.diskConfig.disk + ' ' + (partition.partition + (partition.partitions[p].partition - 1)) + '\n';
+ }
+ }
+ }
+ if (partition.format === true) {
+ formatInstructions += 'ogUnmount ' + self.diskConfig.disk + ' ' + partition.partition + '\n';
+ formatInstructions += 'ogFormat ' + self.diskConfig.disk + ' ' + partition.partition + '\n';
+ }
+ } else {
+ cacheInstruction = 'ogEcho session "[50] $MSG_HELP_ogCreateCache"\n';
+ cacheInstruction += 'initCache ' + self.diskConfig.disk + ' ' + partition.size + ' NOMOUNT &>/dev/null\n';
+
+ if (partition.format === true) {
+ formatInstructions += 'ogUnmountCache\n';
+ formatInstructions += 'ogFormatCache\n';
+ }
+ }
+ }
+ });
+
+ createPartitions += 'ogEcho session "[70] $MSG_HELP_ogCreatePartitions ' + partitionList + '"\n';
+ createPartitions += 'ogExecAndLog command ogCreatePartitions ' + this.diskConfig.disk + partitionList + '\n';
+ createPartitions += 'ogEcho session "[80] $MSG_HELP_ogSetPartitionActive ' + this.diskConfig.disk + ' 1"\n';
+ createPartitions += 'ogSetPartitionActive ' + this.diskConfig.disk + ' 1\n';
+ createPartitions += 'ogEcho log session "[100] $MSG_HELP_ogListPartitions ' + this.diskConfig.disk + '"\n';
+ createPartitions += 'ogUpdatePartitionTable ' + this.diskConfig.disk + '\n';
+ createPartitions += 'ms-sys /dev/sda | grep unknow && ms-sys /dev/sda\n';
+ createPartitions += 'ogExecAndLog command session log ogListPartitions ' + this.diskConfig.disk + '\n';
+
+ this.ogCommandsService.ogInstructions = initPartitionTable + cacheInstruction + createPartitions + formatInstructions;
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/common/directive/col-resizable.directive.ts b/admin/WebConsole3/frontend/src/app/pages/common/directive/col-resizable.directive.ts
new file mode 100644
index 00000000..7c32f406
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/common/directive/col-resizable.directive.ts
@@ -0,0 +1,81 @@
+import {Directive, DoCheck, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, Renderer2} from '@angular/core';
+
+
+class ResizeInfo {
+ width: number;
+ percent: number;
+}
+
+@Directive({
+ selector: '[col-resizable]'
+})
+export class ColResizableDirective implements OnInit, DoCheck {
+ private el: ElementRef;
+ private start: any;
+ private pressed: boolean;
+ private startX: number;
+ private startWidth: any;
+
+ @Input()
+ elements: any[];
+
+ @Output()
+ onResize = new EventEmitter<ResizeInfo>();
+ private elementProperty: string;
+
+
+ constructor(el: ElementRef, private renderer: Renderer2) {
+ this.el = el;
+
+ }
+
+ ngOnInit() {
+ this.elementProperty = this.el.nativeElement.getAttribute('cr-update-property') || '';
+ }
+ ngDoCheck(): void {
+ const table = this.el.nativeElement;
+ const trs = table.getElementsByTagName('tr');
+ let tds = null;
+
+ for (let i = 0; i < trs.length; i++) {
+ tds = trs[i].getElementsByTagName('td');
+ if (tds.length > 0) {
+ for (let n = 0; n < tds.length; n++) {
+
+ if (tds[n].getElementsByClassName('resizer').length === 0) {
+ const span = document.createElement('span');
+ span.classList.add('resizer');
+ tds[n].appendChild(span);
+ span.addEventListener('mousedown', (event) => {
+ this.start = event.target;
+ this.pressed = true;
+ this.startX = event.x;
+ this.startWidth = this.start.parentElement.offsetWidth;
+ this.initResizableColumns();
+ });
+ }
+ }
+ }
+ }
+
+ }
+
+ private initResizableColumns() {
+ this.renderer.listen('body', 'mousemove', (event) => {
+ if (this.pressed) {
+ const width = this.startWidth + (event.x - this.startX);
+ this.start.parentElement.style.width = width + 'px';
+ const element = this.elements[this.start.parentElement.cellIndex];
+ if (typeof element !== 'undefined' && this.elementProperty !== ''){
+ element[this.elementProperty] = ((width / this.el.nativeElement.offsetWidth) * 100);
+ }
+ this.onResize.emit(element);
+ }
+ })
+ this.renderer.listen('body', 'mouseup', (event) => {
+ if (this.pressed) {
+ this.pressed = false;
+ }
+ });
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-commands-options/og-commands-options.component.html b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-commands-options/og-commands-options.component.html
index 7f114997..c008d3a1 100644
--- a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-commands-options/og-commands-options.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-commands-options/og-commands-options.component.html
@@ -6,14 +6,14 @@
<li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)"(click)="ogCommandsService.execute('POWER_OFF')" translate="power_off"></a></li>
<li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)"(click)="ogCommandsService.execute('POWER_ON')" translate="power_on"></a></li>
<li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)"(click)="ogCommandsService.execute('REBOOT')" translate="reboot"></a></li>
- <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'app/commands/login'" translate="login_command"></a></li>
+ <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'/app/commands/login'" translate="login_command"></a></li>
<li role="presentation" class="divider"></li>
- <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'app/commands/execute'" translate="execute_command"></a></li>
- <li role="presentation" class="{{ogCommonService.getSelectionSize() != 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'app/commands/create_image'" translate="create_image"></a></li>
- <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)" [routerLink]="'app/commands/deploy_image'" translate="deploy_image"></a></li>
- <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)" [routerLink]="'app/commands/delete_cache_image'" translate="delete_cache_image"></a></li>
- <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'app/commands/partition_format'" translate="partition_format"></a></li>
- <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'app/commands/format'" translate="format"></a></li>
+ <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'/app/commands/execute'" translate="execute_command"></a></li>
+ <li role="presentation" class="{{ogCommonService.getSelectionSize() != 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'/app/commands/create_image'" translate="create_image"></a></li>
+ <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)" [routerLink]="'/app/commands/deploy_image'" translate="deploy_image"></a></li>
+ <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)" [routerLink]="'/app/commands/delete_cache_image'" translate="delete_cache_image"></a></li>
+ <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'/app/commands/partition_format'" translate="partition_format"></a></li>
+ <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'/app/commands/format'" translate="format"></a></li>
<li role="presentation" class="divider"></li>
<li role="presentation" class="{{ogCommonService.getSelectionSize() != 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)"(click)="ogCommandsService.execute('SOFTWARE_INVENTORY')" translate="software_inventary"></a></li>
<li role="presentation" class="{{ogCommonService.getSelectionSize() != 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)"(click)="ogCommandsService.execute('HARDWARE_INVENTORY')" translate="hardware_inventary"></a></li>
diff --git a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.html b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.html
index efaabd65..2bc015f9 100644
--- a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.html
@@ -1,3 +1,8 @@
-<p>
- og-execute-command-options works!
-</p>
+<div class="btn-group">
+ <button class="btn btn-default"(click)="ogCommandsService.execute('RUN_SCRIPT',{script: ogCommandsService.ogInstructions})">
+ <span translate="execute"></span>
+ </button>
+ <button class="btn btn-primary"(click)="ogCommandsService.execute('RUN_SCRIPT',{script: ogCommandsService.ogInstructions, save: true})">
+ <span translate="save"></span>
+ </button>
+</div>
diff --git a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.ts b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.ts
index 55da5e36..86ccbf53 100644
--- a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.ts
@@ -1,4 +1,5 @@
import { Component, OnInit } from '@angular/core';
+import {OGCommandsService} from '../../../../service/og-commands.service';
@Component({
selector: 'app-og-execute-command-options',
@@ -7,7 +8,7 @@ import { Component, OnInit } from '@angular/core';
})
export class OgExecuteCommandOptionsComponent implements OnInit {
- constructor() { }
+ constructor(public ogCommandsService: OGCommandsService) { }
ngOnInit() {
}
diff --git a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.html b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.html
index e87b931a..91d187ff 100644
--- a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.html
@@ -1,3 +1,21 @@
-<p>
- og-selected-clients works!
-</p>
+<div class="row">
+ <div *ngFor="let client of selectedClients | keyvalue" class="col-md-2 col-xs-6 padding-5">
+ <div class="info-box client" *ngIf="client.value && client.value.id">
+ <span style="position: absolute;">
+ <input icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox"
+ class="selection-checkbox" [(ngModel)]="client.value.selected"
+ (change)="ogCommonService.selectClient(client.value, client.value.parent)"/>
+ </span>
+ <span class="info-box-icon">
+ <i class="fa fa-desktop">
+ </i>
+ </span>
+ <div class="info-box-content">
+ <span class="info-box-text">{{client.value.name}}</span>
+ <span class="info-box-text">{{client.value.ip}}</span>
+ <span class="info-box-text">{{client.value.mac}}</span>
+ </div>
+ <!-- /.info-box-content -->
+ </div>
+ </div>
+</div>
diff --git a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.ts b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.ts
index 9c6f1c4e..a6c7a606 100644
--- a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.ts
@@ -1,4 +1,6 @@
import { Component, OnInit } from '@angular/core';
+import {OgCommonService} from '../../../../service/og-common.service';
+import {Client} from '../../../../model/client';
@Component({
selector: 'app-og-selected-clients',
@@ -6,10 +8,17 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./og-selected-clients.component.css']
})
export class OgSelectedClientsComponent implements OnInit {
+ public selectedClients: Client[];
- constructor() { }
+ constructor(public ogCommonService: OgCommonService) {
+ this.selectedClients = [];
+ }
ngOnInit() {
+ this.selectedClients = this.ogCommonService.selectedClients;
}
+ getClientInfo(c: Client) {
+ console.log(c);
+ }
}
diff --git a/admin/WebConsole3/frontend/src/app/pages/common/table-action/ng2-table-action.component.css b/admin/WebConsole3/frontend/src/app/pages/common/table-action/ng2-table-action.component.css
index 4e8eee70..975006ac 100644
--- a/admin/WebConsole3/frontend/src/app/pages/common/table-action/ng2-table-action.component.css
+++ b/admin/WebConsole3/frontend/src/app/pages/common/table-action/ng2-table-action.component.css
@@ -1,3 +1,3 @@
-ul.dropdown-menu {
- background-color: transparent;
-}
+::ng-deep ng2-smart-table ul.dropdown-menu {
+ background-color: transparent;
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/dashboard/dashboard.component.ts b/admin/WebConsole3/frontend/src/app/pages/dashboard/dashboard.component.ts
index 97d26ae1..ef11a47f 100644
--- a/admin/WebConsole3/frontend/src/app/pages/dashboard/dashboard.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/dashboard/dashboard.component.ts
@@ -87,11 +87,13 @@ export class DashboardComponent implements OnInit, OnDestroy {
this.ogCommonService.loadEngineConfig().subscribe(
(config) => {
this.timers = config.timers;
- if (this.timers.serverStatusInterval.object == null) {
+ if (this.timers.serverStatusInterval.object == null && this.timers.serverStatusInterval.tick > 0) {
this.updateStatus();
this.timers.serverStatusInterval.object = setInterval(() => {
this.updateStatus();
}, this.timers.serverStatusInterval.tick);
+ } else {
+ this.updateStatus();
}
},
(error) => {
diff --git a/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.html b/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.html
index 0ddd6b5c..60c60cd1 100644
--- a/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.html
@@ -11,7 +11,7 @@
<div>
<div class="col-md-12">
<div class="box-tools pull-right">
- <button class="btn btn-primary" translate="save" ng-click="vm.save(Form)"></button>
+ <button class="btn btn-primary" translate="save" (click)="save(Form)"></button>
</div>
</div>
</div>
@@ -21,13 +21,12 @@
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header with-border">
- <h3 ng-if="!vm.hardwareComponent.id" class="box-title" translate="new_hardware_component"></h3>
- <h3 ng-if="vm.hardwareComponent.id" class="box-title" translate="hardware_component"></h3>
+ <h3 *ngIf="!hardwareComponent.id" class="box-title" translate="new_hardware_component"></h3>
+ <h3 *ngIf="hardwareComponent.id" class="box-title" translate="hardware_component"></h3>
</div>
<div class="box-body">
- <form role="form" gbn-auto-form name="Form" form-options="vm.formOptions" form-model="vm.hardwareComponent">
+ <app-form-input [model]="hardwareComponent" [formType]="formType"></app-form-input>
- </form>
</div>
</div>
</div>
diff --git a/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.ts b/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.ts
index a7ef127f..4b4306af 100644
--- a/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.ts
@@ -1,17 +1,48 @@
-import { Component } from '@angular/core';
-
-import { HardwareComponentService } from 'src/app/api/hardware-component.service';
-import { HardwareComponent } from 'src/app/model/hardware-component';
-
-@Component({
- selector: 'app-hardware-component',
- templateUrl: './hardware-component.component.html',
- styleUrls: [ './hardware-component.component.scss' ]
-})
-export class HardwareComponentComponent {
- // this tells the tabs component which Pages
- // should be each tab's root Page
- constructor(public hardwareComponentService: HardwareComponentService) {
- }
-
-}
+import { Component } from '@angular/core';
+
+import { HardwareComponentService } from 'src/app/api/hardware-component.service';
+import { HardwareComponent } from 'src/app/model/hardware-component';
+import {Observable} from 'rxjs';
+import {ToasterService} from '../../service/toaster.service';
+import {TranslateService} from '@ngx-translate/core';
+import {Router} from '@angular/router';
+
+@Component({
+ selector: 'app-hardware-component',
+ templateUrl: './hardware-component.component.html',
+ styleUrls: [ './hardware-component.component.scss' ]
+})
+export class HardwareComponentComponent {
+ // this tells the tabs component which Pages
+ public hardwareComponent: HardwareComponent;
+ formType: any;
+ // should be each tab's root Page
+ constructor(public hardwareComponentService: HardwareComponentService, private toaster: ToasterService, private translate: TranslateService, private router: Router) {
+ this.hardwareComponent = new HardwareComponent();
+ this.formType = [{
+ field: 'description',
+ name: 'description',
+ label: 'description',
+ type: 'textarea'
+ }];
+ }
+
+ save() {
+ let request: Observable<HardwareComponent>;
+ if (this.hardwareComponent.id !== 0) {
+ request = this.hardwareComponentService.update(this.hardwareComponent);
+ } else {
+ request = this.hardwareComponentService.create(this.hardwareComponent);
+ }
+
+ request.subscribe(
+ (response) => {
+ this.toaster.pop({type: this.translate.instant('success'), title: this.translate.instant('success'), body: this.translate.instant('successfully_saved')});
+ this.router.navigate(['/app/hardware']);
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/profiles-group.component.html b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/hardware-profiles-group.component.html
index 365ceebe..d7a73e89 100644
--- a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/profiles-group.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/hardware-profiles-group.component.html
@@ -1,47 +1,47 @@
-<mk-box boxColor="warning" headerBorder="true" isCollapsable="true" [isRemovable]="false">
- <mk-box-header class="box-header with-border">
- <i class="fa fa-folder-open-o"></i>
- <h3 class="box-title">
- <div class="btn-group" *ngIf="!content.editing">
- <div mk-dropdown class="btn-group" [isWrapper]="false" >
- <mk-dropdown-toggle>
- <button #toggleElement type="button" class="btn btn-default dropdown-toggle">
- {{content.name}}
- <span class="fa fa-caret-down"></span>
- </button>
- </mk-dropdown-toggle>
- <mk-dropdown-menu>
- <li >
- <a role="menuitem" tabindex="-1" href="#" translate="add_group"></a>
- </li>
- <li >
- <a role="menuitem" tabindex="-1" href="#" translate="add_profile" [routerLink]="'/app/hardware/profile/create/' + content.id "></a>
- </li>
- <li class="divider"></li>
- <li>
- <a class="" href="javascript:void(0)" translate="edit" (click)="content.$$tmpName = content.name; content.editing = true"></a>
- </li>
- <li role="presentation" class="divider"></li>
- <li role="presentation" class="delete-option">
- <a class="" href="javascript:void(0)" translate="delete" (click)="deleteGroup(content.id)"></a>
- </li>
- </mk-dropdown-menu>
- </div>
- </div>
- <div *ngIf="content.editing" class="col-xs-6">
- <input type="text" class="form-control" [(ngModel)]="content.$$tmpName">
- <span class="input-group-btn">
- <button type="button" class="btn btn-default btn-flat" translate="done" (click)="changeGroupName(content)"></button>
- <button type="button" class="btn btn-info btn-flat" translate="cancel" (click)="content.editing = false"></button>
- </span>
- </div>
- </h3>
- <!-- /.box-tools -->
- </mk-box-header>
- <!-- /.box-header -->
- <mk-box-content class="box-body folders" style="display: block;">
- <app-profiles-group *ngFor="let content of content.groups" [content]="content">
- </app-profiles-group>
- <app-profiles-table *ngIf="content.profiles" [profiles]="content.profiles"></app-profiles-table>
- </mk-box-content>
-</mk-box>
+<mk-box boxColor="warning" headerBorder="true" isCollapsable="true" [isRemovable]="false">
+ <mk-box-header class="box-header with-border">
+ <i class="fa fa-folder-open-o"></i>
+ <h3 class="box-title">
+ <div class="btn-group" *ngIf="!content.editing">
+ <div mk-dropdown class="btn-group" [isWrapper]="false" >
+ <mk-dropdown-toggle>
+ <button #toggleElement type="button" class="btn btn-default dropdown-toggle">
+ {{content.name}}
+ <span class="fa fa-caret-down"></span>
+ </button>
+ </mk-dropdown-toggle>
+ <mk-dropdown-menu>
+ <li >
+ <a role="menuitem" tabindex="-1" href="#" translate="add_group"></a>
+ </li>
+ <li >
+ <a role="menuitem" tabindex="-1" href="#" translate="add_profile" [routerLink]="'/app/hardware/profile/create/' + content.id "></a>
+ </li>
+ <li class="divider"></li>
+ <li>
+ <a class="" href="javascript:void(0)" translate="edit" (click)="content.$$tmpName = content.name; content.editing = true"></a>
+ </li>
+ <li role="presentation" class="divider"></li>
+ <li role="presentation" class="delete-option">
+ <a class="" href="javascript:void(0)" translate="delete" (click)="deleteGroup(content.id)"></a>
+ </li>
+ </mk-dropdown-menu>
+ </div>
+ </div>
+ <div *ngIf="content.editing" class="col-xs-6">
+ <input type="text" class="form-control" [(ngModel)]="content.$$tmpName">
+ <span class="input-group-btn">
+ <button type="button" class="btn btn-default btn-flat" translate="done" (click)="changeGroupName(content)"></button>
+ <button type="button" class="btn btn-info btn-flat" translate="cancel" (click)="content.editing = false"></button>
+ </span>
+ </div>
+ </h3>
+ <!-- /.box-tools -->
+ </mk-box-header>
+ <!-- /.box-header -->
+ <mk-box-content class="box-body folders" style="display: block;">
+ <app-profiles-group *ngFor="let content of content.groups" [content]="content">
+ </app-profiles-group>
+ <app-profiles-table *ngIf="content.profiles" [profiles]="content.profiles"></app-profiles-table>
+ </mk-box-content>
+</mk-box>
diff --git a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/profiles-group.component.ts b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/hardware-profiles-group.component.ts
index f9dbd868..884bb680 100644
--- a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/profiles-group.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/hardware-profiles-group.component.ts
@@ -1,14 +1,14 @@
-import {ComponentMetadata} from 'codelyzer/angular/metadata';
-import {Component, Input} from '@angular/core';
-
-@Component({
- selector: 'app-profiles-group',
- templateUrl: 'profiles-group.component.html'
-})
-export class ProfilesGroupComponent {
- @Input() content;
-
- constructor() {
- console.log(this.content);
- }
-}
+import {ComponentMetadata} from 'codelyzer/angular/metadata';
+import {Component, Input} from '@angular/core';
+
+@Component({
+ selector: 'app-profiles-group',
+ templateUrl: 'hardware-profiles-group.component.html'
+})
+export class HardwareProfilesGroupComponent {
+ @Input() content;
+
+ constructor() {
+ console.log(this.content);
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/profiles-table.component.html b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/hardware-profiles-table.component.html
index 45f17240..70bd2fd1 100644
--- a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/profiles-table.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/hardware-profiles-table.component.html
@@ -1,61 +1,61 @@
-<table class="table table-hover">
- <tbody>
- <tr>
- <th translate="description"></th>
- <th translate="windowsboot"></th>
- <th translate="options"></th>
- </tr>
- <tr *ngFor="let profile of profiles; let index = index" class="{{(index%2 == 0)?'odd':'even'}}">
- <td>
- <span *ngIf="profile.$$editing">
- <input type="text" class="form-control" [(ngModel)]="profile.$$tmpDescription">
- </span>
- <span *ngIf="!profile.$$editing">
- {{profile.description}}
- </span>
- </td>
- <td>
- <span *ngIf="profile.$$editing">
- <select class="form-control"[(ngModel)]="profile.$$tmpWindowsboot">
- <option [value]="item" *ngFor="let item of windowsboots"> {{item}}</option>
- </select>
- </span>
- <span *ngIf="!profile.$$editing">
- {{profile.windowsboot}}
- </span>
- </td>
- <td class="right">
- <ng-container *ngIf="profile.$$editing">
- <div class="btn-group ">
- <button class="btn btn-primary " translate="ok" (click)="saveHardwareProfile(profile)"></button>
- <button class="btn btn-default " translate="cancel" (click)="profile.$$editing = false"></button>
- </div>
- </ng-container>
- <ng-container *ngIf="!profile.$$editing">
- <app-table-action [rowData]="profile" [options]="tableOptions" (edit)="editHardwareProfile($event)" (delete)="deleteHardwareProfile($event)"></app-table-action>
-<!--
- <div class="btn-group visible-md visible-lg hidden-sm hidden-xs">
- <button class="btn btn-default" translate="edit" (click)="editHardwareProfile(profile)"></button>
- <button class="btn btn-default" href="javascript:void(0)" translate="config" (click)="goToEditProfile(profile)"></button>
- <button class="btn btn-danger " translate="delete" (click)="deleteHardwareProfile(profile)"></button>
- </div>
- <div class="btn-group hidden-md hidden-lg">
- <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
- <i class="fa fa-gear"></i>
- <span class="caret"></span>
- <span class="sr-only">Toggle Dropdown</span>
- </button>
- <ul class="dropdown-menu" role="menu">
- <li class="btn-group-vertical">
- <button class="btn btn-default" translate="edit" (click)="editHardwareProfile(profile)"></button>
- <button class="btn btn-default" href="javascript:void(0)" translate="config" ui-sref="goToEditProfile(profile)"></button>
- <button class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteHardwareProfile(profile)"></button>
- </li>
- </ul>
- </div>
--->
- </ng-container>
- </td>
- </tr>
- </tbody>
- </table>
+<table class="table table-hover">
+ <tbody>
+ <tr>
+ <th translate="description"></th>
+ <th translate="windowsboot"></th>
+ <th translate="options"></th>
+ </tr>
+ <tr *ngFor="let profile of profiles; let index = index" class="{{(index%2 == 0)?'odd':'even'}}">
+ <td>
+ <span *ngIf="profile.$$editing">
+ <input type="text" class="form-control" [(ngModel)]="profile.$$tmpDescription">
+ </span>
+ <span *ngIf="!profile.$$editing">
+ {{profile.description}}
+ </span>
+ </td>
+ <td>
+ <span *ngIf="profile.$$editing">
+ <select class="form-control"[(ngModel)]="profile.$$tmpWindowsboot">
+ <option [value]="item" *ngFor="let item of windowsboots"> {{item}}</option>
+ </select>
+ </span>
+ <span *ngIf="!profile.$$editing">
+ {{profile.windowsboot}}
+ </span>
+ </td>
+ <td class="right">
+ <ng-container *ngIf="profile.$$editing">
+ <div class="btn-group ">
+ <button class="btn btn-primary " translate="ok" (click)="saveHardwareProfile(profile)"></button>
+ <button class="btn btn-default " translate="cancel" (click)="profile.$$editing = false"></button>
+ </div>
+ </ng-container>
+ <ng-container *ngIf="!profile.$$editing">
+ <app-table-action [rowData]="profile" [options]="tableOptions" (edit)="editHardwareProfile($event)" (delete)="deleteHardwareProfile($event)"></app-table-action>
+<!--
+ <div class="btn-group visible-md visible-lg hidden-sm hidden-xs">
+ <button class="btn btn-default" translate="edit" (click)="editHardwareProfile(profile)"></button>
+ <button class="btn btn-default" href="javascript:void(0)" translate="config" (click)="goToEditProfile(profile)"></button>
+ <button class="btn btn-danger " translate="delete" (click)="deleteHardwareProfile(profile)"></button>
+ </div>
+ <div class="btn-group hidden-md hidden-lg">
+ <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
+ <i class="fa fa-gear"></i>
+ <span class="caret"></span>
+ <span class="sr-only">Toggle Dropdown</span>
+ </button>
+ <ul class="dropdown-menu" role="menu">
+ <li class="btn-group-vertical">
+ <button class="btn btn-default" translate="edit" (click)="editHardwareProfile(profile)"></button>
+ <button class="btn btn-default" href="javascript:void(0)" translate="config" ui-sref="goToEditProfile(profile)"></button>
+ <button class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteHardwareProfile(profile)"></button>
+ </li>
+ </ul>
+ </div>
+-->
+ </ng-container>
+ </td>
+ </tr>
+ </tbody>
+ </table>
diff --git a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/profiles-table.component.ts b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/hardware-profiles-table.component.ts
index c1a155ff..76db2008 100644
--- a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/profiles-table.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/hardware-profiles-table.component.ts
@@ -1,101 +1,101 @@
-import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
-import {HardwareProfile} from '../../../../model/hardware-profile';
-import {HardwareProfileService} from '../../../../api/hardware-profile.service';
-import {ToasterService} from '../../../../service/toaster.service';
-import {TranslateService} from '@ngx-translate/core';
-import {OgSweetAlertService} from '../../../../service/og-sweet-alert.service';
-import {Router} from '@angular/router';
-import {environment} from '../../../../../environments/environment';
-import {PartitionInfo} from '../../../../model/image';
-import {Ng2TableActionComponent} from '../../../common/table-action/ng2-table-action.component';
-
-@Component({
- selector: 'app-profiles-table',
- templateUrl: 'profiles-table.component.html'
-})
-export class ProfilesTableComponent implements OnInit {
- @Input() profiles;
- windowsboots: any;
- tableOptions: any;
-
- public constructor(private router: Router, private hardwareProfileService: HardwareProfileService, private ogSweetAlert: OgSweetAlertService, private toaster: ToasterService, private translate: TranslateService) {
-
- }
- ngOnInit(): void {
- this.windowsboots = environment.windowsboots;
- this.tableOptions = {
- override: false,
- buttons: [
- {
- action: 'edit'
- },
- {
- label: 'configure',
- handler: (profile) => this.goToEditProfile(profile),
- classes: 'btn-default'
- },
- {
- action: 'delete'
- }
- ]
- };
- }
-
- editHardwareProfile(hardwareProfile) {
- hardwareProfile.$$editing = true;
- hardwareProfile.$$tmpName = hardwareProfile.name;
- hardwareProfile.$$tmpDescription = hardwareProfile.description;
- hardwareProfile.$$tmpWindowsboot = hardwareProfile.windowsboot;
- }
-
- saveHardwareProfile(hardwareProfile) {
- hardwareProfile.$$editing = false;
- hardwareProfile.name = hardwareProfile.$$tmpName;
- hardwareProfile.description = hardwareProfile.$$tmpDescription;
- hardwareProfile.windowsboot = hardwareProfile.$$tmpWindowsboot;
- const hpCopy = Object.assign({}, hardwareProfile);
- // TODO - Llamar al servidor para guardar el cambio
- this.hardwareProfileService.update(hpCopy).subscribe(
- (response) => {
- this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_saved')});
- },
- (error) => {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- }
-
- deleteHardwareProfile(hardwareProfile) {
- const self = this;
-
- this.ogSweetAlert.question(this.translate.instant('sure_to_delete') + '?', this.translate.instant('action_cannot_be_undone'),
- function(result) {
- if (result.value === true) {
- self.hardwareProfileService.delete(hardwareProfile.id).subscribe(
- (response) => {
- self.toaster.pop({type: 'success', title: self.translate.instant('success'), body: self.translate.instant('successfully_deleted')});
- const index = self.profiles.indexOf(hardwareProfile);
- if (index !== -1) {
- self.profiles.splice(index, 1);
- }
- },
- (error) => {
- self.toaster.pop({type: 'error', title: self.translate.instant('error'), body: error});
- }
- );
- }
- }
- );
- }
-
- goToEditProfile(profile: HardwareProfile) {
- this.router.navigate(['/app/hardware/profile', profile.id]).then(
- success => {
- console.log(success);
- },
- error => {
- console.log(error);
- }
- );
- }
-}
+import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
+import {HardwareProfile} from '../../../../model/hardware-profile';
+import {HardwareProfileService} from '../../../../api/hardware-profile.service';
+import {ToasterService} from '../../../../service/toaster.service';
+import {TranslateService} from '@ngx-translate/core';
+import {OgSweetAlertService} from '../../../../service/og-sweet-alert.service';
+import {Router} from '@angular/router';
+import {environment} from '../../../../../environments/environment';
+import {PartitionInfo} from '../../../../model/image';
+import {Ng2TableActionComponent} from '../../../common/table-action/ng2-table-action.component';
+
+@Component({
+ selector: 'app-profiles-table',
+ templateUrl: 'hardware-profiles-table.component.html'
+})
+export class HardwareProfilesTableComponent implements OnInit {
+ @Input() profiles;
+ windowsboots: any;
+ tableOptions: any;
+
+ public constructor(private router: Router, private hardwareProfileService: HardwareProfileService, private ogSweetAlert: OgSweetAlertService, private toaster: ToasterService, private translate: TranslateService) {
+
+ }
+ ngOnInit(): void {
+ this.windowsboots = environment.windowsboots;
+ this.tableOptions = {
+ override: false,
+ buttons: [
+ {
+ action: 'edit'
+ },
+ {
+ label: 'configure',
+ handler: (profile) => this.goToEditProfile(profile),
+ classes: 'btn-default'
+ },
+ {
+ action: 'delete'
+ }
+ ]
+ };
+ }
+
+ editHardwareProfile(hardwareProfile) {
+ hardwareProfile.$$editing = true;
+ hardwareProfile.$$tmpName = hardwareProfile.name;
+ hardwareProfile.$$tmpDescription = hardwareProfile.description;
+ hardwareProfile.$$tmpWindowsboot = hardwareProfile.windowsboot;
+ }
+
+ saveHardwareProfile(hardwareProfile) {
+ hardwareProfile.$$editing = false;
+ hardwareProfile.name = hardwareProfile.$$tmpName;
+ hardwareProfile.description = hardwareProfile.$$tmpDescription;
+ hardwareProfile.windowsboot = hardwareProfile.$$tmpWindowsboot;
+ const hpCopy = Object.assign({}, hardwareProfile);
+ // TODO - Llamar al servidor para guardar el cambio
+ this.hardwareProfileService.update(hpCopy).subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_saved')});
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+
+ deleteHardwareProfile(hardwareProfile) {
+ const self = this;
+
+ this.ogSweetAlert.question(this.translate.instant('sure_to_delete') + '?', this.translate.instant('action_cannot_be_undone'),
+ function(result) {
+ if (result.value === true) {
+ self.hardwareProfileService.delete(hardwareProfile.id).subscribe(
+ (response) => {
+ self.toaster.pop({type: 'success', title: self.translate.instant('success'), body: self.translate.instant('successfully_deleted')});
+ const index = self.profiles.indexOf(hardwareProfile);
+ if (index !== -1) {
+ self.profiles.splice(index, 1);
+ }
+ },
+ (error) => {
+ self.toaster.pop({type: 'error', title: self.translate.instant('error'), body: error});
+ }
+ );
+ }
+ }
+ );
+ }
+
+ goToEditProfile(profile: HardwareProfile) {
+ this.router.navigate(['/app/hardware/profile', profile.id]).then(
+ success => {
+ console.log(success);
+ },
+ error => {
+ console.log(error);
+ }
+ );
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/image/edit/image-edit.component.ts b/admin/WebConsole3/frontend/src/app/pages/image/edit/image-edit.component.ts
index 1117762b..8bc33f44 100644
--- a/admin/WebConsole3/frontend/src/app/pages/image/edit/image-edit.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/image/edit/image-edit.component.ts
@@ -1,76 +1,100 @@
-import {Component, OnInit} from '@angular/core';
-
-import { ImageService } from 'src/app/api/image.service';
-import {Image, PartitionInfo} from 'src/app/model/image';
-
-import {ActivatedRoute, Router} from '@angular/router';
-import {ToasterService} from '../../../service/toaster.service';
-import {TranslateService} from '@ngx-translate/core';
-import {ImageFormType} from '../../../form-type/image.form-type';
-import {RepositoryService} from '../../../api/repository.service';
-
-@Component({
- selector: 'app-image',
- templateUrl: './image-edit.component.html',
- styleUrls: [ './image-edit.component.scss' ]
-})
-export class ImageEditComponent implements OnInit {
- image: Image;
- constants: any;
- private formType = new ImageFormType();
- public form: any;
-
- // this tells the tabs component which Pages
- // should be each tab's root Page
- constructor(private router: Router, private activatedRouter: ActivatedRoute, private imageService: ImageService, private repositoryService: RepositoryService, private translate: TranslateService, private toaster: ToasterService) {
- this.form = this.formType.getForm();
- }
-
- ngOnInit(): void {
- this.image = new Image();
- this.activatedRouter.paramMap.subscribe(
- (data: any) => {
- if (data.params.id) {
- this.imageService.read(data.params.id).subscribe(
- image => {
- this.image = image;
- },
- error => {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- }
- }
- );
- this.repositoryService.list().subscribe(
- data => {
- this.formType.getField(this.form, 'repository').options = {
- items: data,
- label: 'name',
- value: 'id'
- }
- }
- )
- }
-
- getImageFileSystem(image) {
- const result = '';
- if (typeof image.partitionInfo === 'string') {
- image.partitionInfo = JSON.parse(image.partitionInfo);
- } else if (!image.partitionInfo) {
- image.partitionInfo = {};
- }
- return image.partitionInfo.filesystem;
- }
-
-
- getPartitionType(partition) {
- // buscar la particion en el array global
- let result = this.constants.partitionTypes.filter(function (obj) {
- return obj.id === partition.id;
- });
- result = result[0];
- return result.type;
- }
-
-}
+import {Component, OnInit} from '@angular/core';
+
+import { ImageService } from 'src/app/api/image.service';
+import {Image, PartitionInfo} from 'src/app/model/image';
+
+import {ActivatedRoute, Router} from '@angular/router';
+import {ToasterService} from '../../../service/toaster.service';
+import {TranslateService} from '@ngx-translate/core';
+import {ImageFormType} from '../../../form-type/image.form-type';
+import {RepositoryService} from '../../../api/repository.service';
+import {Observable} from 'rxjs';
+
+@Component({
+ selector: 'app-image',
+ templateUrl: './image-edit.component.html',
+ styleUrls: [ './image-edit.component.scss' ]
+})
+export class ImageEditComponent implements OnInit {
+ image: Image;
+ constants: any;
+ private formType = new ImageFormType();
+ public form: any;
+
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(private router: Router, private activatedRouter: ActivatedRoute, private imageService: ImageService, private repositoryService: RepositoryService, private translate: TranslateService, private toaster: ToasterService) {
+ this.form = this.formType.getForm();
+ }
+
+ ngOnInit(): void {
+ this.image = new Image();
+ this.activatedRouter.paramMap.subscribe(
+ (data: any) => {
+ if (data.params.id) {
+ this.imageService.read(data.params.id).subscribe(
+ image => {
+ this.image = image;
+ if (typeof this.image.partitionInfo === 'string') {
+ this.image.partitionInfo = JSON.parse(this.image.partitionInfo);
+ } else if (!this.image.partitionInfo) {
+ this.image.partitionInfo = new PartitionInfo();
+ }
+ },
+ error => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+ }
+ );
+ this.repositoryService.list().subscribe(
+ data => {
+ this.formType.getField(this.form, 'repository').options = {
+ items: data,
+ label: 'name',
+ value: 'id'
+ };
+ }
+ );
+ }
+
+ getImageFileSystem(image) {
+ const result = '';
+ if (typeof image.partitionInfo === 'string') {
+ image.partitionInfo = JSON.parse(image.partitionInfo);
+ } else if (!image.partitionInfo) {
+ image.partitionInfo = {};
+ }
+ return image.partitionInfo.filesystem;
+ }
+
+
+ getPartitionType(partition) {
+ // buscar la particion en el array global
+ let result = this.constants.partitionTypes.filter(function (obj) {
+ return obj.id === partition.id;
+ });
+ result = result[0];
+ return result.type;
+ }
+
+ save() {
+ let request: Observable<any>;
+ if (this.image.id !== 0) {
+ request = this.imageService.update(this.image);
+ } else {
+ request = this.imageService.create(this.image);
+ }
+ request.subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: this.translate.instant('success'), body: this.translate.instant('successfully_saved')});
+ this.router.navigate(['/app/images']);
+
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/image/image.component.html b/admin/WebConsole3/frontend/src/app/pages/image/image.component.html
index 09ba6036..a5b700ac 100644
--- a/admin/WebConsole3/frontend/src/app/pages/image/image.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/image/image.component.html
@@ -9,16 +9,16 @@
</section>
<section fixed-toolboxbar class="toolboxbar">
<div class="row">
- <div class="col-10">
+ <div class="col-md-10 col-10">
<div class="input-group">
- <input type="text" name="q" class="form-control" placeholder="{{'search'|translate}}..." ng-model="vm.ngTableSearch.text">
+ <input type="text" name="q" class="form-control" placeholder="{{'search'|translate}}..." >
<span class="input-group-btn">
<button type="button" name="search" id="search-btn" class="btn btn-flat btn-default"><i class="fa fa-search"></i>
</button>
</span>
</div>
</div>
- <div class="col-2" style="margin-top: 5px;margin-bottom: 5px;">
+ <div class="col-md-2 col-2" style="margin-top: 5px;margin-bottom: 5px;">
<div class="box-tools">
<mk-dropdown class="btn-group" [isWrapper]="false" >
<mk-dropdown-toggle>
diff --git a/admin/WebConsole3/frontend/src/app/pages/image/image.component.ts b/admin/WebConsole3/frontend/src/app/pages/image/image.component.ts
index 821f63a4..76629163 100644
--- a/admin/WebConsole3/frontend/src/app/pages/image/image.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/image/image.component.ts
@@ -1,146 +1,146 @@
-import {Component, OnInit} from '@angular/core';
-
-import { ImageService } from 'src/app/api/image.service';
-import {Image, PartitionInfo} from 'src/app/model/image';
-import {OgCommonService} from '../../service/og-common.service';
-import {TranslateService} from '@ngx-translate/core';
-import {ToasterService} from '../../service/toaster.service';
-import {OgSweetAlertService} from '../../service/og-sweet-alert.service';
-import {Ng2TableActionComponent} from '../common/table-action/ng2-table-action.component';
-import {Router} from '@angular/router';
-
-@Component({
- selector: 'app-image',
- templateUrl: './image.component.html',
- styleUrls: [ './image.component.scss' ]
-})
-export class ImageComponent implements OnInit {
- images: Image[];
- constants: any;
- removeFile = false;
- tableSettings: any;
-
- // this tells the tabs component which Pages
- // should be each tab's root Page
- constructor(private router: Router, public imageService: ImageService, private ogCommonService: OgCommonService, private translate: TranslateService, private toaster: ToasterService, private ogSweetAlert: OgSweetAlertService) {
- this.ogCommonService.loadEngineConfig().subscribe(
- data => {
- this.constants = data.constants;
- }
- );
- }
-
- ngOnInit(): void {
- this.imageService.list().subscribe(
- data => {
- this.images = data;
- }
- );
- const self = this;
- this.tableSettings = {
- columns: {
- canonicalName: {
- title: this.translate.instant('canonical_name')
- },
- description: {
- title: this.translate.instant('description')
- },
- partitionInfo: {
- title: this.translate.instant('filesystem'),
- valuePrepareFunction: (cell, image) => {
- return this.getImageFileSystem(image);
- },
- filterFunction: (value: PartitionInfo, search: string) => {
- return (value.filesystem) ? value.filesystem.includes(search) : false;
- }
-
- },
- createdAt: {
- title: this.translate.instant('createdAt')
- },
- options: {
- title: 'Options',
- filter: false,
- sort: false,
- type: 'custom',
- renderComponent: Ng2TableActionComponent,
- onComponentInitFunction(instance) {
- instance.edit.subscribe(row => {
- self.router.navigate(['/app/images/edit/', row.id]);
- });
- instance.delete.subscribe(row => {
- self.deleteImage(row);
- });
- }
- },
- },
- actions: {
- position: 'right',
- add: false,
- edit: false,
- delete: false
- }
- };
- }
-
- getImageFileSystem(image) {
- const result = '';
- if (typeof image.partitionInfo === 'string') {
- image.partitionInfo = JSON.parse(image.partitionInfo);
- } else if (!image.partitionInfo) {
- image.partitionInfo = {};
- }
- return image.partitionInfo.filesystem;
- }
-
-
- getPartitionType(partition) {
- // buscar la particion en el array global
- let result = this.constants.partitionTypes.filter(function(obj) { return obj.id === partition.id; });
- result = result[0];
- return result.type;
- }
-
- deleteImage(image) {
- const self = this;
- this.removeFile = false;
- this.ogSweetAlert.swal({
- title: this.translate.instant('sure_to_delete') + '?',
- html: '<form style="text-align: center; padding-left: 10px">\
- <div class="form-group" translate="action_cannot_be_undone"></div>\
- <div class="form-group">\
- <div class="checkbox clip-check check-primary checkbox-inline">\
- <input id="removeFile" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" [(ngModel)]="removeFile" />\
- </div>\
- <label for="removeFile" translate="remove_file">\
- </label>?\
- </div>\
- </form>',
- type: 'warning',
- showCancelButton: true,
- confirmButtonColor: '#3c8dbc',
- confirmButtonText: this.translate.instant('yes_delete'),
- closeOnConfirm: true
- }).then(
- function(result) {
- if (result === true) {
- if (self.removeFile === true) {
- // TODO Borrar fichero físico...
- }
- this.imageService.delete(image.id).then(
- function(response) {
- this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_deleted')});
- // Buscar el elemento en el array y borrarlo
- const index = this.images.indexOf(image);
- if (index !== -1) {
- this.images.splice(index, 1);
- }
- },
- function(error) {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- }
- });
- }
-}
+import {Component, OnInit} from '@angular/core';
+
+import { ImageService } from 'src/app/api/image.service';
+import {Image, PartitionInfo} from 'src/app/model/image';
+import {OgCommonService} from '../../service/og-common.service';
+import {TranslateService} from '@ngx-translate/core';
+import {ToasterService} from '../../service/toaster.service';
+import {OgSweetAlertService} from '../../service/og-sweet-alert.service';
+import {Ng2TableActionComponent} from '../common/table-action/ng2-table-action.component';
+import {Router} from '@angular/router';
+
+@Component({
+ selector: 'app-image',
+ templateUrl: './image.component.html',
+ styleUrls: [ './image.component.scss' ]
+})
+export class ImageComponent implements OnInit {
+ images: Image[];
+ constants: any;
+ removeFile = false;
+ tableSettings: any;
+
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(private router: Router, public imageService: ImageService, private ogCommonService: OgCommonService, private translate: TranslateService, private toaster: ToasterService, private ogSweetAlert: OgSweetAlertService) {
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.constants = data.constants;
+ }
+ );
+ }
+
+ ngOnInit(): void {
+ this.imageService.list().subscribe(
+ data => {
+ this.images = data;
+ }
+ );
+ const self = this;
+ this.tableSettings = {
+ columns: {
+ canonicalName: {
+ title: this.translate.instant('canonical_name')
+ },
+ description: {
+ title: this.translate.instant('description')
+ },
+ partitionInfo: {
+ title: this.translate.instant('filesystem'),
+ valuePrepareFunction: (cell, image) => {
+ return this.getImageFileSystem(image);
+ },
+ filterFunction: (value: PartitionInfo, search: string) => {
+ return (value.filesystem) ? value.filesystem.includes(search) : false;
+ }
+
+ },
+ createdAt: {
+ title: this.translate.instant('createdAt')
+ },
+ options: {
+ title: 'Options',
+ filter: false,
+ sort: false,
+ type: 'custom',
+ renderComponent: Ng2TableActionComponent,
+ onComponentInitFunction(instance) {
+ instance.edit.subscribe(row => {
+ self.router.navigate(['/app/images/edit/', row.id]);
+ });
+ instance.delete.subscribe(row => {
+ self.deleteImage(row);
+ });
+ }
+ },
+ },
+ actions: {
+ position: 'right',
+ add: false,
+ edit: false,
+ delete: false
+ }
+ };
+ }
+
+ getImageFileSystem(image) {
+ const result = '';
+ if (typeof image.partitionInfo === 'string') {
+ image.partitionInfo = JSON.parse(image.partitionInfo);
+ } else if (!image.partitionInfo) {
+ image.partitionInfo = {};
+ }
+ return image.partitionInfo.filesystem;
+ }
+
+
+ getPartitionType(partition) {
+ // buscar la particion en el array global
+ let result = this.constants.partitionTypes.filter(function(obj) { return obj.id === partition.id; });
+ result = result[0];
+ return result.type;
+ }
+
+ deleteImage(image) {
+ const self = this;
+ this.removeFile = false;
+ this.ogSweetAlert.swal({
+ title: this.translate.instant('sure_to_delete') + '?',
+ html: '<form style="text-align: center; padding-left: 10px">\
+ <div class="form-group" translate="action_cannot_be_undone"></div>\
+ <div class="form-group">\
+ <div class="checkbox clip-check check-primary checkbox-inline">\
+ <input id="removeFile" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" [(ngModel)]="removeFile" />\
+ </div>\
+ <label for="removeFile" translate="remove_file">\
+ </label>?\
+ </div>\
+ </form>',
+ type: 'warning',
+ showCancelButton: true,
+ confirmButtonColor: '#3c8dbc',
+ confirmButtonText: this.translate.instant('yes_delete'),
+ closeOnConfirm: true
+ }).then(
+ function(result) {
+ if (result.value === true) {
+ if (self.removeFile === true) {
+ // TODO Borrar fichero físico...
+ }
+ self.imageService.delete(image.id).subscribe(
+ (response) => {
+ self.toaster.pop({type: 'success', title: 'success', body: self.translate.instant('successfully_deleted')});
+ // Buscar el elemento en el array y borrarlo
+ const index = self.images.indexOf(image);
+ if (index !== -1) {
+ self.images.splice(index, 1);
+ }
+ },
+ (error) => {
+ self.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+ });
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.html b/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.html
new file mode 100644
index 00000000..dd147bf3
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.html
@@ -0,0 +1,37 @@
+<section class="content-header">
+ <h1 translate="new_image">
+ </h1>
+ <ol class="breadcrumb">
+ <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li>
+ <li><a [routerLink]="'/app/images'"><i class="fa fa-cubes"></i> {{'images'|translate}}</a></li>
+ <li class="active" translate="edit_image"></li>
+ </ol>
+</section>
+<section fixed-toolboxbar class="toolboxbar">
+ <div>
+ <div class="col-md-12">
+ <div class="box-tools pull-right">
+ <button class="btn btn-primary" translate="save" (click)="save()"></button>
+ </div>
+ </div>
+ </div>
+</section>
+<!-- Main content -->
+<section class="content">
+ <div class="row">
+ <div class="col-md-4">
+ <div class="box box-primary">
+ <div class="box-header with-border">
+ </div>
+ <div class="box-body">
+ <form role="form" gbn-auto-form name="Form" form-model="image">
+ <app-form-input [model]="menu" [cols]="1" [formType]="form"></app-form-input>
+ </form>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-8">
+ <iframe class="e2e-trusted-url" [src]="sanitizer.bypassSecurityTrustResourceUrl(menu.publicUrl)" width="100%" height="500px"></iframe>
+ </div>
+ </div>
+</section>
diff --git a/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.scss b/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.scss
new file mode 100644
index 00000000..1382f194
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.scss
@@ -0,0 +1,3 @@
+image {
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.ts b/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.ts
new file mode 100644
index 00000000..c16bf372
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.ts
@@ -0,0 +1,78 @@
+import {Component, OnInit} from '@angular/core';
+
+
+import {ActivatedRoute, Router} from '@angular/router';
+import {ToasterService} from '../../../service/toaster.service';
+import {TranslateService} from '@ngx-translate/core';
+import {MenuFormType} from '../../../form-type/menu.form-type';
+import {RepositoryService} from '../../../api/repository.service';
+import {Observable} from 'rxjs';
+import {MenuService} from '../../../api/menu.service';
+import {Menu} from '../../../model/menu';
+import {OgCommonService} from '../../../service/og-common.service';
+import {DomSanitizer} from '@angular/platform-browser';
+
+@Component({
+ selector: 'app-menu',
+ templateUrl: './menu-edit.component.html',
+ styleUrls: [ './menu-edit.component.scss' ]
+})
+export class MenuEditComponent implements OnInit {
+ menu: Menu;
+ constants: any;
+ private formType = new MenuFormType();
+ public form: any;
+
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(public sanitizer: DomSanitizer, private router: Router, private activatedRouter: ActivatedRoute, private ogCommonService: OgCommonService, private menuService: MenuService, private translate: TranslateService, private toaster: ToasterService) {
+ this.form = this.formType.getForm();
+ }
+
+ ngOnInit(): void {
+ this.menu = new Menu();
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.formType.getField(this.form, 'resolution').options = {
+ items: data.constants.menus.resolutions,
+ label: 'text',
+ value: 'id'
+ };
+ }
+ );
+ this.activatedRouter.paramMap.subscribe(
+ (data: any) => {
+ if (data.params.id) {
+ this.menuService.read(data.params.id).subscribe(
+ menu => {
+ this.menu = menu;
+ },
+ error => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+ }
+ );
+ }
+
+
+ save() {
+ let request: Observable<any>;
+ if (this.menu.id !== 0) {
+ request = this.menuService.update(this.menu);
+ } else {
+ request = this.menuService.create(this.menu);
+ }
+ request.subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: this.translate.instant('success'), body: this.translate.instant('successfully_saved')});
+ this.router.navigate(['/app/menus']);
+
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.html b/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.html
index 93bab7ab..bc65667b 100644
--- a/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.html
@@ -1 +1,51 @@
-<div>Html template for class Menu</div> \ No newline at end of file
+<div ui-view>
+ <section class="content-header">
+ <h1 translate="menus">
+ </h1>
+ <ol class="breadcrumb">
+ <li><a [routerLink]="'app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li>
+ <li class="active" translate="menus"></li>
+ </ol>
+ </section>
+ <section fixed-toolboxbar class="toolboxbar">
+ <div >
+ <div class="col-md-12">
+ <div class="input-group">
+ <input type="text" name="q" class="form-control" placeholder="{{'search'|translate}}..." ng-model="vm.ngTableSearch.text">
+ <span class="input-group-btn">
+ <button type="button" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i>
+ </button>
+ </span>
+ </div>
+ </div>
+ <div class="col-md-12" style="margin-top: 5px;margin-bottom: 5px;">
+
+ <div class="box-tools pull-right">
+ <a [routerLink]="'/app/menus/create'" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
+ <span translate="new"></span>
+ </a>
+ </div>
+ </div>
+ </div>
+ </section>
+ <!-- Main content -->
+ <section class="content">
+ <div class="row">
+ <div class="col-md-12">
+ <!-- Info boxes -->
+ <div class="box box-primary">
+ <div class="box-header with-border">
+ <h3 class="box-title" translate="image_list"></h3>
+ </div>
+ <div class="box-body">
+ <ng2-smart-table [source]="menus" [settings]="tableSettings"></ng2-smart-table>
+ </div>
+ <div class="box-footer">
+ </div>
+ <!-- /.col -->
+ </div>
+ </div>
+ </div>
+ <!-- /.row -->
+ </section>
+</div>
diff --git a/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.ts b/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.ts
index a5cecb4e..2d803c86 100644
--- a/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.ts
@@ -1,17 +1,105 @@
-import { Component } from '@angular/core';
-
-import { MenuService } from 'src/app/api/menu.service';
-import { Menu } from 'src/app/model/menu';
-
-@Component({
- selector: 'menu',
- templateUrl: './menu.component.html',
- styleUrls: [ './menu.component.scss' ]
-})
-export class MenuComponent {
- // this tells the tabs component which Pages
- // should be each tab's root Page
- constructor(public menuService: MenuService) {
- }
-
-}
+import {Component, OnInit} from '@angular/core';
+
+import { MenuService } from 'src/app/api/menu.service';
+import { Menu } from 'src/app/model/menu';
+import {PartitionInfo} from '../../model/image';
+import {Ng2TableActionComponent} from '../common/table-action/ng2-table-action.component';
+import {TranslateService} from '@ngx-translate/core';
+import {Router} from '@angular/router';
+import {OgSweetAlertService} from '../../service/og-sweet-alert.service';
+import {ToasterService} from '../../service/toaster.service';
+
+@Component({
+ selector: 'app-menu',
+ templateUrl: './menu.component.html',
+ styleUrls: [ './menu.component.scss' ]
+})
+export class MenuComponent implements OnInit {
+ public menus: Menu[];
+ private tableSettings: any;
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(public menuService: MenuService, private router: Router, private ogSweetAlert: OgSweetAlertService, private toaster: ToasterService, private translate: TranslateService) {
+ }
+
+ ngOnInit(): void {
+ this.menuService.list().subscribe(
+ data => {
+ this.menus = data;
+ },
+ error => {
+
+ }
+ );
+ const self = this;
+ this.tableSettings = {
+ columns: {
+ title: {
+ title: this.translate.instant('title')
+ },
+ description: {
+ title: this.translate.instant('description')
+ },
+ comments: {
+ title: this.translate.instant('comments'),
+ },
+ resolution: {
+ title: this.translate.instant('resolution')
+ },
+ options: {
+ title: 'Options',
+ filter: false,
+ sort: false,
+ type: 'custom',
+ renderComponent: Ng2TableActionComponent,
+ onComponentInitFunction(instance) {
+ instance.edit.subscribe(row => {
+ self.router.navigate(['/app/menus/edit/', row.id]);
+ });
+ instance.delete.subscribe(row => {
+ self.deleteMenu(row);
+ });
+ }
+ },
+ },
+ actions: {
+ position: 'right',
+ add: false,
+ edit: false,
+ delete: false
+ }
+ };
+ }
+
+ deleteMenu(menu) {
+ const self = this;
+ this.ogSweetAlert.swal({
+ title: this.translate.instant('sure_to_delete') + '?',
+ message: this.translate.instant('action_cannot_be_undone'),
+ type: 'warning',
+ showCancelButton: true,
+ confirmButtonColor: '#3c8dbc',
+ confirmButtonText: this.translate.instant('yes_delete'),
+ closeOnConfirm: true
+ }).then(
+ function(result) {
+ if (result.value === true) {
+
+ self.menuService.delete(menu.id).subscribe(
+ (response) => {
+ self.toaster.pop({type: 'success', title: 'success', body: self.translate.instant('successfully_deleted')});
+ // Buscar el elemento en el array y borrarlo
+ const index = self.menus.indexOf(menu);
+ if (index !== -1) {
+ self.menus.splice(menu, 1);
+ }
+ },
+ (error) => {
+ self.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+ });
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/organizational-unit.component.ts b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/organizational-unit.component.ts
index 8a59d77b..c020b7fc 100644
--- a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/organizational-unit.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/organizational-unit.component.ts
@@ -55,7 +55,7 @@ export class OrganizationalUnitComponent implements OnInit, OnDestroy {
}
ngOnInit(): void {
- this.ogCommonService.loadEngineConfig().subscribe(
+ this.ogCommonService.loadEngineConfig().subscribe(
data => {
this.config = data;
@@ -74,7 +74,7 @@ export class OrganizationalUnitComponent implements OnInit, OnDestroy {
(response) => {
this.ous = Array.isArray(response) ? response : [response];
// La primera vez que entra
- if (this.config.timers.clientsStatusInterval.object == null) {
+ if (this.config.timers.clientsStatusInterval.object == null && this.config.timers.clientsStatusInterval.tick > 0) {
this.getClientStatus();
const self = this;
this.config.timers.clientsStatusInterval.object = window.setInterval(function() {
@@ -95,7 +95,6 @@ export class OrganizationalUnitComponent implements OnInit, OnDestroy {
);
-
}
showGrid(show) {
diff --git a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.html b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.html
index 86508a31..02d60caa 100644
--- a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.html
@@ -24,7 +24,7 @@
</td>
<td class="right">
<div class="btn-group visible-md visible-lg hidden-sm hidden-xs">
- <button class="btn btn-default " translate="edit" [routerLink]="'app/client.edit({ou: content.id, clientId: client.id})'"></button>
+ <button class="btn btn-default " translate="edit" [routerLink]="'/app/clients/edit/'+client.id"></button>
<button class="btn btn-danger " translate="delete" (click)="deleteClient(client)"></button>
</div>
<div class="btn-group hidden-md hidden-lg">
@@ -35,7 +35,7 @@
</button>
<ul class="dropdown-menu" role="menu">
<li class="btn-group-vertical">
- <button class="btn btn-default" href="javascript:void(0)" translate="edit" [routerLink]="'app/client.edit({ou: content.id, clientId: client.id})'"></button>
+ <button class="btn btn-default" href="javascript:void(0)" translate="edit" [routerLink]="'/app/clients/edit/'+client.id"></button>
<button class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteClient(client)"></button>
</li>
</ul>
@@ -49,7 +49,7 @@
<!-- *ngIf="selectedStatus[client.status] == true" -->
<div class="row">
<ng-container *ngFor="let client of ou.clients">
- <div class="col-md-2 col-xs-6 padding-5">
+ <div class="col-md-2 col-xs-6 og-client-box">
<div class="info-box client " *ngIf="mustShow(client)">
<span style="position: absolute;">
<input icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" [(ngModel)]="client.selected" (change)="selectClient(client)" />
diff --git a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.scss b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.scss
new file mode 100644
index 00000000..118db555
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.scss
@@ -0,0 +1,11 @@
+.og-client-box {
+ padding: 0;
+ border: 1px solid lightgray;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+ margin: 0 5px;
+ background: white;
+}
+
+.og-client-box .info-box {
+ box-shadow: none;
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.ts b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.ts
index b65b2ffa..0c5e8a14 100644
--- a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.ts
@@ -9,7 +9,8 @@ import {OgCommonService} from '../../../service/og-common.service';
@Component({
selector: 'app-ou-client-component',
- templateUrl: 'ou-client.component.html'
+ templateUrl: 'ou-client.component.html',
+ styleUrls: ['ou-client.component.scss']
})
export class OuClientComponent {
private _ou: OrganizationalUnit;
@@ -41,6 +42,7 @@ export class OuClientComponent {
}
deleteClient(client) {
+ const self = this;
this.ogSweetAlert.swal(
{
title: this.translate.instant('sure_to_delete') + '?',
@@ -52,18 +54,18 @@ export class OuClientComponent {
}).then(
function(response) {
- if (response === true) {
- this.clientService.delete(client.id).then(
- function(success) {
+ if (response.value === true) {
+ self.clientService.delete(client.id).subscribe(
+ (success) => {
// Lo borramos de la unidad organizativa
- const index = this.ou.clients.indexOf(client);
+ const index = self.ou.clients.indexOf(client);
if (index !== -1) {
- this.ou.clients.splice(index, 1);
+ self.ou.clients.splice(index, 1);
}
- this.toaster.pop({type: 'success', title: 'success', body: 'Successfully deleted'});
+ self.toaster.pop({type: 'success', title: 'success', body: 'Successfully deleted'});
},
- function(error) {
- this.toaster.pop({type: 'error', title: 'error', body: error});
+ (error) => {
+ self.toaster.pop({type: 'error', title: 'error', body: error});
}
);
}
diff --git a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-group/ou-group.component.ts b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-group/ou-group.component.ts
index 9d04c84e..e2f3d005 100644
--- a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-group/ou-group.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-group/ou-group.component.ts
@@ -17,8 +17,20 @@ import {Router} from '@angular/router';
styleUrls: ['ou-group.component.css']
})
export class OuGroupComponent {
+ private _ou: OrganizationalUnit;
@Input() ous;
- @Input() content;
+ @Input()
+ set content(ou) {
+ this._ou = ou;
+ this._ou.clients.forEach((client) => {
+ if (this.ogCommonService.selectedClients[client.id]) {
+ client.selected = true;
+ }
+ });
+ }
+ get content() {
+ return this._ou;
+ }
@Input() clientStatus;
@Input() showGrid;
@Input() selectedStatus;
diff --git a/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.html b/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.html
index 97761b02..2f1b7bf5 100644
--- a/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.html
@@ -16,6 +16,7 @@
</div>
</section>
<section class="content">
+ {{user.preferences|json}}
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
@@ -26,7 +27,7 @@
<form role="form">
<div class="form-group col-md-2">
<label translate="username"></label>
- <input class="form-control" readonly="readonly" type="text" [(ngModel)]="user.username" name="username">
+ <input class="form-control" readonly="readonly" type="text" [value]="user.username" name="username">
</div>
<div class="form-group col-md-4">
<label translate="password"></label>
@@ -52,11 +53,11 @@
<label class="help-block" translate="display_as"></label>
<div class="row">
<div class="form-group col-md-1">
- <input icheck type="radio" name="displayGrid" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="user.preferences.ous.showGrid" value="true" />
+ <input icheck type="radio" name="displayGrid" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="user.preferences.ous.showGrid" [value]="true" />
<label translate="grid"></label>
</div>
<div class="form-group col-md-1">
- <input icheck type="radio" name="displayTable" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="user.preferences.ous.showGrid" value="false" />
+ <input icheck type="radio" name="displayTable" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="user.preferences.ous.showGrid" [value]="false" />
<label translate="table"></label>
</div>
</div>
@@ -66,7 +67,7 @@
<div class="row">
<div class="form-group col-md-2">
<label translate="language"></label>
- <select class="form-control" name="language" [(ngModel)]="user.preferences.language" (change)="ogCommonService.changeLanguage($event)">
+ <select class="form-control" name="language" [(ngModel)]="user.preferences.language" (ngModelChange)="ogCommonService.changeLanguage(user.preferences.language)">
<option *ngFor="let lang of constants.languages" [ngValue]="lang.id" >{{lang.name}}</option>
</select>
</div>
diff --git a/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.ts b/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.ts
index 149ad6f3..da6859c2 100644
--- a/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.ts
@@ -42,7 +42,6 @@ export class ProfileComponent implements OnInit {
}
changeTheme() {
- this.app.theme = this.user.preferences.theme;
this.layoutStore.setSkin(this.user.preferences.theme);
}
diff --git a/admin/WebConsole3/frontend/src/app/pages/repository/repository.component.html b/admin/WebConsole3/frontend/src/app/pages/repository/repository.component.html
index 38f08ade..a2d0cf28 100644
--- a/admin/WebConsole3/frontend/src/app/pages/repository/repository.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/repository/repository.component.html
@@ -1,100 +1,100 @@
-<section class="content-header">
- <h1 translate="repositories">
- </h1>
- <ol class="breadcrumb">
- <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li>
- <li class="active" translate="repositories"></li>
- </ol>
-</section>
-<section fixed-toolboxbar class="toolboxbar">
- <div >
- <div class="col-md-12">
- <div class="input-group">
- <input type="text" name="q" class="form-control" placeholder="Search..." ng-model="searchText">
- <span class="input-group-btn">
- <button type="button" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i>
- </button>
- </span>
- </div>
- </div>
- <div class="col-md-12" style="margin-top: 5px;margin-bottom: 5px;">
- <div class="box-tools pull-right">
- <button class="btn btn-default" (click)="newRepository()" translate="new_repo"></button>
- </div>
- </div>
- </div>
-</section>
-<section class="content">
- <div class="row">
- <mk-box [header]="repository.name" [isLoading]="isRepositoryLoading()" [isCollapsable]="true" [isRemovable]="false" boxColor="primary" *ngFor="let repository of repositories" class="col-md-6">
- <div class="box-body">
- <form #form>
- <app-form-input [formType]="formType" [model]="repository" [cols]="2"></app-form-input>
- </form>
- <div class="box-footer">
-
- <button type="button" class="btn btn-primary" translate="save" (click)="saveRepository(Form, repository)"></button>
- <button type="button" class="btn btn-danger pull-right" (click)="deleteRepository(repository)" translate="delete">
- </button>
- </div>
- </div>
- <div class="box-footer">
- <mk-box header="{{'filesystem_info'|translate}}" [isCollapsable]="true" [isRemovable]="false" contentClasses="table-responsive">
- <button type="button" [disabled]="repository.password.length == 0" class="btn btn-primary pull-right" (click)="refreshRepoInfo(repository)">
- <i class="fa fa-refresh"></i> <span translate="refresh_info"></span>
- </button>
- <div class="box-body no-padding" >
-
- <div translate="connection_not_available" *ngIf="!repository.info"></div>
- <table class="table table-condensed table-striped" *ngIf="repository.info">
- <tbody>
- <tr>
- <th colspan="5" translate="disk_info"></th>
- </tr>
- <tr>
- <th translate="partition"></th>
- <th translate="total_disk"></th>
- <th translate="used_disk"></th>
- <th translate="free_disk"></th>
- <th translate="busy_percent_disk"></th>
- </tr>
- <tr>
- <td>{{repository.info.disk[0].partition}}</td>
- <td>{{repository.info.disk[0].total}}</td>
- <td>{{repository.info.disk[0].used}}</td>
- <td>
- {{repository.info.disk[0].free}}
- </td>
- <td>
- <span class="badge" ng-class="{'bg-green': repository.info.disk[0].percent.split('%')[0] < 60, 'bg-red': repository.info.disk[0].percent.split('%')[0] > 85, 'bg-yellow': repository.info.disk[0].percent.split('%')[0] >= 60 && repository.info.disk[0].percent.split('%')[0] <= 85}">{{repository.info.disk[0].percent}}
- </span>
- </td>
- </tr>
- </tbody>
- <tbody>
- <tr>
- <th colspan="2" translate="images_info"></th>
- </tr>
- <tr>
- <th translate="name"></th>
- <th translate="size"></th>
- <th translate="delete"></th>
- </tr>
- </tbody>
- <tbody ng-repeat="fileGroup in repository.info.files">
- <tr ng-repeat="file in fileGroup | orderBy: 'name'">
- <td>{{file.name}}</td>
- <td>{{OGCommonService.getUnits(file.size)}}</td>
- <td>
- <a *ngIf="isImageFile(file)" class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteImageFile(file)"></a>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </mk-box>
- </div>
- <!-- /.box-body -->
- </mk-box>
- </div>
-</section>
+<section class="content-header">
+ <h1 translate="repositories">
+ </h1>
+ <ol class="breadcrumb">
+ <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li>
+ <li class="active" translate="repositories"></li>
+ </ol>
+</section>
+<section fixed-toolboxbar class="toolboxbar">
+ <div >
+ <div class="col-md-12">
+ <div class="input-group">
+ <input type="text" name="q" class="form-control" placeholder="Search..." ng-model="searchText">
+ <span class="input-group-btn">
+ <button type="button" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i>
+ </button>
+ </span>
+ </div>
+ </div>
+ <div class="col-md-12" style="margin-top: 5px;margin-bottom: 5px;">
+ <div class="box-tools pull-right">
+ <button class="btn btn-default" (click)="newRepository()" translate="new_repo"></button>
+ </div>
+ </div>
+ </div>
+</section>
+<section class="content">
+ <div class="row">
+ <mk-box [header]="repository.name" [isLoading]="isRepositoryLoading()" [isCollapsable]="true" [isRemovable]="false" boxColor="primary" *ngFor="let repository of repositories" class="col-md-6">
+ <div class="box-body">
+ <form #form>
+ <app-form-input [formType]="formType" [model]="repository" [cols]="1"></app-form-input>
+ </form>
+ <div class="box-footer">
+
+ <button type="button" class="btn btn-primary" translate="save" (click)="saveRepository(Form, repository)"></button>
+ <button type="button" class="btn btn-danger pull-right" (click)="deleteRepository(repository)" translate="delete">
+ </button>
+ </div>
+ </div>
+ <div class="box-footer">
+ <mk-box header="{{'filesystem_info'|translate}}" [isCollapsable]="true" [isRemovable]="false" contentClasses="table-responsive">
+ <button type="button" [disabled]="repository.password.length == 0" class="btn btn-primary pull-right" (click)="refreshRepoInfo(repository)">
+ <i class="fa fa-refresh"></i> <span translate="refresh_info"></span>
+ </button>
+ <div class="box-body no-padding" >
+
+ <div translate="connection_not_available" *ngIf="!repository.info"></div>
+ <table class="table table-condensed table-striped" *ngIf="repository.info">
+ <tbody>
+ <tr>
+ <th colspan="5" translate="disk_info"></th>
+ </tr>
+ <tr>
+ <th translate="partition"></th>
+ <th translate="total_disk"></th>
+ <th translate="used_disk"></th>
+ <th translate="free_disk"></th>
+ <th translate="busy_percent_disk"></th>
+ </tr>
+ <tr>
+ <td>{{repository.info.disk[0].partition}}</td>
+ <td>{{repository.info.disk[0].total}}</td>
+ <td>{{repository.info.disk[0].used}}</td>
+ <td>
+ {{repository.info.disk[0].free}}
+ </td>
+ <td>
+ <span class="badge" ng-class="{'bg-green': repository.info.disk[0].percent.split('%')[0] < 60, 'bg-red': repository.info.disk[0].percent.split('%')[0] > 85, 'bg-yellow': repository.info.disk[0].percent.split('%')[0] >= 60 && repository.info.disk[0].percent.split('%')[0] <= 85}">{{repository.info.disk[0].percent}}
+ </span>
+ </td>
+ </tr>
+ </tbody>
+ <tbody>
+ <tr>
+ <th colspan="2" translate="images_info"></th>
+ </tr>
+ <tr>
+ <th translate="name"></th>
+ <th translate="size"></th>
+ <th translate="delete"></th>
+ </tr>
+ </tbody>
+ <tbody ng-repeat="fileGroup in repository.info.files">
+ <tr ng-repeat="file in fileGroup | orderBy: 'name'">
+ <td>{{file.name}}</td>
+ <td>{{OGCommonService.getUnits(file.size)}}</td>
+ <td>
+ <a *ngIf="isImageFile(file)" class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteImageFile(file)"></a>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </mk-box>
+ </div>
+ <!-- /.box-body -->
+ </mk-box>
+ </div>
+</section>
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.html
new file mode 100644
index 00000000..65c3cacb
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.html
@@ -0,0 +1,45 @@
+<mk-box [boxColor]="'warning'" [isRemovable]="false">
+ <mk-box-header class="box-header with-border">
+ <i class="fa fa-folder-open-o"></i>
+ <h3 class="box-title">
+ <div mk-dropdown class="btn-group" *ngIf="!content.$$editing">
+ <mk-dropdown-toggle>
+ <button #toggleElement type="button" class="btn btn-default dropdown-toggle" >
+ {{content.name}}
+ <span class="fa fa-caret-down"></span>
+ </button>
+ </mk-dropdown-toggle>
+ <mk-dropdown-menu>
+ <li role="presentation">
+ <a role="menuitem" tabindex="-1" href="#" translate="add_group"></a>
+ </li>
+ <li role="presentation">
+ <a role="menuitem" tabindex="-1" href="#" translate="add_software_component"></a>
+ </li>
+ <li role="presentation" class="divider"></li>
+ <li>
+ <a class="" href="javascript:void(0)" translate="edit" (click)="content.$$tmpDescription = content.description; content.$$editing = true"></a>
+ </li>
+ <li role="presentation" class="divider"></li>
+ <li role="presentation" class="delete-option">
+ <a class="" href="javascript:void(0)" translate="delete" (click)="vm.deleteGroup(content.id)"></a>
+ </li>
+ </mk-dropdown-menu>
+ </div>
+ <div *ngIf="content.$$editing" class="col-xs-6">
+ <input type="text" class="form-control" [(ngModel)]="content.$$tmpDescription">
+ <span class="input-group-btn">
+ <button type="button" class="btn btn-default btn-flat" translate="done" (click)="changeGroupName(content)"></button>
+ <button type="button" class="btn btn-info btn-flat" translate="cancel" (click)="content.$$editing = false"></button>
+ </span>
+ </div>
+ </h3>
+ <!-- /.box-tools -->
+ </mk-box-header>
+ <!-- /.box-header -->
+ <mk-box-content class="box-body folders" style="display: block;">
+ <app-software-component-group *ngFor="let content of content.groups" [content]="content" [softwareTypes]="softwareTypes">
+ </app-software-component-group>
+ <app-software-components-table *ngIf="content.components" [components]="content.components" [softwareTypes]="softwareTypes"></app-software-components-table>
+ </mk-box-content>
+</mk-box>
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.ts
new file mode 100644
index 00000000..d27504a4
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.ts
@@ -0,0 +1,10 @@
+import {Component, Input} from '@angular/core';
+
+@Component({
+ selector: 'app-software-component-group',
+ templateUrl: 'software-components-group.component.html'
+})
+export class SoftwareComponentsGroupComponent {
+ @Input() content;
+ @Input() softwareTypes;
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.html
new file mode 100644
index 00000000..fb4bdbd2
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.html
@@ -0,0 +1,43 @@
+<table class="table table-hover">
+ <tbody>
+ <tr>
+ <th translate="description"></th>
+ <th translate="type"></th>
+ <!--th translate="imageUrl"></th-->
+ <th translate="options"></th>
+ </tr>
+ <tr *ngFor="let softwareComponent of components; let index = index" class="{{(index%2 == 0)?'odd':'even'}}">
+ <td>
+ <span *ngIf="softwareComponent.$$editing">
+ <input type="text" class="form-control" [(ngModel)]="softwareComponent.$$tmpDescription">
+ </span>
+ <span *ngIf="!softwareComponent.$$editing">
+ {{softwareComponent.description}}
+ </span>
+ </td>
+ <td>
+ <span *ngIf="softwareComponent.$$editing">
+ <select class="form-control" [(ngModel)]="softwareComponent.$$tmpType">
+ <option [value]="softwareType.nemonic" *ngFor="let softwareType of softwareTypes">{{softwareType.name}}</option>
+ </select>
+ </span>
+ <span *ngIf="!softwareComponent.$$editing">
+ <select disabled="disabled" class="form-control" [(ngModel)]="softwareComponent.type">
+ <option [value]="softwareType.nemonic" *ngFor="let softwareType of softwareTypes">{{softwareType.name}}</option>
+ </select>
+ </span>
+ </td>
+ <td class="right">
+ <span *ngIf="softwareComponent.$$editing">
+ <div class="btn-group ">
+ <button class="btn btn-primary " translate="ok" (click)="saveSoftwareComponent(softwareComponent)"></button>
+ <button class="btn btn-default " translate="cancel" (click)="softwareComponent.$$editing = false"></button>
+ </div>
+ </span>
+ <span *ngIf="!softwareComponent.$$editing">
+ <app-table-action [rowData]="softwareComponent" [options]="tableOptions" (edit)="editSoftwareComponent($event)" (delete)="deleteSoftwareComponent($event)"></app-table-action>
+ </span>
+ </td>
+ </tr>
+ </tbody>
+</table>
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.ts
new file mode 100644
index 00000000..30341c92
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.ts
@@ -0,0 +1,84 @@
+import {Component, Input, OnInit} from '@angular/core';
+import {ToasterService} from '../../../../service/toaster.service';
+import {TranslateService} from '@ngx-translate/core';
+import {OgSweetAlertService} from '../../../../service/og-sweet-alert.service';
+import {Router} from '@angular/router';
+import {SoftwareComponent} from '../../../../model/software-component';
+import {SoftwareComponentService} from '../../../../api/software-component.service';
+import {environment} from '../../../../../environments/environment';
+
+@Component({
+ selector: 'app-software-components-table',
+ templateUrl: 'software-components-table.component.html'
+})
+export class SoftwareComponentsTableComponent implements OnInit {
+ @Input() components;
+ @Input() softwareTypes;
+ public tableOptions: { buttons: ({ action: string } | { handler: (profile) => any; classes: string; label: string })[]; override: boolean };
+
+ public constructor(private router: Router, private softwareComponentService: SoftwareComponentService, private ogSweetAlert: OgSweetAlertService, private toaster: ToasterService, private translate: TranslateService) {
+ }
+
+ ngOnInit(): void {
+ this.tableOptions = {
+ override: false,
+ buttons: [
+ {
+ action: 'edit'
+ },
+ {
+ action: 'delete'
+ }
+ ]
+ };
+ }
+
+ editSoftwareComponent(softwareComponent) {
+ softwareComponent.$$editing = true;
+ softwareComponent.$$tmpDescription = softwareComponent.description;
+ softwareComponent.$$tmpType = softwareComponent.type;
+ }
+ saveSoftwareComponent(softwareComponent: any) {
+ softwareComponent.$$editing = false;
+ softwareComponent.description = softwareComponent.$$tmpDescription;
+ softwareComponent.type = softwareComponent.$$tmpType;
+ const hcCopy = Object.assign({}, softwareComponent);
+
+ // TODO - Llamar al servidor para guardar el cambio
+ this.softwareComponentService.update(hcCopy).subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: this.translate.instant('success'), body: this.translate.instant('successfully_saved')});
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: this.translate.instant('error'), body: error});
+ }
+ );
+ }
+
+ deleteSoftwareComponent(softwareComponent: SoftwareComponent) {
+ this.ogSweetAlert.swal({
+ title: this.translate.instant('sure_to_delete') + '?',
+ text: this.translate.instant('action_cannot_be_undone'),
+ type: 'warning',
+ showCancelButton: true,
+ confirmButtonColor: '#3c8dbc',
+ confirmButtonText: this.translate.instant('yes_delete'),
+ closeOnConfirm: true}).then(
+ function(result) {
+ if (result === true) {
+ this.softwareComponentService.delete(softwareComponent.id).subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: this.translate.instant('success'), body: this.translate.instant('successfully_deleted')});
+ const index = this.softwareComponentsGroups[0].components.indexOf(softwareComponent);
+ if (index !== -1) {
+ this.softwareComponentsGroups[0].components.splice(index, 1);
+ }
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: this.translate.instant('error'), body: error});
+ }
+ );
+ }
+ });
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.css b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.css
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.html
new file mode 100644
index 00000000..043210de
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.html
@@ -0,0 +1 @@
+<app-software-component-group *ngFor="let content of softwareComponentsGroups" [content]="content" [softwareTypes]="softwareTypes"></app-software-component-group>
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.ts
new file mode 100644
index 00000000..78e80784
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.ts
@@ -0,0 +1,17 @@
+import {Component, Input, OnInit} from '@angular/core';
+
+@Component({
+ selector: 'app-software-components',
+ templateUrl: './software-components.component.html',
+ styleUrls: ['./software-components.component.css']
+})
+export class SoftwareComponentsComponent implements OnInit {
+ @Input() softwareTypes;
+ @Input() softwareComponentsGroups;
+ constructor() { }
+
+ ngOnInit() {
+ console.log(this.softwareComponentsGroups);
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.html
new file mode 100644
index 00000000..95b2879a
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.html
@@ -0,0 +1,47 @@
+<mk-box boxColor="warning" headerBorder="true" isCollapsable="true" [isRemovable]="false">
+ <mk-box-header class="box-header with-border">
+ <i class="fa fa-folder-open-o"></i>
+ <h3 class="box-title">
+ <div class="btn-group" *ngIf="!content.editing">
+ <div mk-dropdown class="btn-group" [isWrapper]="false" >
+ <mk-dropdown-toggle>
+ <button #toggleElement type="button" class="btn btn-default dropdown-toggle">
+ {{content.name}}
+ <span class="fa fa-caret-down"></span>
+ </button>
+ </mk-dropdown-toggle>
+ <mk-dropdown-menu>
+ <li >
+ <a role="menuitem" tabindex="-1" href="#" translate="add_group"></a>
+ </li>
+ <li >
+ <a role="menuitem" tabindex="-1" href="#" translate="add_profile" [routerLink]="'/app/software/profile/create/' + content.id "></a>
+ </li>
+ <li class="divider"></li>
+ <li>
+ <a class="" href="javascript:void(0)" translate="edit" (click)="content.$$tmpName = content.name; content.editing = true"></a>
+ </li>
+ <li role="presentation" class="divider"></li>
+ <li role="presentation" class="delete-option">
+ <a class="" href="javascript:void(0)" translate="delete" (click)="deleteGroup(content.id)"></a>
+ </li>
+ </mk-dropdown-menu>
+ </div>
+ </div>
+ <div *ngIf="content.editing" class="col-xs-6">
+ <input type="text" class="form-control" [(ngModel)]="content.$$tmpName">
+ <span class="input-group-btn">
+ <button type="button" class="btn btn-default btn-flat" translate="done" (click)="changeGroupName(content)"></button>
+ <button type="button" class="btn btn-info btn-flat" translate="cancel" (click)="content.editing = false"></button>
+ </span>
+ </div>
+ </h3>
+ <!-- /.box-tools -->
+ </mk-box-header>
+ <!-- /.box-header -->
+ <mk-box-content class="box-body folders" style="display: block;">
+ <app-software-profiles-group *ngFor="let content of content.groups" [content]="content">
+ </app-software-profiles-group>
+ <app-software-profiles-table *ngIf="content.profiles" [profiles]="content.profiles"></app-software-profiles-table>
+ </mk-box-content>
+</mk-box>
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.ts
new file mode 100644
index 00000000..e3e65420
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.ts
@@ -0,0 +1,14 @@
+import {ComponentMetadata} from 'codelyzer/angular/metadata';
+import {Component, Input} from '@angular/core';
+
+@Component({
+ selector: 'app-software-profiles-group',
+ templateUrl: 'software-profiles-group.component.html'
+})
+export class SoftwareProfilesGroupComponent {
+ @Input() content;
+
+ constructor() {
+ console.log(this.content);
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.html
new file mode 100644
index 00000000..6f362fa9
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.html
@@ -0,0 +1,61 @@
+<table class="table table-hover">
+ <tbody>
+ <tr>
+ <th translate="description"></th>
+ <th translate="windowsboot"></th>
+ <th translate="options"></th>
+ </tr>
+ <tr *ngFor="let profile of profiles; let index = index" class="{{(index%2 == 0)?'odd':'even'}}">
+ <td>
+ <span *ngIf="profile.$$editing">
+ <input type="text" class="form-control" [(ngModel)]="profile.$$tmpDescription">
+ </span>
+ <span *ngIf="!profile.$$editing">
+ {{profile.description}}
+ </span>
+ </td>
+ <td>
+ <span *ngIf="profile.$$editing">
+ <select class="form-control"[(ngModel)]="profile.$$tmpWindowsboot">
+ <option [value]="item" *ngFor="let item of windowsboots"> {{item}}</option>
+ </select>
+ </span>
+ <span *ngIf="!profile.$$editing">
+ {{profile.windowsboot}}
+ </span>
+ </td>
+ <td class="right">
+ <ng-container *ngIf="profile.$$editing">
+ <div class="btn-group ">
+ <button class="btn btn-primary " translate="ok" (click)="saveSoftwareProfile(profile)"></button>
+ <button class="btn btn-default " translate="cancel" (click)="profile.$$editing = false"></button>
+ </div>
+ </ng-container>
+ <ng-container *ngIf="!profile.$$editing">
+ <app-table-action [rowData]="profile" [options]="tableOptions" (edit)="editSoftwareProfile($event)" (delete)="deleteSoftwareProfile($event)"></app-table-action>
+<!--
+ <div class="btn-group visible-md visible-lg hidden-sm hidden-xs">
+ <button class="btn btn-default" translate="edit" (click)="editSoftwareProfile(profile)"></button>
+ <button class="btn btn-default" href="javascript:void(0)" translate="config" (click)="goToEditProfile(profile)"></button>
+ <button class="btn btn-danger " translate="delete" (click)="deleteSoftwareProfile(profile)"></button>
+ </div>
+ <div class="btn-group hidden-md hidden-lg">
+ <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
+ <i class="fa fa-gear"></i>
+ <span class="caret"></span>
+ <span class="sr-only">Toggle Dropdown</span>
+ </button>
+ <ul class="dropdown-menu" role="menu">
+ <li class="btn-group-vertical">
+ <button class="btn btn-default" translate="edit" (click)="editSoftwareProfile(profile)"></button>
+ <button class="btn btn-default" href="javascript:void(0)" translate="config" ui-sref="goToEditProfile(profile)"></button>
+ <button class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteSoftwareProfile(profile)"></button>
+ </li>
+ </ul>
+ </div>
+-->
+ </ng-container>
+ </td>
+ </tr>
+ </tbody>
+ </table>
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.ts
new file mode 100644
index 00000000..9ea76af2
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.ts
@@ -0,0 +1,100 @@
+import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
+import {SoftwareProfile} from '../../../../model/software-profile';
+import {SoftwareProfileService} from '../../../../api/software-profile.service';
+import {ToasterService} from '../../../../service/toaster.service';
+import {TranslateService} from '@ngx-translate/core';
+import {OgSweetAlertService} from '../../../../service/og-sweet-alert.service';
+import {Router} from '@angular/router';
+import {environment} from '../../../../../environments/environment';
+
+
+@Component({
+ selector: 'app-software-profiles-table',
+ templateUrl: 'software-profiles-table.component.html'
+})
+export class SoftwareProfilesTableComponent implements OnInit {
+ @Input() profiles;
+ windowsboots: any;
+ tableOptions: any;
+
+ public constructor(private router: Router, private softwareProfileService: SoftwareProfileService, private ogSweetAlert: OgSweetAlertService, private toaster: ToasterService, private translate: TranslateService) {
+
+ }
+ ngOnInit(): void {
+ this.windowsboots = environment.windowsboots;
+ this.tableOptions = {
+ override: false,
+ buttons: [
+ {
+ action: 'edit'
+ },
+ {
+ label: 'configure',
+ handler: (profile) => this.goToEditProfile(profile),
+ classes: 'btn-default'
+ },
+ {
+ action: 'delete'
+ }
+ ]
+ };
+ }
+
+ editSoftwareProfile(softwareProfile) {
+ softwareProfile.$$editing = true;
+ softwareProfile.$$tmpName = softwareProfile.name;
+ softwareProfile.$$tmpDescription = softwareProfile.description;
+ softwareProfile.$$tmpWindowsboot = softwareProfile.windowsboot;
+ }
+
+ saveSoftwareProfile(softwareProfile) {
+ softwareProfile.$$editing = false;
+ softwareProfile.name = softwareProfile.$$tmpName;
+ softwareProfile.description = softwareProfile.$$tmpDescription;
+ softwareProfile.windowsboot = softwareProfile.$$tmpWindowsboot;
+ const hpCopy = Object.assign({}, softwareProfile);
+ // TODO - Llamar al servidor para guardar el cambio
+ this.softwareProfileService.update(hpCopy).subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_saved')});
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+
+ deleteSoftwareProfile(softwareProfile) {
+ const self = this;
+
+ this.ogSweetAlert.question(this.translate.instant('sure_to_delete') + '?', this.translate.instant('action_cannot_be_undone'),
+ function(result) {
+ if (result.value === true) {
+ self.softwareProfileService.delete(softwareProfile.id).subscribe(
+ (response) => {
+ self.toaster.pop({type: 'success', title: self.translate.instant('success'), body: self.translate.instant('successfully_deleted')});
+ const index = self.profiles.indexOf(softwareProfile);
+ if (index !== -1) {
+ self.profiles.splice(index, 1);
+ }
+ },
+ (error) => {
+ self.toaster.pop({type: 'error', title: self.translate.instant('error'), body: error});
+ }
+ );
+ }
+ }
+ );
+ }
+
+ goToEditProfile(profile: SoftwareProfile) {
+ this.router.navigate(['/app/software/profile', profile.id]).then(
+ success => {
+ console.log(success);
+ },
+ error => {
+ console.log(error);
+ }
+ );
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.css b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.css
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.html
new file mode 100644
index 00000000..adf2e70b
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.html
@@ -0,0 +1,3 @@
+<!-- Nested node template -->
+
+<app-software-profiles-group *ngFor="let content of softwareProfileGroups" [content]="content"></app-software-profiles-group>
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.ts
new file mode 100644
index 00000000..d7d3987d
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.ts
@@ -0,0 +1,19 @@
+import {Component, Input, OnInit} from '@angular/core';
+
+@Component({
+ selector: 'app-software-profiles',
+ templateUrl: './software-profiles.component.html',
+ styleUrls: ['./software-profiles.component.css']
+})
+export class SoftwareProfilesComponent implements OnInit {
+
+ @Input() softwareProfileGroups;
+
+ constructor() {
+ }
+
+ ngOnInit() {
+ console.log(this.softwareProfileGroups);
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.css b/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.css
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.html
new file mode 100644
index 00000000..ceda7046
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.html
@@ -0,0 +1,66 @@
+<div class="box box-warning" >
+ <div class="box-header with-border">
+ <i class="fa fa-folder-open-o"></i>
+ <h3 class="box-title">
+ <div class="btn-group">
+ <div>
+ <a href="javascript:void(0)" data-toggle="dropdown" class="dropdown-toggle" translate="software_types">
+ </a>
+ <ul class="dropdown-menu">
+ <li role="presentation">
+ <a role="menuitem" tabindex="-1" href="#" translate="add_software_type"></a>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </h3>
+ <div class="box-tools pull-right">
+ <button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i>
+ </button>
+ </div>
+ <!-- /.box-tools -->
+ </div>
+ <!-- /.box-header -->
+ <div class="box-body folders" style="display: block;">
+ <table class="table table-hover">
+ <tbody><tr>
+ <th translate="name"></th>
+ <th translate="options"></th>
+ </tr>
+ <tr *ngFor="let softwareType of softwareTypes; let index = index;" class="{{( index%2 == 0)?'odd':'even'}}">
+ <td>
+ <span *ngIf="!softwareType.$$editing">{{softwareType.name}}</span>
+ <span *ngIf="softwareType.$$editing"><input type="text" class="form-control" [(ngModel)]="softwareType.$$tmpName" /></span>
+ </td>
+ <td class="right">
+ <span *ngIf="softwareType.$$editing">
+ <div class="btn-group ">
+ <button class="btn btn-primary " translate="ok" (click)="saveSoftwareType(softwareType)"></button>
+ <button class="btn btn-default " translate="cancel" (click)="softwareType.$$editing = false"></button>
+ </div>
+ </span>
+ <span *ngIf="!softwareType.$$editing">
+ <div class="btn-group visible-md visible-lg hidden-sm hidden-xs">
+ <button class="btn btn-default " translate="edit" (click)="editSoftwareType(softwareType)"></button>
+ <button class="btn btn-danger " translate="delete" (click)="deleteClient(client.id)"></button>
+ </div>
+ <div class="btn-group hidden-md hidden-lg">
+ <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
+ <i class="fa fa-gear"></i>
+ <span class="caret"></span>
+ <span class="sr-only">Toggle Dropdown</span>
+ </button>
+ <ul class="dropdown-menu" role="menu">
+ <li class="btn-group-vertical">
+ <button class="btn btn-default" href="javascript:void(0)" translate="edit" (click)="editSoftwareType(softwareType)"></button>
+ <button class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteClient(client.id)"></button>
+ </li>
+ </ul>
+ </div>
+ </span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+</div>
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.ts
new file mode 100644
index 00000000..a5e62b2f
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.ts
@@ -0,0 +1,26 @@
+import {Component, Input, OnInit} from '@angular/core';
+
+@Component({
+ selector: 'app-software-types',
+ templateUrl: './software-types.component.html',
+ styleUrls: ['./software-types.component.css']
+})
+export class SoftwareTypesComponent implements OnInit {
+ @Input() softwareTypes;
+
+ constructor() { }
+
+ ngOnInit() {
+ }
+
+ editSoftwareType(softwareType) {
+ softwareType.$$editing = true;
+ softwareType.$$tmpName = softwareType.name;
+ }
+ saveSoftwareType(softwareType) {
+ softwareType.$$editing = false;
+ softwareType.name = softwareType.$$tmpName;
+ // TODO - Llamar al servidor para guardar el cambio
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software.component.html
index adb7ae48..fadb8848 100644
--- a/admin/WebConsole3/frontend/src/app/pages/software/software.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software.component.html
@@ -1 +1,65 @@
-<div>Html template for class Software</div> \ No newline at end of file
+<ng-container>
+ <section class="content-header">
+ <h1 translate="software">
+ </h1>
+ <ol class="breadcrumb">
+ <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li>
+ <li class="active" translate="software"></li>
+ </ol>
+ </section>
+ <section fixed-toolboxbar class="toolboxbar">
+ <div >
+ <div class="col-md-12">
+ <div class="input-group">
+ <input type="text" name="q" class="form-control" placeholder="{{'search'|translate}}..." ng-model="vm.searchText">
+ <span class="input-group-btn">
+ <button type="button" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i>
+ </button>
+ </span>
+ </div>
+ </div>
+ <div class="col-md-12" style="margin-top: 5px;margin-bottom: 5px;">
+ <div class="box-tools pull-right">
+ <mk-dropdown class="btn-group">
+ <mk-dropdown-toggle>
+ <span translate="new"></span><span class="caret"></span>
+ </mk-dropdown-toggle>
+ <mk-dropdown-menu>
+ <li role="presentation"><a role="menuitem" tabindex="-1" [routerLink]="'/app/software/profile/create'" translate="profile"></a></li>
+ <li role="presentation"><a role="menuitem" tabindex="-1" [routerLink]="'/app/software/component/create'" translate="component"></a></li>
+ <!--li role="presentation"><a role="menuitem" tabindex="-1" [routerLink]="app/software.type.new" translate="software_type"></a></li-->
+ </mk-dropdown-menu>
+ </mk-dropdown>
+ </div>
+ </div>
+ </div>
+ </section>
+ <section class="content">
+ <div class="row">
+ <span style="padding: 0 10px"></span>
+ <div class="col-md-12">
+ <mk-tabs>
+ <mk-tab>
+ <mk-tab-header><span translate="software_profiles"></span></mk-tab-header>
+ <mk-tab-content>
+ <app-software-profiles [softwareProfileGroups]="softwareProfileGroups"></app-software-profiles>
+ </mk-tab-content>
+ </mk-tab>
+ <mk-tab>
+ <mk-tab-header><span translate="software_components"></span></mk-tab-header>
+ <mk-tab-content>
+ <app-software-components [softwareComponentsGroups]="softwareComponentsGroups" [softwareTypes]="softwareTypes"></app-software-components>
+ </mk-tab-content>
+ </mk-tab>
+ <mk-tab>
+ <mk-tab-header><span translate="software_types"></span></mk-tab-header>
+ <mk-tab-content>
+ <app-software-types [softwareTypes]="softwareTypes" ></app-software-types>
+ </mk-tab-content>
+ </mk-tab>
+ </mk-tabs>
+ <!-- /.tab-content -->
+ </div>
+ </div>
+ </section>
+</ng-container>
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software.component.scss b/admin/WebConsole3/frontend/src/app/pages/software/software.component.scss
index b936796b..e69de29b 100644
--- a/admin/WebConsole3/frontend/src/app/pages/software/software.component.scss
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software.component.scss
@@ -1,3 +0,0 @@
-software {
-
-}
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software.component.ts
index ef75722b..59b81298 100644
--- a/admin/WebConsole3/frontend/src/app/pages/software/software.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software.component.ts
@@ -1,17 +1,67 @@
-import { Component } from '@angular/core';
-
-import { SoftwareService } from 'src/app/api/software.service';
-import { Software } from 'src/app/model/software';
-
-@Component({
- selector: 'software',
- templateUrl: './software.component.html',
- styleUrls: [ './software.component.scss' ]
-})
-export class SoftwareComponent {
- // this tells the tabs component which Pages
- // should be each tab's root Page
- constructor(public softwareService: SoftwareService) {
- }
-
-}
+import { Component, OnInit } from '@angular/core';
+import {AuthModule} from 'globunet-angular/core';
+import {SoftwareProfileService} from '../../api/software-profile.service';
+import {OgCommonService} from '../../service/og-common.service';
+import {TranslateService} from '@ngx-translate/core';
+import {SoftwareComponentService} from '../../api/software-component.service';
+import {OgSweetAlertService} from '../../service/og-sweet-alert.service';
+import {ToasterService} from '../../service/toaster.service';
+import {SoftwareTypeService} from '../../api/software-type.service';
+
+@Component({
+ selector: 'app-software',
+ templateUrl: './software.component.html',
+ styleUrls: ['./software.component.scss']
+})
+export class SoftwareComponent implements OnInit {
+ public softwareProfileGroups: any[] = [];
+ public softwareComponentsGroups: any[][];
+ public softwareComponents: any[] = [];
+ public softwareTypes: any[] = [];
+
+ constructor(private authModule: AuthModule,
+ private ogSweetAlert: OgSweetAlertService,
+ private toaster: ToasterService,
+ private softwareComponentService: SoftwareComponentService,
+ private softwareTypeService: SoftwareTypeService,
+ private softwareProfileService: SoftwareProfileService,
+ private OGCommonService: OgCommonService,
+ private translate: TranslateService) { }
+
+ ngOnInit() {
+ if (this.authModule.getLoggedUser().id !== 0) {
+ this.softwareProfileService.list().subscribe(
+ (response) => {
+ this.softwareProfileGroups = [
+ this.OGCommonService.createGroups(response, 'profiles')
+ ];
+ this.softwareProfileGroups[0].name = this.translate.instant('software_profiles');
+ },
+ (error) => {
+ alert(error);
+ }
+ );
+ this.softwareTypeService.list().subscribe(
+ data => {
+ this.softwareTypes = data;
+ },
+ (error) => {
+ alert(error);
+ }
+ );
+ this.softwareComponentService.list().subscribe(
+ data => {
+ this.softwareComponents = data;
+ this.softwareComponentsGroups = [
+ this.OGCommonService.createGroups(this.softwareComponents, 'components')
+ ];
+ // @ts-ignore
+ this.softwareComponentsGroups[0].name = this.translate.instant('software_components');
+ },
+ error => {
+ alert(error);
+ }
+ );
+ }
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/trace/trace.component.ts b/admin/WebConsole3/frontend/src/app/pages/trace/trace.component.ts
index af1b2cf7..750e5096 100644
--- a/admin/WebConsole3/frontend/src/app/pages/trace/trace.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/trace/trace.component.ts
@@ -1,261 +1,263 @@
-import {Component, OnDestroy, OnInit} from '@angular/core';
-
-import { TraceService } from 'src/app/api/trace.service';
-import { Trace } from 'src/app/model/trace';
-import {ToasterService} from '../../service/toaster.service';
-import {OgSweetAlertService} from '../../service/og-sweet-alert.service';
-import {Router} from '@angular/router';
-import {OgCommonService} from '../../service/og-common.service';
-import {environment} from '../../../environments/environment';
-import {TranslateService} from '@ngx-translate/core';
-import {QueryOptions} from 'globunet-angular/core/providers/api/query-options';
-import {forkJoin} from 'rxjs';
-
-import * as moment from 'moment';
-
-@Component({
- selector: 'app-trace',
- templateUrl: './trace.component.html',
- styleUrls: [ './trace.component.scss' ]
-})
-export class TraceComponent implements OnInit, OnDestroy {
- public traces = [];
- public selection = [];
- public filters = {
- searchText: '',
- status: {
- 'finished': {
- name: 'finished',
- selected: true
- },
- 'execution': {
- name: 'execution',
- selected: true
- }
- },
- finishedStatus: {
- 'noErrors': {
- name: 'no-errors',
- selected: true
- },
- 'withErrors': {
- name: 'with-errors',
- selected: true
- },
- },
- dateRange: {
- startDate: null,
- endDate: null
- }
- };
- config: { constants: any; timers: any; };
-
- private datePickerOptions: { timePickerIncrement: number; timePicker: boolean; format: string; timePicker24Hour: boolean; locale: { fromLabel: any; toLabel: any; cancelLabel: any; firstDay: number; applyLabel: any; format: string; daysOfWeek: any[]; separator: string; customRangeLabel: any; weekLabel: string; monthNames: any[] } };
- private selectAll: any;
- private executionTasks: Trace[];
- public showInfo: string;
- // this tells the tabs component which Pages
- // should be each tab's root Page
- constructor(public traceService: TraceService,
- private ogCommonService: OgCommonService,
- private router: Router,
- private ogSweetAlert: OgSweetAlertService,
- private toaster: ToasterService,
- private translate: TranslateService) {
- }
-
- ngOnDestroy() {
- if (this.config.timers && this.config.timers.executionsInterval) {
- clearInterval(this.config.timers.executionsInterval.object);
- }
- }
-
-ngOnInit(): void {
- const self = this;
- this.ogCommonService.loadEngineConfig().subscribe(
- data => {
- this.config = data;
-
- if (this.config.timers.executionsInterval.object === null) {
- this.config.timers.executionsInterval.object = setInterval(function() {
- self.getExecutionTasks();
- }, this.config.timers.executionsInterval.tick);
- }
-
- this.datePickerOptions = {
- 'locale': {
- 'format': 'DD/MM/YYYY HH:mm',
- 'separator': ' - ',
- 'applyLabel': this.translate.instant('apply'),
- 'cancelLabel': this.translate.instant('cancel'),
- 'fromLabel': this.translate.instant('from'),
- 'toLabel': this.translate.instant('to'),
- 'customRangeLabel': this.translate.instant('custom_range'),
- 'weekLabel': 'W',
- 'daysOfWeek': [
- this.translate.instant('sun'),
- this.translate.instant('mon'),
- this.translate.instant('tue'),
- this.translate.instant('wed'),
- this.translate.instant('thu'),
- this.translate.instant('fri'),
- this.translate.instant('sat')
- ],
- 'monthNames': [
- this.translate.instant('january'),
- this.translate.instant('february'),
- this.translate.instant('march'),
- this.translate.instant('april'),
- this.translate.instant('may'),
- this.translate.instant('june'),
- this.translate.instant('july'),
- this.translate.instant('august'),
- this.translate.instant('september'),
- this.translate.instant('october'),
- this.translate.instant('november'),
- this.translate.instant('december')
- ],
- 'firstDay': 1
- },
- timePicker: true,
- timePickerIncrement: 30,
- timePicker24Hour: true,
- format: 'DD/MM/YYYY HH:mm'
- };
- this.traceService.list().subscribe(
- (response) => {
- this.traces = response;
- },
- (error) => {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- }
- );
-}
-
-
- selectTrace(trace) {
- const index = this.selection.indexOf(trace);
- if (trace.selected === true && index === -1) {
- this.selection.push(trace);
- } else if (trace.selected === false && index !== -1) {
- this.selection.splice(index, 1);
- }
- }
-
- selectAllTraces() {
- const filter = this.traces.filter(function(trace: Trace) {
- return true;
- });
- for (let index = 0; index < filter.length; index++) {
- filter[index].selected = this.selectAll;
- this.selectTrace(filter[index]);
- }
- }
-
- relaunchTraces() {
-
- }
-
- deleteTraces() {
- this.ogSweetAlert.question( this.translate.instant('sure_to_delete') + '?', this.translate.instant('action_cannot_be_undone'), function(response) {
- const promises = [];
- for (let index = 0; index < this.selection.length; index++) {
- promises.push(this.traceService.delete(this.selection[index].id));
- }
- forkJoin(promises).subscribe(
- (success) => {
- this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_deleted')});
- this.selectAll = false;
- this.selection = [];
- this.searchText = '';
- },
- (error) => {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- });
- }
-
- getExecutionTasks() {
- this.traceService.list(new QueryOptions({finished: 0})).subscribe(
- (result) => {
- this.executionTasks = result;
- },
- (error) => {
-
- }
- );
- }
-
- deleteExecutionTace(task) {
- this.ogSweetAlert.question(
- this.translate.instant('delete_task'),
- this.translate.instant('sure_to_delete_task') + '?',
- function(result) {
- if (result) {
- this.traceService.delete(task.id).subscribe(
- (response) => {
- this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_deleted')});
- this.getExecutionTasks();
- },
- (error) => {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
-
- }
- }
- );
-
- }
-
- relaunchExecutionTask(task) {
- this.ogSweetAlert.question(
- this.translate.instant('relaunch_task'),
- this.translate.instant('sure_to_relaunch_task') + '?',
- function(result) {
- if (result) {
-
- }
- }
- );
- }
-
- filterTraceStatus(trace, index, array) {
-
- // Comprobar si para el filtro de estado actual de la traza
- let result = (trace.finishedAt != null && this.filters.status['finished'].selected === true) || (trace.finishedAt === null && this.filters.status['execution'].selected === true);
- result = result && (trace.finishedAt != null && (trace.status === 0 && this.filters.finishedStatus['noErrors'].selected === true) || (trace.status !== 0 && this.filters.finishedStatus['withErrors'].selected === true));
- if (this.filters.dateRange.startDate != null) {
- result = result && moment(trace.executedAt).isAfter(this.filters.dateRange.startDate);
- }
- if (this.filters.dateRange.endDate != null) {
- result = result && moment(trace.executedAt).isBefore(this.filters.dateRange.endDate);
- }
-
- return result;
- }
-
-
- filteredTraces() {
- const self = this;
- return this.traces.filter(function(trace, index, array) {
- return self.filterTraceStatus(trace, index, array);
- });
- }
-
- getTraceCssClass(trace: any) {
- let result = '';
- if (!trace.finishedAt) {
- result = 'fa-warning text-yellow';
- }
- if (trace.status === 0) {
- result += ' fa-check-circle text-green';
- } else {
- result += ' fa-times-circle text-red';
- }
- return result;
- }
-}
+import {Component, OnDestroy, OnInit} from '@angular/core';
+
+import { TraceService } from 'src/app/api/trace.service';
+import { Trace } from 'src/app/model/trace';
+import {ToasterService} from '../../service/toaster.service';
+import {OgSweetAlertService} from '../../service/og-sweet-alert.service';
+import {Router} from '@angular/router';
+import {OgCommonService} from '../../service/og-common.service';
+import {environment} from '../../../environments/environment';
+import {TranslateService} from '@ngx-translate/core';
+import {QueryOptions} from 'globunet-angular/core/providers/api/query-options';
+import {forkJoin} from 'rxjs';
+
+import * as moment from 'moment';
+
+@Component({
+ selector: 'app-trace',
+ templateUrl: './trace.component.html',
+ styleUrls: [ './trace.component.scss' ]
+})
+export class TraceComponent implements OnInit, OnDestroy {
+ public traces = [];
+ public selection = [];
+ public searchText = '';
+ public filters = {
+ searchText: '',
+ status: {
+ 'finished': {
+ name: 'finished',
+ selected: true
+ },
+ 'execution': {
+ name: 'execution',
+ selected: true
+ }
+ },
+ finishedStatus: {
+ 'noErrors': {
+ name: 'no-errors',
+ selected: true
+ },
+ 'withErrors': {
+ name: 'with-errors',
+ selected: true
+ },
+ },
+ dateRange: {
+ startDate: null,
+ endDate: null
+ }
+ };
+ config: { constants: any; timers: any; };
+
+ private datePickerOptions: { timePickerIncrement: number; timePicker: boolean; format: string; timePicker24Hour: boolean; locale: { fromLabel: any; toLabel: any; cancelLabel: any; firstDay: number; applyLabel: any; format: string; daysOfWeek: any[]; separator: string; customRangeLabel: any; weekLabel: string; monthNames: any[] } };
+ private selectAll: any;
+ private executionTasks: Trace[];
+ public showInfo: string;
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(public traceService: TraceService,
+ private ogCommonService: OgCommonService,
+ private router: Router,
+ private ogSweetAlert: OgSweetAlertService,
+ private toaster: ToasterService,
+ private translate: TranslateService) {
+ }
+
+ ngOnDestroy() {
+ if (this.config.timers && this.config.timers.executionsInterval) {
+ clearInterval(this.config.timers.executionsInterval.object);
+ }
+ }
+
+ngOnInit(): void {
+ const self = this;
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.config = data;
+
+ if (this.config.timers.executionsInterval.object === null && this.config.timers.executionsInterval.tick > 0) {
+ this.config.timers.executionsInterval.object = setInterval(function() {
+ self.getExecutionTasks();
+ }, this.config.timers.executionsInterval.tick);
+ }
+
+ this.datePickerOptions = {
+ 'locale': {
+ 'format': 'DD/MM/YYYY HH:mm',
+ 'separator': ' - ',
+ 'applyLabel': this.translate.instant('apply'),
+ 'cancelLabel': this.translate.instant('cancel'),
+ 'fromLabel': this.translate.instant('from'),
+ 'toLabel': this.translate.instant('to'),
+ 'customRangeLabel': this.translate.instant('custom_range'),
+ 'weekLabel': 'W',
+ 'daysOfWeek': [
+ this.translate.instant('sun'),
+ this.translate.instant('mon'),
+ this.translate.instant('tue'),
+ this.translate.instant('wed'),
+ this.translate.instant('thu'),
+ this.translate.instant('fri'),
+ this.translate.instant('sat')
+ ],
+ 'monthNames': [
+ this.translate.instant('january'),
+ this.translate.instant('february'),
+ this.translate.instant('march'),
+ this.translate.instant('april'),
+ this.translate.instant('may'),
+ this.translate.instant('june'),
+ this.translate.instant('july'),
+ this.translate.instant('august'),
+ this.translate.instant('september'),
+ this.translate.instant('october'),
+ this.translate.instant('november'),
+ this.translate.instant('december')
+ ],
+ 'firstDay': 1
+ },
+ timePicker: true,
+ timePickerIncrement: 30,
+ timePicker24Hour: true,
+ format: 'DD/MM/YYYY HH:mm'
+ };
+ this.traceService.list().subscribe(
+ (response) => {
+ this.traces = response;
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+ );
+}
+
+
+ selectTrace(trace) {
+ const index = this.selection.indexOf(trace);
+ if (trace.selected === true && index === -1) {
+ this.selection.push(trace);
+ } else if (trace.selected === false && index !== -1) {
+ this.selection.splice(index, 1);
+ }
+ }
+
+ selectAllTraces() {
+ const filter = this.traces.filter(function(trace: Trace) {
+ return true;
+ });
+ for (let index = 0; index < filter.length; index++) {
+ filter[index].selected = this.selectAll;
+ this.selectTrace(filter[index]);
+ }
+ }
+
+ relaunchTraces() {
+
+ }
+
+ deleteTraces() {
+ const self = this;
+ this.ogSweetAlert.question( this.translate.instant('sure_to_delete') + '?', this.translate.instant('action_cannot_be_undone'), function(response) {
+ const promises = [];
+ for (let index = 0; index < self.selection.length; index++) {
+ promises.push(self.traceService.delete(self.selection[index].id));
+ }
+ forkJoin(promises).subscribe(
+ (success) => {
+ self.toaster.pop({type: 'success', title: 'success', body: self.translate.instant('successfully_deleted')});
+ self.selectAll = false;
+ self.selection = [];
+ self.searchText = '';
+ },
+ (error) => {
+ self.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ });
+ }
+
+ getExecutionTasks() {
+ this.traceService.list(new QueryOptions({finished: 0})).subscribe(
+ (result) => {
+ this.executionTasks = result;
+ },
+ (error) => {
+
+ }
+ );
+ }
+
+ deleteExecutionTace(task) {
+ this.ogSweetAlert.question(
+ this.translate.instant('delete_task'),
+ this.translate.instant('sure_to_delete_task') + '?',
+ function(result) {
+ if (result) {
+ this.traceService.delete(task.id).subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_deleted')});
+ this.getExecutionTasks();
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+
+ }
+ }
+ );
+
+ }
+
+ relaunchExecutionTask(task) {
+ this.ogSweetAlert.question(
+ this.translate.instant('relaunch_task'),
+ this.translate.instant('sure_to_relaunch_task') + '?',
+ function(result) {
+ if (result) {
+
+ }
+ }
+ );
+ }
+
+ filterTraceStatus(trace, index, array) {
+
+ // Comprobar si para el filtro de estado actual de la traza
+ let result = (trace.finishedAt != null && this.filters.status['finished'].selected === true) || (trace.finishedAt === null && this.filters.status['execution'].selected === true);
+ result = result && (trace.finishedAt != null && (trace.status === 0 && this.filters.finishedStatus['noErrors'].selected === true) || (trace.status !== 0 && this.filters.finishedStatus['withErrors'].selected === true));
+ if (this.filters.dateRange.startDate != null) {
+ result = result && moment(trace.executedAt).isAfter(this.filters.dateRange.startDate);
+ }
+ if (this.filters.dateRange.endDate != null) {
+ result = result && moment(trace.executedAt).isBefore(this.filters.dateRange.endDate);
+ }
+
+ return result;
+ }
+
+
+ filteredTraces() {
+ const self = this;
+ return this.traces.filter(function(trace, index, array) {
+ return self.filterTraceStatus(trace, index, array);
+ });
+ }
+
+ getTraceCssClass(trace: any) {
+ let result = '';
+ if (!trace.finishedAt) {
+ result = 'fa-warning text-yellow';
+ }
+ if (trace.status === 0) {
+ result += ' fa-check-circle text-green';
+ } else {
+ result += ' fa-times-circle text-red';
+ }
+ return result;
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/serializer/image.serializer.ts b/admin/WebConsole3/frontend/src/app/serializer/image.serializer.ts
index f6004e6a..c2043805 100644
--- a/admin/WebConsole3/frontend/src/app/serializer/image.serializer.ts
+++ b/admin/WebConsole3/frontend/src/app/serializer/image.serializer.ts
@@ -1,5 +1,16 @@
-import { Serializer } from "globunet-angular/core/providers/api/serializer";
-
-export class ImageSerializer extends Serializer {
-
-} \ No newline at end of file
+import { Serializer } from 'globunet-angular/core/providers/api/serializer';
+import {Image} from '../model/image';
+
+export class ImageSerializer extends Serializer {
+
+ toJson(resource: Image): any {
+ const image: any = Object.assign({}, resource);
+ if (image.client && image.client.id) {
+ image.client = image.client.id;
+ }
+ if (image.repository && image.repository.id) {
+ image.repository = image.repository.id;
+ }
+ return super.toJson(image);
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts b/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts
index 7ea08bb8..1ea33faa 100644
--- a/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts
+++ b/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts
@@ -1,236 +1,235 @@
-import {ToasterService} from './toaster.service';
-import {OgSweetAlertService} from './og-sweet-alert.service';
-import {CommandService} from '../api/command.service';
-import {OgCommonService} from './og-common.service';
-import {TranslateService} from '@ngx-translate/core';
-import {Router} from '@angular/router';
-import {Injectable} from '@angular/core';
-import * as _ from 'lodash';
-import {environment} from '../../environments/environment';
-
-@Injectable({
- providedIn: 'root'
-})
-export class OGCommandsService {
- public ogInstructions = '';
- public execution: any;
- private commands = [];
-
- constructor(private router: Router, private ogCommonService: OgCommonService, private toaster: ToasterService, private ogSweetAlert: OgSweetAlertService, private commandService: CommandService, private translate: TranslateService) {
- this.execution = {};
- this.ogCommonService.loadEngineConfig().subscribe(
- (response) => {
- this.commands = response.constants.commandtypes;
- }
- );
- }
-
- sendCommand() {
- let result = true;
- // TODO - Comprobar parametros
- if (!this.execution.script) {
- result = false;
- this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('command_not_valid')});
- } else if (!this.execution.clients) {
- result = false;
- this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('not_clients_selected')});
- }
- // Si no hubo ningun error
- if (result === true) {
- this.execution.script = this.execution.script.replace(/\"/g, '\\"').replace(/\$/g, '\\\$');
- // Resetar las instrucciones del script opengnsys almacenadas.
- this.ogInstructions = '';
- this.commandService.execute(this.execution).subscribe(
- (response: any[]) => {
- // Buscar en la respuesta si hay algún statuscode diferente de 200
- const errors = response.filter(function(value) {
- return (value.statusCode && value.statusCode !== '!200');
- } );
- let errorStr = '';
- let toasterOpts = {type: 'success', title: 'success', body: this.translate.instant('successfully_executed')};
- if (errors.length > 0) {
- for (let e = 0; e < errors.length; e++) {
- errorStr += this.translate.instant('execution_failed_in') + ' ' + errors[e].name + '\n';
- }
-
- toasterOpts = {type: 'error', title: 'error', body: errorStr};
- }
- this.toaster.pop(toasterOpts);
- this.router.navigate(['/app/ous']);
- },
- (error) => {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- }
- }
-
- execute(command, params?) {
-
- this.execution.type = command;
-
- if (command === 'HISTORY_LOG') {
- let clientIp = null;
- // Abrir ventana de log
- if (typeof params === 'undefined' || typeof params.clientIp === 'undefined') {
- const client = this.ogCommonService.selectedClients[Object.keys(this.ogCommonService.selectedClients)[0]];
- if (client) {
- clientIp = client.ip;
- }
- } else {
- clientIp = params.clientIp;
- }
-
- if (clientIp) {
- const url = 'http://' + clientIp + environment.commands.HISTORY_LOG;
- window.open(url, '', 'resizable=yes,toolbar=no,status=no,location=no,menubar=no,scrollbars=yes');
- }
- } else if (command === 'REALTIME_LOG') {
- let clientIp = null;
- // Abrir ventana de log
- if (typeof params === 'undefined' || typeof params.clientIp === 'undefined') {
- const client = this.ogCommonService.selectedClients[Object.keys(this.ogCommonService.selectedClients)[0]];
- if (client) {
- clientIp = client.ip;
- }
- } else {
- clientIp = params.clientIp;
- }
-
- if (clientIp) {
- const url = 'http://' + clientIp + environment.commands.REALTIME_LOG;
- window.open(url, '', 'resizable=yes,toolbar=no,status=no,location=no,menubar=no,scrollbars=yes');
- }
- } else if (command === 'SOFTWARE_INVENTORY') {
- const client = this.ogCommonService.selectedClients[Object.keys(this.ogCommonService.selectedClients)[0]];
- // Preparar el scope para el sweet alert
- const options = {
- scope: {
- partitions: [],
- selectedPart: null
- }
- };
-
- // Comprobar tipo de cada particion para ver si es clonable
- // var parttable = $rootScope.constants.partitiontable[client.partitions[0].partitionCode-1];
- // buscar las particiones que sean clonables
- for (let index = 1; index < client.partitions.length; index++) {
- if (client.partitions[index].osName !== 'DATA' && client.partitions[index].osName !== '') {
- // Crear como nombre para mostrar, el disco y partición del sistema
- const obj = Object.assign({}, client.partitions[index]);
- obj.name = 'disco: ' + obj.numDisk + ', part: ' + obj.numPartition + ', SO: ' + client.partitions[index].osName;
- options.scope.partitions.push(obj);
- }
- }
-
- this.ogSweetAlert.swal({
- title: this.translate.instant('select_partition_to_inventary'),
- // text: $filter("translate")("action_cannot_be_undone"),
- type: 'info',
- input: 'select',
- inputOptions: options.scope.partitions,
- showCancelButton: true,
- confirmButtonColor: '#3c8dbc',
- confirmButtonText: this.translate.instant('done'),
- closeOnConfirm: true
- }).then(
- function(result) {
- if (result.value) {
- // Montar el script con el disco y partición elegida
- this.execution.script = this.commands.SOFTWARE_INVENTORY + ' ' + result.value;
- this.loadClients();
- this.sendCommand();
- }
- },
- null);
- } else {
- if (command === 'REBOOT') {
- this.execution.script = environment.commands.REBOOT;
- } else if (command === 'POWER_OFF') {
- this.execution.script = environment.commands.POWER_OFF;
- } else if (command === 'POWER_ON') {
- this.execution.script = 'wakeonlan';
- } else if (command === 'HARDWARE_INVENTORY') {
- this.execution.script = environment.commands.HARDWARE_INVENTORY;
- } else if (command === 'RUN_SCRIPT') {
- this.execution.script = params ? (params.script || this.ogInstructions) : this.ogInstructions;
- } else if (command === 'REFRESH_INFO') {
- this.execution.script = environment.commands.REFRESH_INFO;
- }
-
- // Comprobar si en los parametros viene la opcion de guardar
- if (typeof params !== 'undefined' && params.save === true) {
- const self = this;
- // Mostrar cuadro de dialogo para guardar procedimiento
- this.ogSweetAlert.swal({
- title: this.translate.instant('new_command_name'),
- type: 'info',
- html:
- '<form style="text-align: left; padding-left: 10px">\
- <div class="form-group">\
- <label for="execute" translate="execute">\
- </label>\
- <div class="checkbox clip-check check-primary checkbox-inline">\
- <input id="execute" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" />\
- </div>\
- </div>\
- <div class="form-group">\
- <label translate="title"></label>\
- <input type="text" class="form-control" id="command.title" />\
- </div>\
- <div class="form-group">\
- <label for="parameters" translate="parameters"></label>\
- <div class="checkbox clip-check check-primary checkbox-inline">\
- <input id="parameters" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" />\
- </div>\
- <p class="help-block" translate="help_command_parameters"></p>\
- </div>\
- </form>',
- showCancelButton: true,
- confirmButtonColor: '#3c8dbc',
- confirmButtonText: this.translate.instant('done'),
- closeOnConfirm: true,
- preConfirm: () => {
- return {
- execute: (<HTMLInputElement>document.getElementById('execute')).value,
- command: {
- title: (<HTMLInputElement>document.getElementById('command.title')).value,
- parameters: (<HTMLInputElement>document.getElementById('parameters')).value
- }
- };
- }
- }).then(
- function(response) {
- if (response.value) {
- response.value.command.script = this.execution.script;
- response.value.command.type = this.execution.type;
- self.commandService.create(response.value.command).subscribe(
- (success) => {
- // Si se seleccionó continuar con la ejecución
- if (response.value.execute) {
- self.loadClients();
- self.sendCommand();
- } else {
- self.router.navigate(['app/commands']);
- }
- },
- (error) => {
- self.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- }
- });
- } else {
- this.loadClients();
- this.sendCommand();
- }
- }
- }
-
- loadClients() {
- if (this.ogCommonService.selectedClients) {
- this.execution.clients = _.join(Object.keys(this.ogCommonService.selectedClients));
- }
- }
-
-}
+import {ToasterService} from './toaster.service';
+import {OgSweetAlertService} from './og-sweet-alert.service';
+import {CommandService} from '../api/command.service';
+import {OgCommonService} from './og-common.service';
+import {TranslateService} from '@ngx-translate/core';
+import {Router} from '@angular/router';
+import {Injectable} from '@angular/core';
+import * as _ from 'lodash';
+import {environment} from '../../environments/environment';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class OGCommandsService {
+ public ogInstructions = '';
+ public execution: any;
+ private commands: any;
+
+ constructor(private router: Router, private ogCommonService: OgCommonService, private toaster: ToasterService, private ogSweetAlert: OgSweetAlertService, private commandService: CommandService, private translate: TranslateService) {
+ this.execution = {};
+ this.commands = environment.commands;
+ }
+
+ sendCommand() {
+ let result = true;
+ // TODO - Comprobar parametros
+ if (!this.execution.script) {
+ result = false;
+ this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('command_not_valid')});
+ } else if (!this.execution.clients) {
+ result = false;
+ this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('not_clients_selected')});
+ }
+ // Si no hubo ningun error
+ if (result === true) {
+ this.execution.script = this.execution.script.replace(/\"/g, '\\"').replace(/\$/g, '\\\$');
+ // Resetar las instrucciones del script opengnsys almacenadas.
+ this.ogInstructions = '';
+ this.commandService.execute(this.execution).subscribe(
+ (response: any[]) => {
+ // Buscar en la respuesta si hay algún statuscode diferente de 200
+ const errors = response.filter(function(value) {
+ return (value.statusCode && value.statusCode !== '!200');
+ } );
+ let errorStr = '';
+ let toasterOpts = {type: 'success', title: 'success', body: this.translate.instant('successfully_executed')};
+ if (errors.length > 0) {
+ for (let e = 0; e < errors.length; e++) {
+ errorStr += this.translate.instant('execution_failed_in') + ' ' + errors[e].name + '\n';
+ }
+
+ toasterOpts = {type: 'error', title: 'error', body: errorStr};
+ }
+ this.toaster.pop(toasterOpts);
+ this.router.navigate(['/app/ous']);
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+ }
+
+ execute(command, params?) {
+
+ this.execution.type = command;
+
+ if (command === 'HISTORY_LOG') {
+ let clientIp = null;
+ // Abrir ventana de log
+ if (typeof params === 'undefined' || typeof params.clientIp === 'undefined') {
+ const client = this.ogCommonService.selectedClients[Object.keys(this.ogCommonService.selectedClients)[0]];
+ if (client) {
+ clientIp = client.ip;
+ }
+ } else {
+ clientIp = params.clientIp;
+ }
+
+ if (clientIp) {
+ const url = 'http://' + clientIp + environment.commands.HISTORY_LOG;
+ window.open(url, '', 'resizable=yes,toolbar=no,status=no,location=no,menubar=no,scrollbars=yes');
+ }
+ } else if (command === 'REALTIME_LOG') {
+ let clientIp = null;
+ // Abrir ventana de log
+ if (typeof params === 'undefined' || typeof params.clientIp === 'undefined') {
+ const client = this.ogCommonService.selectedClients[Object.keys(this.ogCommonService.selectedClients)[0]];
+ if (client) {
+ clientIp = client.ip;
+ }
+ } else {
+ clientIp = params.clientIp;
+ }
+
+ if (clientIp) {
+ const url = 'http://' + clientIp + environment.commands.REALTIME_LOG;
+ window.open(url, '', 'resizable=yes,toolbar=no,status=no,location=no,menubar=no,scrollbars=yes');
+ }
+ } else if (command === 'SOFTWARE_INVENTORY') {
+ const client = this.ogCommonService.selectedClients[Object.keys(this.ogCommonService.selectedClients)[0]];
+ // Preparar el scope para el sweet alert
+ const options = {
+ scope: {
+ partitions: [],
+ selectedPart: null
+ }
+ };
+
+ // Comprobar tipo de cada particion para ver si es clonable
+ // var parttable = $rootScope.constants.partitiontable[client.partitions[0].partitionCode-1];
+ // buscar las particiones que sean clonables
+ const clonablePartitions = [];
+ for (let index = 1; index < client.partitions.length; index++) {
+ if (client.partitions[index].osName !== 'DATA' && client.partitions[index].osName !== '') {
+ // Crear como nombre para mostrar, el disco y partición del sistema
+ const obj = Object.assign({}, client.partitions[index]);
+ const str = 'disco: ' + obj.numDisk + ', part: ' + obj.numPartition + ', SO: ' + client.partitions[index].osName;
+ clonablePartitions.push(obj.numDisk + ' ' + obj.numPartition)
+ options.scope.partitions.push(str);
+ }
+ }
+
+ const self = this;
+
+ this.ogSweetAlert.swal({
+ title: this.translate.instant('select_partition_to_inventary'),
+ // text: $filter("translate")("action_cannot_be_undone"),
+ type: 'info',
+ input: 'select',
+ inputOptions: options.scope.partitions,
+ showCancelButton: true,
+ confirmButtonColor: '#3c8dbc',
+ confirmButtonText: this.translate.instant('done'),
+ closeOnConfirm: true
+ }).then(
+ function(result) {
+ if (result.value) {
+ // Montar el script con el disco y partición elegida
+ self.execution.script = self.commands.SOFTWARE_INVENTORY + ' ' + clonablePartitions[result.value];
+ self.loadClients();
+ self.sendCommand();
+ }
+ },
+ null);
+ } else {
+ if (command === 'REBOOT') {
+ this.execution.script = environment.commands.REBOOT;
+ } else if (command === 'POWER_OFF') {
+ this.execution.script = environment.commands.POWER_OFF;
+ } else if (command === 'POWER_ON') {
+ this.execution.script = 'wakeonlan';
+ } else if (command === 'HARDWARE_INVENTORY') {
+ this.execution.script = environment.commands.HARDWARE_INVENTORY;
+ } else if (command === 'RUN_SCRIPT') {
+ this.execution.script = params ? (params.script || this.ogInstructions) : this.ogInstructions;
+ } else if (command === 'REFRESH_INFO') {
+ this.execution.script = environment.commands.REFRESH_INFO;
+ }
+
+ // Comprobar si en los parametros viene la opcion de guardar
+ if (typeof params !== 'undefined' && params.save === true) {
+ const self = this;
+ // Mostrar cuadro de dialogo para guardar procedimiento
+ this.ogSweetAlert.swal({
+ title: this.translate.instant('new_command_name'),
+ type: 'info',
+ html:
+ '<form style="text-align: left; padding-left: 10px">\
+ <div class="form-group">\
+ <label for="execute">' + this.translate.instant('execute') + '</label>\
+ <div class="checkbox clip-check check-primary checkbox-inline">\
+ <input id="execute" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" />\
+ </div>\
+ </div>\
+ <div class="form-group">\
+ <label>' + this.translate.instant('title') + '</label>\
+ <input type="text" class="form-control" id="command.title" />\
+ </div>\
+ <div class="form-group">\
+ <label for="parameters">' + this.translate.instant('parameters') + '</label>\
+ <div class="checkbox clip-check check-primary checkbox-inline">\
+ <input id="parameters" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" />\
+ </div>\
+ <p class="help-block">' + this.translate.instant('help_command_parameters') + '</p>\
+ </div>\
+ </form>',
+ showCancelButton: true,
+ confirmButtonColor: '#3c8dbc',
+ confirmButtonText: this.translate.instant('done'),
+ closeOnConfirm: true,
+ preConfirm: () => {
+ return {
+ execute: (<HTMLInputElement>document.getElementById('execute')).checked,
+ command: {
+ title: (<HTMLInputElement>document.getElementById('command.title')).value,
+ parameters: (<HTMLInputElement>document.getElementById('parameters')).checked
+ }
+ };
+ }
+ }).then(
+ function(response) {
+ if (response.value) {
+ response.value.command.script = self.execution.script;
+ response.value.command.type = self.execution.type;
+ self.commandService.create(response.value.command).subscribe(
+ (success) => {
+ // Si se seleccionó continuar con la ejecución
+ if (response.value.execute) {
+ self.loadClients();
+ self.sendCommand();
+ } else {
+ self.router.navigate(['app/commands']);
+ }
+ },
+ (error) => {
+ self.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+ });
+ } else {
+ this.loadClients();
+ this.sendCommand();
+ }
+ }
+ }
+
+ loadClients() {
+ if (this.ogCommonService.selectedClients) {
+ this.execution.clients = _.join(Object.keys(this.ogCommonService.selectedClients));
+ }
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/service/og-common.service.ts b/admin/WebConsole3/frontend/src/app/service/og-common.service.ts
index ee5a8a9d..b529199d 100644
--- a/admin/WebConsole3/frontend/src/app/service/og-common.service.ts
+++ b/admin/WebConsole3/frontend/src/app/service/og-common.service.ts
@@ -26,10 +26,13 @@ export class OgCommonService {
constructor(private layoutStore: LayoutStore, private adminLteConfig: AdminLteConf, private engineService: EngineService, private translate: TranslateService, private authModule: AuthModule) {
this.app = {};
- this.selectedClients = [];
+ this.selectedClients = {};
this.selectedOu = null;
this.movingOu = null;
this.movingClients = false;
+ if (localStorage.getItem('selectedClients')) {
+ this.selectedClients = JSON.parse(localStorage.getItem('selectedClients'));
+ }
}
loadEngineConfig(): Observable<{constants: any, timers: any}> {
@@ -42,21 +45,23 @@ export class OgCommonService {
ou: environment.ou,
themes: environment.themes,
menus: environment.menus,
- languages: environment.languages
+ languages: environment.languages,
+ deployMethods: environment.deployMethods,
+ commands: environment.commands
};
this.constants = Object.assign(this.constants, data[0]);
// inicializar timers generales para refresco de información
this.timers = {
serverStatusInterval: {
- tick: 5000,
+ tick: 0,
object: null
},
clientsStatusInterval: {
- tick: 5000,
+ tick: 0,
object: null
},
executionsInterval: {
- tick: 5000,
+ tick: 0,
object: null
},
@@ -189,6 +194,19 @@ export class OgCommonService {
} else {
delete this.selectedClients[client.id];
}
+ this.saveSelection();
+ }
+
+ saveSelection() {
+ if (Object.keys(this.selectedClients).length > 0) {
+ localStorage.setItem('selectedClients', JSON.stringify(this.selectedClients, function (key, value) {
+ let result = value;
+ if (key === 'parent' && typeof value === 'object') {
+ result = value.id;
+ }
+ return result;
+ }));
+ }
}
getSelectionSize() {
diff --git a/admin/WebConsole3/frontend/src/assets/i18n/es.json b/admin/WebConsole3/frontend/src/assets/i18n/es.json
index dfc609c3..7427ea51 100644
--- a/admin/WebConsole3/frontend/src/assets/i18n/es.json
+++ b/admin/WebConsole3/frontend/src/assets/i18n/es.json
@@ -110,7 +110,7 @@
"images_info": "Info imágenes",
"imageUrl": "Url imagen",
"info": "Información",
- "initializing": "Opengnsys",
+ "initializing": "Inicializando",
"invalid_login": "Usuario o contraseña no válido",
"ip": "Ip",
"january": "Enero",
diff --git a/admin/WebConsole3/frontend/src/environments/environment.ts b/admin/WebConsole3/frontend/src/environments/environment.ts
index fcc0dcba..ef17e26d 100644
--- a/admin/WebConsole3/frontend/src/environments/environment.ts
+++ b/admin/WebConsole3/frontend/src/environments/environment.ts
@@ -9,8 +9,8 @@ export const environment = {
API_PUBLIC_URL: url + '/api',
API_BASE_URL: '/backend/web/app_dev.php/api',
OAUTH_DOMAIN: '/backend/web/app_dev.php/oauth/v2/token',
- OAUTH_CLIENT_ID: '1_23amzbdp4kskg80444oscko4w0w8wokocs88k0g8w88o4oggs4',
- OAUTH_CLIENT_SECRET: '46rttt2trwo4gocgoc4w80k4s8ok48sg8s84kk0cw48csks8o8',
+ OAUTH_CLIENT_ID: 'CLIENTID',
+ OAUTH_CLIENT_SECRET: 'CLIENTSECRET',
BASE_DIR: 'opengnsys3',
clientstatus: ['off', 'initializing', 'oglive', 'busy', 'linux', 'linux_session', 'macos', 'windows', 'windows_session'],
windowsboots: ['reboot', 'directo (kexec)'],
diff --git a/admin/WebConsole3/frontend/src/styles.scss b/admin/WebConsole3/frontend/src/styles.scss
index 57a04153..b0a5eaec 100644
--- a/admin/WebConsole3/frontend/src/styles.scss
+++ b/admin/WebConsole3/frontend/src/styles.scss
@@ -1,4 +1,8 @@
/* You can add global styles to this file, and also import other style files */
+.input-group {
+ width: 100%;
+}
+
.capitalize {
text-transform: capitalize;
}
@@ -15,6 +19,14 @@ table.table-no-border {
border: none;
}
+.loader {
+ position: absolute;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 999999;
+}
+
#loading-bar .bar {
background: white;
}
@@ -96,8 +108,7 @@ i.client {
}
.bg-lab{
- background-color: #d7dbef;
- padding: 10px 10px 0 10px;
+ background-color: #d7dbef !important;
}
tr.odd {
@@ -178,7 +189,7 @@ table.disk-partitions td {
}
table.disk-partitions td span {
- padding: 5px 10px;
+ padding: 5px 5px;
font-weight: bold;
}
@@ -302,3 +313,7 @@ ul.dropdown-menu.fit {
ng2-smart-table {
font-size: initial !important;
}
+
+.swal2-popup {
+ font-size: 1em !important;
+}
diff --git a/client/boot-tools/boottoolsfunctions.lib b/client/boot-tools/boottoolsfunctions.lib
index f364f174..7f7bbb38 100755
--- a/client/boot-tools/boottoolsfunctions.lib
+++ b/client/boot-tools/boottoolsfunctions.lib
@@ -116,13 +116,20 @@ case "${1,,}" in
OSARCH="amd64"
OSHTTP="http://es.archive.ubuntu.com/ubuntu/"
;;
- bionic) # ogLive 1.1.1-rc1 basado en Ubuntu 18.04 y Kernel 4.15.
+ bionic|bionic-4.15) # ogLive 1.1.1-rc1 basado en Ubuntu 18.04 y Kernel 4.15.
OSDISTRIB="ubuntu"
OSCODENAME="bionic"
OSRELEASE="4.15.0-32-generic"
OSARCH="amd64"
OSHTTP="http://es.archive.ubuntu.com/ubuntu/"
;;
+ bionic-4.18) # ogLive 1.1.1-rc3 basado en Ubuntu 18.04 y Kernel 4.18.
+ OSDISTRIB="ubuntu"
+ OSCODENAME="bionic"
+ OSRELEASE="4.18.0-17-generic"
+ OSARCH="amd64"
+ OSHTTP="http://es.archive.ubuntu.com/ubuntu/"
+ ;;
host) # ogLive basado en la distribución del servidor.
OSDISTRIB=$(lsb_release -is)
OSCODENAME=$(lsb_release -cs)
diff --git a/client/boot-tools/includes/etc/initramfs-tools/scripts/VERSION.txt b/client/boot-tools/includes/etc/initramfs-tools/scripts/VERSION.txt
index 45805bd6..bc92b96f 100644
--- a/client/boot-tools/includes/etc/initramfs-tools/scripts/VERSION.txt
+++ b/client/boot-tools/includes/etc/initramfs-tools/scripts/VERSION.txt
@@ -1 +1 @@
-OpenGnsys Client 1.1.1-rc2
+OpenGnsys Client 1.1.1-rc3
diff --git a/client/boot-tools/includes/usr/bin/boot-tools/listpackages/sw.basic b/client/boot-tools/includes/usr/bin/boot-tools/listpackages/sw.basic
index afd8ff4c..31f2b559 100644
--- a/client/boot-tools/includes/usr/bin/boot-tools/listpackages/sw.basic
+++ b/client/boot-tools/includes/usr/bin/boot-tools/listpackages/sw.basic
@@ -9,7 +9,8 @@ install console-data
install locales
install lshw
install gawk
-install subversion
+#install subversion # ogLive anterior a Ubuntu 18.04
+install git # ogLive a partir de Ubuntu 18.04
install python-openssl
install python
#install php5-cli # ogLive anterior a Ubuntu 16.04
diff --git a/client/shared/etc/init/default.sh b/client/shared/etc/init/default.sh
index efc1e035..2fc3ede9 100755
--- a/client/shared/etc/init/default.sh
+++ b/client/shared/etc/init/default.sh
@@ -3,30 +3,32 @@
# Fichero de registro de incidencias (en el servidor; si no, en local).
OPENGNSYS=${OPENGNSYS:-/opt/opengnsys}
-OGLOGFILE=${OGLOGFILE:-$OPENGNSYS/log/$(ogGetIpAddress).log}
+OGLOGFILE=${OGLOGFILE:-$OPENGNSYS/log/$(ogGetIpAdderss).log}
if ! touch $OGLOGFILE 2>/dev/null; then
OGLOGFILE=/var/log/opengnsys.log
fi
LOGLEVEL=5
-# TODO - PRUEBA
-AGENT_FILE="/var/tmp/ogAdmClient"
-touch $AGENT_FILE
-chmod a+wxs $AGENT_FILE
-chown root:root $AGENT_FILE
-# Exportar funciones para comunicacion con el servidor
-sendConfigToServer
-sendStatusToServer "initializing"
-
# Matando plymount para inicir browser o shell
pkill -9 plymouthd
-# Arranque de OpenGnsys Client daemon (socket).
+# Cargar idioma.
echo "${MSG_LAUNCHCLIENT:-.}"
# Indicar fichero de teclado de Qt para el idioma especificado (tipo "es.qmap").
[ -f /usr/local/etc/${LANG%_*}.qmap ] && export QWS_KEYBOARD="TTY:keymap=/usr/local/etc/${LANG%_*}.qmap"
-if [ -x "$OPENGNSYS/bin/ogAdmClient" -a "$ogstatus" != "offline" ]; then
+source /scripts/client.cfg
+VERSION="1.1.1" # TEMPORAL
+if [ -f "$OPENGNSYS/images/ogagent-oglive_${VERSION}_all.deb" -a "$ogstatus" != "offline" ]; then
+ # Instalar, configurar e iniciar agente.
+ dpkg -i "$OPENGNSYS/images/ogagent-oglive_${VERSION}_all.deb"
+ sed -i -e "s,remote=.*,remote=https://$(ogGetServerIp)/opengnsys3/backend/web/app_dev.php/," \
+ -e "s,client=.*,client=$CLIENTID," \
+ -e "s,secret=.*,secret=$CLIENTSECRET," \
+ /usr/share/OGAgent/cfg/ogagent.cfg
+ ogagent start
+ sleep 10
+elif [ -x "$OPENGNSYS/bin/ogAdmClient" -a "$ogstatus" != "offline" ]; then
# Ejecutar servicio cliente.
$OPENGNSYS/bin/ogAdmClient -f $OPENGNSYS/etc/ogAdmClient.cfg -l $OGLOGFILE -d $LOGLEVEL
else
@@ -42,3 +44,4 @@ if [ "$ogactiveadmin" == "true" ]; then
bash
fi
+
diff --git a/client/shared/scripts/poweroff b/client/shared/scripts/poweroff
index 7297cad3..563845b3 100755
--- a/client/shared/scripts/poweroff
+++ b/client/shared/scripts/poweroff
@@ -30,12 +30,10 @@ ethtool -s $DEVICE wol g 2>/dev/null
BUSYBOX=$(which busyboxOLD)
BUSYBOX=${BUSYBOX:-"busybox"}
-# Retardo para dar lugar al registro en cola de acciones.
-sleep 5
-# Parar Browser para evitar "cuelgues".
-[ "$ogstatus" == "offline" ] || pkill browser
+# Parar agente y Browser.
+ogagent stop &>/dev/null
+pkill -9 browser
-sendStatusToServer "off"
# Apagar.
$BUSYBOX poweroff
diff --git a/client/shared/scripts/reboot b/client/shared/scripts/reboot
index 5e6305af..30362cc7 100755
--- a/client/shared/scripts/reboot
+++ b/client/shared/scripts/reboot
@@ -44,12 +44,9 @@ ethtool -s $DEVICE wol g 2>/dev/null
BUSYBOX=$(which busyboxOLD)
BUSYBOX=${BUSYBOX:-"busybox"}
-# Retardo para dar lugar al registro en cola de acciones.
-sleep $TIME
-# Parar Browser para evitar "cuelgues".
-[ "$ogstatus" == "offline" ] || pkill browser
-
-sendStatusToServer "off"
+# Parar agente y Browser.
+ogagent stop &>/dev/null
+pkill -9 browser
# Reiniciar.
$BUSYBOX reboot
diff --git a/installer/opengnsys_installer.sh b/installer/opengnsys_installer.sh
index f559552c..ff2605d8 100755
--- a/installer/opengnsys_installer.sh
+++ b/installer/opengnsys_installer.sh
@@ -9,8 +9,8 @@
#### AVISO: Puede editar configuración de acceso por defecto.
#### WARNING: Edit default access configuration if you wish.
DEFAULT_MYSQL_ROOT_PASSWORD="passwordroot" # Clave por defecto root de MySQL
-DEFAULT_OPENGNSYS_DB_USER="usuog" # Usuario por defecto de acceso a la base de datos
-DEFAULT_OPENGNSYS_DB_PASSWD="passusuog" # Clave por defecto de acceso a la base de datos
+DEFAULT_OPENGNSYS_DB_USER="admin" # Usuario por defecto de acceso a la base de datos
+DEFAULT_OPENGNSYS_DB_PASSWD="admin" # Clave por defecto de acceso a la base de datos
DEFAULT_OPENGNSYS_CLIENT_PASSWD="og" # Clave por defecto de acceso del cliente
# Sólo ejecutable por usuario root
@@ -123,9 +123,8 @@ LOG_FILE=/tmp/$(basename $OGLOGFILE)
# Usuario del cliente para acceso remoto.
OPENGNSYS_CLIENT_USER="opengnsys"
-# Nombre de la base datos y fichero SQL para su creación.
-OPENGNSYS_DATABASE="ogAdmBD"
-OPENGNSYS_DB_CREATION_FILE=opengnsys/admin/Database/${OPENGNSYS_DATABASE}.sql
+# Nombre de la base datos.
+OPENGNSYS_DATABASE="opengnsys"
#####################################################################
@@ -135,7 +134,7 @@ OPENGNSYS_DB_CREATION_FILE=opengnsys/admin/Database/${OPENGNSYS_DATABASE}.sql
# Generar variables de configuración del instalador
# Variables globales:
# - OSDISTRIB, OSVERSION - tipo y versión de la distribución GNU/Linux
-# - DEPENDENCIES - array de dependencias que deben estar instaladas
+# - PREREQS, DEPENDENCIES - arrays de prerrequisitos y dependencias que deben estar instaladas
# - UPDATEPKGLIST, INSTALLPKGS, CHECKPKGS - comandos para gestión de paquetes
# - INSTALLEXTRADEPS - instalar dependencias no incluidas en la distribución
# - STARTSERVICE, ENABLESERVICE - iniciar y habilitar un servicio
@@ -169,9 +168,10 @@ OSVERSION="${OSVERSION%%.*}"
# Configuración según la distribución GNU/Linux (usar minúsculas).
case "$OSDISTRIB" in
ubuntu|debian|linuxmint)
- DEPENDENCIES=( subversion apache2 php php-ldap php-fpm mysql-server php-mysql isc-dhcp-server bittorrent tftp-hpa tftpd-hpa xinetd build-essential g++-multilib libmysqlclient-dev wget curl doxygen graphviz bittornado ctorrent samba rsync unzip netpipes debootstrap schroot squashfs-tools btrfs-tools procps arp-scan realpath php-curl gettext moreutils jq udpcast libev-dev shim-signed grub-efi-amd64-signed )
+ PREREQS=( curl software-properties-common )
+ DEPENDENCIES=( subversion apache2 php php-ldap php-fpm mysql-server php-mysql isc-dhcp-server bittorrent tftp-hpa tftpd-hpa xinetd build-essential g++-multilib libmysqlclient-dev wget doxygen graphviz bittornado ctorrent samba rsync unzip netpipes debootstrap schroot squashfs-tools btrfs-tools procps arp-scan realpath php-curl gettext moreutils jq udpcast libev-dev shim-signed grub-efi-amd64-signed git php-mbstring php-xml nodejs debhelper )
UPDATEPKGLIST="apt-get update"
- INSTALLPKG="apt-get -y install --force-yes"
+ INSTALLPKG="apt-get -y install"
CHECKPKG="dpkg -s \$package 2>/dev/null | grep Status | grep -qw install"
if which service &>/dev/null; then
STARTSERVICE="eval service \$service restart"
@@ -188,7 +188,7 @@ case "$OSDISTRIB" in
APACHEOGSITE=opengnsys
APACHEUSER="www-data"
APACHEGROUP="www-data"
- APACHEENABLEMODS="a2enmod ssl rewrite proxy_fcgi fastcgi actions alias"
+ APACHEENABLEMODS="a2enmod ssl rewrite proxy_fcgi actions alias"
APACHEENABLESSL="a2ensite default-ssl"
APACHEENABLEOG="a2ensite $APACHEOGSITE"
APACHEMAKECERT="make-ssl-cert generate-default-snakeoil --force-overwrite"
@@ -206,7 +206,8 @@ case "$OSDISTRIB" in
TFTPCFGDIR=/var/lib/tftpboot
;;
fedora|centos)
- DEPENDENCIES=( subversion httpd mod_ssl php-ldap php-fpm mysql-server mysql-devel mysql-devel.i686 php-mysql dhcp tftp-server tftp xinetd binutils gcc gcc-c++ glibc-devel glibc-devel.i686 glibc-static glibc-static.i686 libstdc++-devel.i686 make wget curl doxygen graphviz ctorrent samba samba-client rsync unzip debootstrap schroot squashfs-tools python-crypto arp-scan procps-ng gettext moreutils jq net-tools udpcast libev-devel shim-x64 grub2-efi-x64 grub2-efi-x64-modules http://ftp.altlinux.org/pub/distributions/ALTLinux/5.1/branch/$(arch)/RPMS.classic/netpipes-4.2-alt1.$(arch).rpm )
+ PREREQS=( curl )
+ DEPENDENCIES=( subversion httpd mod_ssl php-ldap php-fpm mysql-server mysql-devel mysql-devel.i686 php-mysql dhcp tftp-server tftp xinetd binutils gcc gcc-c++ glibc-devel glibc-devel.i686 glibc-static glibc-static.i686 libstdc++-devel.i686 make wget doxygen graphviz ctorrent samba samba-client rsync unzip debootstrap schroot squashfs-tools python-crypto arp-scan procps-ng gettext moreutils jq net-tools udpcast libev-devel shim-x64 grub2-efi-x64 grub2-efi-x64-modules http://ftp.altlinux.org/pub/distributions/ALTLinux/5.1/branch/$(arch)/RPMS.classic/netpipes-4.2-alt1.$(arch).rpm )
[ "$OSDISTRIB" == "centos" ] && UPDATEPKGLIST="yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-$OSVERSION.noarch.rpm http://rpms.remirepo.net/enterprise/remi-release-$OSVERSION.rpm"
INSTALLEXTRADEPS=( 'pushd /tmp; wget -t3 http://ftp.acc.umu.se/mirror/bittornado/BitTornado-0.3.18.tar.gz && tar xvzf BitTornado-0.3.18.tar.gz && cd BitTornado-CVS && python setup.py install && ln -fs btlaunchmany.py /usr/bin/btlaunchmany && ln -fs bttrack.py /usr/bin/bttrack; popd' )
INSTALLPKG="yum install -y libstdc++ libstdc++.i686"
@@ -248,6 +249,10 @@ case "$OSDISTRIB" in
*) echo "ERROR: Distribution not supported by OpenGnsys."
exit 1 ;;
esac
+# Instalar Composer y Angular-CLI.
+INSTALLEXTRADEPS=( ${INSTALLEXTRADEPS[@]} \
+ 'if [ ! -f /usr/local/bin/composer.phar ]; then php -r "copy(\"https://getcomposer.org/installer\", \"/tmp/composer-setup.php\");"; php /tmp/composer-setup.php --install-dir=/usr/local/bin; rm -f /tmp/composer-setup.php; else /usr/local/bin/composer.phar self-update; fi' \
+ 'npm install -g @angular/cli@6.2.3' )
# Fichero de credenciales de acceso a MySQL.
TMPMYCNF=/tmp/.my.cnf.$$
@@ -257,8 +262,6 @@ TMPMYCNF=/tmp/.my.cnf.$$
# Modificar variables de configuración tras instalar paquetes del sistema.
function autoConfigurePost()
{
-local f
-
# Configuraciones específicas para Samba y TFTP en Debian 6.
[ -z "$SYSTEMD" -a ! -e /etc/init.d/$SAMBASERV ] && SAMBASERV=samba
[ ! -e $TFTPCFGDIR ] && TFTPCFGDIR=/srv/tftp
@@ -271,12 +274,14 @@ function updatePackageList()
{
local DHCPVERSION PHP7VERSION
-# Si es necesario, actualizar la lista de paquetes disponibles.
+# Si es necesario, actualizar la lista de paquetes disponibles e instalar prerrequisitos.
[ -n "$UPDATEPKGLIST" ] && eval $UPDATEPKGLIST
+[ ${#PREREQS[@]} -gt 0 ] && eval $INSTALLPKG ${PREREQS[@]}
# Configuración personallizada de algunos paquetes.
case "$OSDISTRIB" in
ubuntu|linuxmint) # Postconfiguación personalizada para Ubuntu.
+ # Instalar prerrequisitos.
# Configuración para DHCP v3.
DHCPVERSION=$(apt-cache show $(apt-cache pkgnames|egrep "dhcp.?-server$") | \
awk '/Version/ {print substr($2,1,1);}' | \
@@ -288,10 +293,9 @@ case "$OSDISTRIB" in
fi
# Configuración para PHP 7 en Ubuntu.
if [ -z "$(apt-cache pkgnames php7)" ]; then
- eval $INSTALLPKG software-properties-common
add-apt-repository -y ppa:ondrej/php
eval $UPDATEPKGLIST
- PHP7VERSION=$(apt-cache pkgnames php7 | sort | head -1)
+ PHP7VERSION=$(apt-cache pkgnames php7. | sort | tail -1)
PHPFPMSERV="${PHP7VERSION}-fpm"
DEPENDENCIES=( ${DEPENDENCIES[@]//php/$PHP7VERSION} )
fi
@@ -299,6 +303,8 @@ case "$OSDISTRIB" in
[ -z "$(apt-cache pkgnames libmysqlclient-dev)" ] && [ -n "$(apt-cache pkgnames libmysqlclient15)" ] && DEPENDENCIES=( ${DEPENDENCIES[@]//libmysqlclient-dev/libmysqlclient15} )
# Paquete correcto para realpath.
[ -z "$(apt-cache pkgnames realpath)" ] && DEPENDENCIES=( ${DEPENDENCIES[@]//realpath/coreutils} )
+ # Instalar NodeJS.
+ curl -sL https://deb.nodesource.com/setup_10.x | bash -
;;
centos) # Postconfiguación personalizada para CentOS.
# Configuración para PHP 7.
@@ -312,12 +318,16 @@ case "$OSDISTRIB" in
# Instalar ctorrent de EPEL para CentOS 6 (no disponible en CentOS 7).
DEPENDENCIES=( ${DEPENDENCIES[*]/ctorrent/http://dl.fedoraproject.org/pub/epel/6/$(arch)/Packages/c/ctorrent-1.3.4-14.dnh3.3.2.el6.$(arch).rpm} )
fi
+ # Instalar NodeJS.
+ curl -sL https://rpm.nodesource.com/setup_10.x | bash -
;;
fedora) # Postconfiguación personalizada para Fedora.
# Incluir paquetes específicos.
DEPENDENCIES=( ${DEPENDENCIES[@]} btrfs-progs )
# Sustituir MySQL por MariaDB a partir de Fedora 20.
[ $OSVERSION -ge 20 ] && DEPENDENCIES=( ${DEPENDENCIES[*]/mysql-/mariadb-} )
+ # Instalar NodeJS.
+ curl -sL https://rpm.nodesource.com/setup_10.x | bash -
;;
esac
}
@@ -725,23 +735,20 @@ function mysqlCreateDb()
# Comprueba si ya está definido el usuario de acceso a la BD.
function mysqlCheckUserExists()
{
- if [ $# -ne 1 ]; then
- errorAndLog "${FUNCNAME}(): invalid number of parameters"
- exit 1
- fi
-
- local userdb="$1"
-
- echoAndLog "${FUNCNAME}(): checking if $userdb exists..."
- echo "select user from user where user='${userdb}'\\G" |mysql --defaults-extra-file=$TMPMYCNF mysql | grep user
- if [ $? -ne 0 ]; then
- echoAndLog "${FUNCNAME}(): user doesn't exists"
- return 1
- else
- echoAndLog "${FUNCNAME}(): user already exists"
- return 0
- fi
+if [ $# -ne 1 ]; then
+ errorAndLog "${FUNCNAME}(): invalid number of parameters"
+ exit 1
+fi
+local userdb="$1"
+echoAndLog "${FUNCNAME}(): checking if $userdb exists..."
+if [ "$(mysql --defaults-extra-file=$TMPMYCNF -Nse "SELECT user FROM mysql.user WHERE user='$userdb'")" == "$userdb" ]; then
+ echoAndLog "${FUNCNAME}(): user already exists"
+ return 0
+else
+ echoAndLog "${FUNCNAME}(): user doesn't exists"
+ return 1
+fi
}
# Crea un usuario administrativo para la base de datos
@@ -810,16 +817,9 @@ function downloadCode()
# Comprobar si existe conexión.
function checkNetworkConnection()
{
- echoAndLog "${FUNCNAME}(): Checking OpenGnsys server connectivity."
- OPENGNSYS_SERVER=${OPENGNSYS_SERVER:-"opengnsys.es"}
- if which wget &>/dev/null; then
- wget --spider -q $OPENGNSYS_SERVER
- elif which curl &>/dev/null; then
- curl --connect-timeout 10 -s $OPENGNSYS_SERVER -o /dev/null
- else
- echoAndLog "${FUNCNAME}(): Cannot execute \"wget\" nor \"curl\"."
- return 1
- fi
+echoAndLog "${FUNCNAME}(): Checking OpenGnsys server connectivity."
+OPENGNSYS_SERVER=${OPENGNSYS_SERVER:-"opengnsys.es"}
+curl --connect-timeout 10 -s $OPENGNSYS_SERVER -o /dev/null
}
# Convierte nº de bits (notación CIDR) en máscara de red (gracias a FriedZombie en openwrt.org).
@@ -1045,37 +1045,67 @@ function dhcpConfigure()
####### Funciones específicas de la instalación de Opengnsys
#####################################################################
-# Copiar ficheros del OpenGnsys Web Console.
+# Instalar OpenGnsys Web Console.
function installWebFiles()
{
- local COMPATDIR f
- local SLIMFILE="slim-2.6.1.zip"
- local SWAGGERFILE="swagger-ui-2.2.5.zip"
-
- echoAndLog "${FUNCNAME}(): Installing web files..."
- # Copiar ficheros.
- cp -a $WORKDIR/opengnsys/admin/WebConsole/* $INSTALL_TARGET/www #*/ comentario para Doxygen.
- if [ $? != 0 ]; then
- errorAndLog "${FUNCNAME}(): Error copying web files."
- exit 1
- fi
+local $tmpdir jsonfile=$INSTALL_TARGET/etc/opengnsys.json
+
+echoAndLog "${FUNCNAME}(): Copying backend files..."
+sed -e "s/ database_name:.*/ database_name: $OPENGNSYS_DATABASE/" \
+ -e "s/ database_user:.*/ database_user: $OPENGNSYS_DB_USER/" \
+ -e "s/ database_password:.*/ database_password: $OPENGNSYS_DB_PASSWD/" \
+ $WORKDIR/opengnsys/admin/WebConsole3/backend/app/config/parameters.yml.dist \
+ > $WORKDIR/opengnsys/admin/WebConsole3/backend/app/config/parameters.yml
+chown -R $OPENGNSYS_CLIENT_USER:$OPENGNSYS_CLIENT_USER $WORKDIR/opengnsys/admin/WebConsole3
+cp -a $WORKDIR/opengnsys/admin/WebConsole3/backend $INSTALL_TARGET/www3
+if [ $? != 0 ]; then
+ errorAndLog "${FUNCNAME}(): Error copying backend files."
+ exit 1
+fi
- # Descomprimir librerías: Slim y Swagger-UI.
- unzip -o $WORKDIR/opengnsys/admin/$SLIMFILE -d $INSTALL_TARGET/www/rest
- unzip -o $WORKDIR/opengnsys/admin/$SWAGGERFILE -d $INSTALL_TARGET/www/rest
+echoAndLog "${FUNCNAME}(): Installing backend framework..."
+pushd $INSTALL_TARGET/www3/backend
+sudo -u $OPENGNSYS_CLIENT_USER composer.phar install
+chmod 777 -R var/cache var/logs
+sudo -u $OPENGNSYS_CLIENT_USER php app/console doctrine:database:create --if-not-exists
+sudo -u $OPENGNSYS_CLIENT_USER php app/console doctrine:schema:update --force
+echo yes | php app/console doctrine:fixtures:load
+php app/console fos:user:create "$OPENGNSYS_DB_USER" "${OPENGNSYS_DB_USER}@localhost.localdomain" "$OPENGNSYS_DB_USER"
+# Guardar tokens de seguridad.
+read -e APIID APISECRET <<< \
+ "$(php app/console doctrine:query:sql "SELECT random_id, secret FROM og_core__clients WHERE id=1;" | \
+ awk -F\" '$2~/^(random_id|secret)$/ {getline; printf("%s ", $2)}')"
+read -e CLIENTID CLIENTSECRET <<< \
+ "$(php app/console opengnsys:oauth-server:client:create --no-ansi | \
+ awk 'BEGIN {RS=" "}
+ /^(id|secret)$/ {getline; gsub(/,/, ""); printf("%s ", $0)}')"
+[ -f $jsonfile ] || echo "{}" > $jsonfile
+jq '.client |= (. + {"id":"'"$CLIENTID"'", "secret":"'"$CLIENTSECRET"'"})' $jsonfile | sponge $jsonfile
+chown root $jsonfile
+chmod 600 $jsonfile
+popd
- # Compatibilidad con dispositivos móviles.
- COMPATDIR="$INSTALL_TARGET/www/principal"
- for f in acciones administracion aula aulas hardwares imagenes menus repositorios softwares; do
- sed 's/clickcontextualnodo/clicksupnodo/g' $COMPATDIR/$f.php > $COMPATDIR/$f.device.php
- done
- cp -a $COMPATDIR/imagenes.device.php $COMPATDIR/imagenes.device4.php
- # Acceso al manual de usuario
- ln -fs ../doc/userManual $INSTALL_TARGET/www/userManual
- # Ficheros de log de la API REST.
- touch $INSTALL_TARGET/log/{ogagent,remotepc,rest}.log
+echoAndLog "${FUNCNAME}(): Installing frontend framework..."
+pushd $WORKDIR/opengnsys/admin/WebConsole3/frontend
+tmpdir=$(sudo -u $OPENGNSYS_CLIENT_USER mktemp -d)
+echo "cache = $tmpdir" > .npmrc
+sudo -u $OPENGNSYS_CLIENT_USER npm install
+sed -i -e "s/SERVERIP/$SERVERIP/" \
+ -e "s/CLIENTID/1_$APIID/" \
+ -e "s/CLIENTSECRET/$APISECRET/" src/environments/environment.ts
+sed -i 's,base href=.*,base href="/opengnsys3/frontend/">,' src/index.html
+sudo -u $OPENGNSYS_CLIENT_USER ng build
+rm -fr $tmpdir
+
+echoAndLog "${FUNCNAME}(): Copying frontend files..."
+cp -a dist/opengnsysAngular6 $INSTALL_TARGET/www3/frontend
+if [ $? != 0 ]; then
+ errorAndLog "${FUNCNAME}(): Error copying frontend files."
+ exit 1
+fi
+popd
- echoAndLog "${FUNCNAME}(): Web files installed successfully."
+echoAndLog "${FUNCNAME}(): Web files installed successfully."
}
# Copiar ficheros en la zona de descargas de OpenGnsys Web Console.
@@ -1203,7 +1233,8 @@ function createDirs()
mkdir -p $path_opengnsys_base/log/clients
ln -fs $path_opengnsys_base/log /var/log/opengnsys
mkdir -p $path_opengnsys_base/sbin
- mkdir -p $path_opengnsys_base/www
+ mkdir -p $path_opengnsys_base/www/descargas
+ mkdir -p $path_opengnsys_base/www3 ### TEMPORAL
mkdir -p $path_opengnsys_base/images/groups
mkdir -p $TFTPCFGDIR
ln -fs $TFTPCFGDIR $path_opengnsys_base/tftpboot
@@ -1297,45 +1328,6 @@ function copyServerFiles ()
popd
}
-####################################################################
-### Funciones de compilación de código fuente de servicios
-####################################################################
-
-# Compilar los servicios de OpenGnsys
-function servicesCompilation ()
-{
- local hayErrores=0
-
- # Compilar OpenGnsys Server
- echoAndLog "${FUNCNAME}(): Compiling OpenGnsys Admin Server"
- pushd $WORKDIR/opengnsys/admin/Sources/Services/ogAdmServer
- make && mv ogAdmServer $INSTALL_TARGET/sbin
- if [ $? -ne 0 ]; then
- echoAndLog "${FUNCNAME}(): error while compiling OpenGnsys Admin Server"
- hayErrores=1
- fi
- popd
- # Compilar OpenGnsys Agent
- echoAndLog "${FUNCNAME}(): Compiling OpenGnsys Agent"
- pushd $WORKDIR/opengnsys/admin/Sources/Services/ogAdmAgent
- make && mv ogAdmAgent $INSTALL_TARGET/sbin
- if [ $? -ne 0 ]; then
- echoAndLog "${FUNCNAME}(): error while compiling OpenGnsys Agent"
- hayErrores=1
- fi
- popd
- # Compilar OpenGnsys Client
- echoAndLog "${FUNCNAME}(): Compiling OpenGnsys Admin Client"
- pushd $WORKDIR/opengnsys/admin/Sources/Clients/ogAdmClient
- make && mv ogAdmClient ../../../../client/shared/bin
- if [ $? -ne 0 ]; then
- echoAndLog "${FUNCNAME}(): error while compiling OpenGnsys Admin Client"
- hayErrores=1
- fi
- popd
-
- return $hayErrores
-}
####################################################################
### Funciones de copia de la Interface de administración
@@ -1427,6 +1419,23 @@ function clientCreate()
}
+# Función temporal para generar y copiar el agente OGAgent para ogLive
+function createOgagentPackage ()
+{
+local ogagentdir=$WORKDIR/opengnsys/admin/Sources/Clients/ogagent/oglive
+
+echoAndLog "${FUNCNAME}(): Creating OGAgent for ogLive package..."
+OGAGENTFILE=$($ogagentdir/build-package.sh | awk -F\' '/building package/ {print $(NF-1)}')
+if [ -z "$OGAGENTFILE" ]; then
+ errorAndLog "${FUNCNAME}(): Error generating OGAgent pacakage."
+ return 1
+fi
+OGAGENTFILE=$(realpath $ogagentdir/$OGAGENTFILE)
+cp -va $OGAGENTFILE $INSTALL_TARGET/images
+echoAndLog "${FUNCNAME}(): OGAgent for ogLive package has been copied to the repository"
+}
+
+
# Configuración básica de servicios de OpenGnsys
function openGnsysConfigure()
{
@@ -1460,43 +1469,15 @@ function openGnsysConfigure()
for dev in ${DEVICE[*]}; do
if [ -n "${SERVERIP[i]}" ]; then
sed -e "s/SERVERIP/${SERVERIP[i]}/g" \
- -e "s/DBUSER/$OPENGNSYS_DB_USER/g" \
- -e "s/DBPASSWORD/$OPENGNSYS_DB_PASSWD/g" \
- -e "s/DATABASE/$OPENGNSYS_DATABASE/g" \
- $WORKDIR/opengnsys/admin/Sources/Services/ogAdmServer/ogAdmServer.cfg > $INSTALL_TARGET/etc/ogAdmServer-$dev.cfg
- sed -e "s/SERVERIP/${SERVERIP[i]}/g" \
-e "s/REPOKEY/$OPENGNSYS_REPOKEY/g" \
$WORKDIR/opengnsys/repoman/etc/ogAdmRepo.cfg.tmpl > $INSTALL_TARGET/etc/ogAdmRepo-$dev.cfg
- sed -e "s/SERVERIP/${SERVERIP[i]}/g" \
- -e "s/DBUSER/$OPENGNSYS_DB_USER/g" \
- -e "s/DBPASSWORD/$OPENGNSYS_DB_PASSWD/g" \
- -e "s/DATABASE/$OPENGNSYS_DATABASE/g" \
- $WORKDIR/opengnsys/admin/Sources/Services/ogAdmAgent/ogAdmAgent.cfg > $INSTALL_TARGET/etc/ogAdmAgent-$dev.cfg
- CONSOLEURL="https://${SERVERIP[i]}/opengnsys"
- sed -e "s/SERVERIP/${SERVERIP[i]}/g" \
- -e "s/DBUSER/$OPENGNSYS_DB_USER/g" \
- -e "s/DBPASSWORD/$OPENGNSYS_DB_PASSWD/g" \
- -e "s/DATABASE/$OPENGNSYS_DATABASE/g" \
- -e "s/OPENGNSYSURL/${CONSOLEURL//\//\\/}/g" \
- $INSTALL_TARGET/www/controlacceso.php > $INSTALL_TARGET/www/controlacceso-$dev.php
- sed -e "s/SERVERIP/${SERVERIP[i]}/g" \
- -e "s/OPENGNSYSURL/${CONSOLEURL//\//\\/}/g" \
- $WORKDIR/opengnsys/admin/Sources/Clients/ogAdmClient/ogAdmClient.cfg > $INSTALL_TARGET/client/etc/ogAdmClient-$dev.cfg
if [ "$dev" == "$DEFAULTDEV" ]; then
OPENGNSYS_CONSOLEURL="$CONSOLEURL"
fi
fi
let i++
done
- ln -f $INSTALL_TARGET/etc/ogAdmServer-$DEFAULTDEV.cfg $INSTALL_TARGET/etc/ogAdmServer.cfg
ln -f $INSTALL_TARGET/etc/ogAdmRepo-$DEFAULTDEV.cfg $INSTALL_TARGET/etc/ogAdmRepo.cfg
- ln -f $INSTALL_TARGET/etc/ogAdmAgent-$DEFAULTDEV.cfg $INSTALL_TARGET/etc/ogAdmAgent.cfg
- ln -f $INSTALL_TARGET/client/etc/ogAdmClient-$DEFAULTDEV.cfg $INSTALL_TARGET/client/etc/ogAdmClient.cfg
- ln -f $INSTALL_TARGET/www/controlacceso-$DEFAULTDEV.php $INSTALL_TARGET/www/controlacceso.php
- chown root:root $INSTALL_TARGET/etc/{ogAdmServer,ogAdmAgent}*.cfg
- chmod 600 $INSTALL_TARGET/etc/{ogAdmServer,ogAdmAgent}*.cfg
- chown $APACHE_RUN_USER:$APACHE_RUN_GROUP $INSTALL_TARGET/www/controlacceso*.php
- chmod 600 $INSTALL_TARGET/www/controlacceso*.php
# Configuración del motor de clonación.
# - Zona horaria del servidor.
@@ -1517,10 +1498,6 @@ EOT
service=$MYSQLSERV
$DISABLESERVICE
fi
-
- echoAndLog "${FUNCNAME}(): Starting OpenGnsys services."
- service="opengnsys"
- $ENABLESERVICE; $STARTSERVICE
}
@@ -1647,13 +1624,6 @@ else
ln -fs "$(dirname $PROGRAMDIR)" opengnsys
fi
-# Compilar código fuente de los servicios de OpenGnsys.
-servicesCompilation
-if [ $? -ne 0 ]; then
- errorAndLog "Error while compiling OpenGnsys services"
- exit 1
-fi
-
# Copiar carpeta Interface entre administración y motor de clonación.
copyInterfaceAdm
if [ $? -ne 0 ]; then
@@ -1735,28 +1705,6 @@ if [ $? -ne 0 ]; then
fi
fi
-
-mysqlCheckDbIsEmpty ${OPENGNSYS_DATABASE}
-if [ $? -eq 0 ]; then
- echoAndLog "Creating tables..."
- if [ -f $WORKDIR/$OPENGNSYS_DB_CREATION_FILE ]; then
- mysqlImportSqlFileToDb ${OPENGNSYS_DATABASE} $WORKDIR/$OPENGNSYS_DB_CREATION_FILE
- else
- errorAndLog "Unable to locate $WORKDIR/$OPENGNSYS_DB_CREATION_FILE!!"
- exit 1
- fi
-else
- # Si existe fichero ogBDAdmin-VersLocal-VersRepo.sql; aplicar cambios.
- REPOVERSION=$(jq -r '.version' $WORKDIR/opengnsys/doc/VERSION.json)
- OPENGNSYS_DB_UPDATE_FILE="opengnsys/admin/Database/$OPENGNSYS_DATABASE-$INSTVERSION-$REPOVERSION.sql"
- if [ -f $WORKDIR/$OPENGNSYS_DB_UPDATE_FILE ]; then
- echoAndLog "Updating tables from version $INSTVERSION to $REPOVERSION"
- mysqlImportSqlFileToDb ${OPENGNSYS_DATABASE} $WORKDIR/$OPENGNSYS_DB_UPDATE_FILE
- else
- echoAndLog "Database unchanged."
- fi
-fi
-# Eliminar fichero temporal con credenciales de acceso a MySQL.
rm -f $TMPMYCNF
# Copiando páqinas web.
@@ -1789,6 +1737,9 @@ for i in $OGLIVE; do
fi
done
+# Copiar paquete ogagent-oglive en el repositorio.
+createOgagentPackage
+
# Configuración de servicios de OpenGnsys
openGnsysConfigure
diff --git a/installer/opengnsys_update.sh b/installer/opengnsys_update.sh
index 73a6816d..265853ae 100755
--- a/installer/opengnsys_update.sh
+++ b/installer/opengnsys_update.sh
@@ -732,7 +732,7 @@ function updateWeb3()
sed -i "s/SERVERIP/$SERVERIP/" src/environments/environment.ts
sed -i 's,base href=.*,base href="/opengnsys3/frontend/">,' src/index.html
ng build
- rsync -irplt dist/opengnsysAngular6 $INSTALL_TARGET/www3/frontend
+ rsync -irplt dist/opengnsysAngular6/* $INSTALL_TARGET/www3/frontend
popd
}
diff --git a/server/bin/checkperms b/server/bin/checkperms
index 5c558c45..ca9e1d7d 100755
--- a/server/bin/checkperms
+++ b/server/bin/checkperms
@@ -46,16 +46,16 @@ find $OPENGNSYS_DIR/images -maxdepth 1 -type f -exec chmod 664 {} \;
find $OPENGNSYS_DIR/client/{interfaceAdm,scripts} ! -name "*.txt" -exec chmod +x {} \;
chown $OPENGNSYS_USER:$OPENGNSYS_USER $OPENGNSYS_DIR/client/interfaceAdm/CambiarAcceso
chmod 700 $OPENGNSYS_DIR/client/interfaceAdm/CambiarAcceso
-chown root:root $OPENGNSYS_DIR/etc/{ogAdmServer,ogAdmAgent}*.cfg
-chmod 600 $OPENGNSYS_DIR/etc/{ogAdmServer,ogAdmAgent}*.cfg
-chown root:$APACHE_GROUP $OPENGNSYS_DIR/{www/controlacceso*.php,etc/ogAdmRepo*.cfg}
-chmod 640 $OPENGNSYS_DIR/{www/controlacceso*.php,etc/ogAdmRepo*.cfg}
-chown -R $APACHE_USER:$APACHE_GROUP $OPENGNSYS_DIR/www/images/{fotos,iconos}
+rm -fr $OPENGNSYS_DIR/www3/backend/var/cache/*
+mkdir -p $OPENGNSYS_DIR/www3/backend/var/{cache,logs}
+chown -R $OPENGNSYS_USER:$OPENGNSYS_USER $OPENGNSYS_DIR/www3
+chown -R $APACHE_USER:$APACHE_GROUP $OPENGNSYS_DIR/www3/backend/var
+chmod 777 $OPENGNSYS_DIR/www3/backend/var/{cache,logs}
mkdir -p $OPENGNSYS_DIR/www/{api,tmp}
chown -R $APACHE_USER:$APACHE_GROUP $OPENGNSYS_DIR/www/{api,tmp}
chown -R $APACHE_USER:$APACHE_GROUP $OPENGNSYS_DIR/tftpboot/menu.lst
chown -R :$OPENGNSYS_USER $OPENGNSYS_DIR/tftpboot/ogLive*
find -L $OPENGNSYS_DIR/tftpboot -type d -exec chmod 755 {} \;
find -L $OPENGNSYS_DIR/tftpboot -type f -exec chmod 644 {} \;
-chown $APACHE_USER:$APACHE_GROUP $OPENGNSYS_DIR/log/{ogagent,remotepc,rest}.log
+#chown $APACHE_USER:$APACHE_GROUP $OPENGNSYS_DIR/log/{ogagent,remotepc,rest}.log
diff --git a/server/bin/setsmbpass b/server/bin/setsmbpass
index 2162b3be..57c354d7 100755
--- a/server/bin/setsmbpass
+++ b/server/bin/setsmbpass
@@ -19,6 +19,7 @@
PROG=$(basename "$0")
PATH=$PATH:$(dirname "$(realpath "$0")")
OPENGNSYS=${OPENGNSYS:-"/opt/opengnsys"}
+OGCFGFILE=$OPENGNSYS/etc/opengnsys.json
SAMBAUSER="opengnsys" # Usuario por defecto.
TFTPDIR=$OPENGNSYS/tftpboot
INITRD=oginitrd.img
@@ -88,8 +89,13 @@ for OGLIVE in $LIST; do
# FIN CÓDIGO TEMPORAL.
# Ticket 565, preparar acceso Rsync cliente.
echo "$SAMBAPASS" > scripts/passrsync
- chown root.root scripts/passrsync
- chmod 400 scripts/passrsync
+ # Guardar tokens de seguridad.
+ cat << EOT > scripts/client.cfg
+CLIENTID=$(jq -r .client.id $OGCFGFILE)
+CLIENTSECRET=$(jq -r .client.secret $OGCFGFILE)
+EOT
+ chown root.root scripts/passrsync scripts/client.cfg
+ chmod 400 scripts/passrsync scripts/client.cfg
# Generar Initrd del cliente.
find . | cpio -H newc -oa | gzip -9c > "$CLIENTINITRD"
else
diff --git a/server/etc/apache-console3.conf.tmpl b/server/etc/apache-console3.conf.tmpl
deleted file mode 100644
index 91b61cfb..00000000
--- a/server/etc/apache-console3.conf.tmpl
+++ /dev/null
@@ -1,58 +0,0 @@
-# OpenGnsys Web Admin Console 3 template configuration for Apache.
-
-Alias /opengnsys/v3 CONSOLEDIR3
-
-# PHP-FPM configuration
-<IfModule proxy_fcgi_module>
- <FilesMatch ".+\.ph(p[3457]?|t|tml)$">
- SetHandler "proxy:fcgi://127.0.0.1:9000"
- </FilesMatch>
-</IfModule>
-
-RewriteEngine On
-
-# Redirect HTTP to HTTPS and default configuration.
-<Directory CONSOLEDIR3>
- RewriteCond %{HTTPS} !=on
- RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R]
- Require all granted
- Options -Indexes +FollowSymLinks
- DirectoryIndex index.html index.php
- AddType octet/stream .pkg
-</Directory>
-
-# Redirect HTTP to HTTPS and RESTful configuration.
-<Directory CONSOLEDIR3/backend/web>
- #RewriteBase /opengnsys3/rest/web
- #RewriteRule .? - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
- #RewriteCond %{HTTPS} !=on
- #RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R]
- #RewriteCond %{REQUEST_FILENAME} !-f
- #RewriteRule ^ index.php [QSA,L]
- DirectoryIndex app.php
-
- <IfModule mod_rewrite.c>
- RewriteEngine On
- RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
- RewriteRule ^(.*) - [E=BASE:%1]
-
- # Sets the HTTP_AUTHORIZATION header removed by apache
- RewriteCond %{HTTP:Authorization} .
- RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
-
- RewriteCond %{ENV:REDIRECT_STATUS} ^$
- RewriteRule ^app\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L]
-
- RewriteCond %{REQUEST_FILENAME} -f
- RewriteRule .? - [L]
-
- # Rewrite all other queries to the front controller.
- RewriteRule .? %{ENV:BASE}/app.php [L]
- </IfModule>
-
- <IfModule !mod_rewrite.c>
- <IfModule mod_alias.c>
- RedirectMatch 302 ^/$ /app.php/
- </IfModule>
- </IfModule>
-</Directory>
diff --git a/server/etc/apache.conf.tmpl b/server/etc/apache.conf.tmpl
index edb3fda8..099d9ea5 100644
--- a/server/etc/apache.conf.tmpl
+++ b/server/etc/apache.conf.tmpl
@@ -21,12 +21,50 @@ RewriteEngine On
AddType octet/stream .pkg
</Directory>
+Alias /opengnsys3 CONSOLEDIR3
+
+# Redirect HTTP to HTTPS and default configuration.
+<Directory CONSOLEDIR3>
+ RewriteCond %{HTTPS} !=on
+ RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R]
+ Require all granted
+ Options -Indexes +FollowSymLinks
+ DirectoryIndex index.html index.php
+ AddType octet/stream .pkg
+</Directory>
+
# Redirect HTTP to HTTPS and RESTful configuration.
-<Directory CONSOLEDIR/rest>
- RewriteBase /opengnsys/rest/
- RewriteRule .? - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
- RewriteCond %{HTTPS} !=on
- RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R]
- RewriteCond %{REQUEST_FILENAME} !-f
- RewriteRule ^ index.php [QSA,L]
+<Directory CONSOLEDIR3/backend/web>
+ #RewriteBase /opengnsys3/rest/web
+ #RewriteRule .? - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
+ #RewriteCond %{HTTPS} !=on
+ #RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R]
+ #RewriteCond %{REQUEST_FILENAME} !-f
+ #RewriteRule ^ index.php [QSA,L]
+ DirectoryIndex app.php
+
+ <IfModule mod_rewrite.c>
+ RewriteEngine On
+ RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
+ RewriteRule ^(.*) - [E=BASE:%1]
+
+ # Sets the HTTP_AUTHORIZATION header removed by apache
+ RewriteCond %{HTTP:Authorization} .
+ RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
+
+ RewriteCond %{ENV:REDIRECT_STATUS} ^$
+ RewriteRule ^app\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L]
+
+ RewriteCond %{REQUEST_FILENAME} -f
+ RewriteRule .? - [L]
+
+ # Rewrite all other queries to the front controller.
+ RewriteRule .? %{ENV:BASE}/app.php [L]
+ </IfModule>
+
+ <IfModule !mod_rewrite.c>
+ <IfModule mod_alias.c>
+ RedirectMatch 302 ^/$ /app.php/
+ </IfModule>
+ </IfModule>
</Directory>