diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..039edd9
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,32 @@
+root = true
+
+[*]
+end_of_line = lf
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.{js,py}]
+charset = utf-8
+
+[*.py]
+indent_style = tab
+tag_width = 4
+; max_line_length = 79
+
+[*.html]
+indent_style = space
+indent_size = 2
+
+[*.js]
+indent_style = space
+indent_size = 2
+
+[*.css]
+indent_style = space
+indent_size = 2
+
+[{.travis.yml}]
+indent_style = space
+indent_size = 2
+
+
diff --git a/README.rst b/README.rst
index 06c756c..9af0ac5 100644
--- a/README.rst
+++ b/README.rst
@@ -2,19 +2,20 @@
:target: http://coalition.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
-.. |badge-size| image:: https://reposs.herokuapp.com/?path=https://github.com/MercenariesEngineering/coalition
+.. |badge-tests| image:: https://travis-ci.org/MercenariesEngineering/coalition.svg?branch=master
.. |badge-version| image:: https://badge.fury.io/gh/MercenariesEngineering%2Fcoalition.svg
:target: https://badge.fury.io/gh/MercenariesEngineering%2Fcoalition
+.. |badge-size| image:: https://reposs.herokuapp.com/?path=https://github.com/MercenariesEngineering/coalition
+
.. |badge-coverage| image:: https://coveralls.io/repos/github/MercenariesEngineering/coalition/badge.svg?branch=development
:target: https://coveralls.io/github/MercenariesEngineering/coalition?branch=development
-.. |badge-tests| image:: https://travis-ci.org/MercenariesEngineering/coalition.svg?branch=master
|badge-doc| |badge-size| |badge-version| |badge-coverage| |badge-tests|
-`Full online documentation is availlble on ReadTheDocs `_.
+`Full online documentation is available on ReadTheDocs `_.
Coalition
=========
@@ -40,9 +41,6 @@ The server waits for incoming workers connections. Workers ask the server for a
- **Unittests** of critical code parts;
- **Source code** and **documentation** on `the development platform `_.
-The current stable version are 3.8 and 3.10.
-
-The development version is |current-version|.
-
-.. |current-version| include:: version
+The stable versions are 3.8 and 3.10. The current version is referenced in the file *version*, that is:
+.. literalinclude:: ../../version
diff --git a/db_sql.py b/db_sql.py
index a9167b4..7d4ff97 100644
--- a/db_sql.py
+++ b/db_sql.py
@@ -113,9 +113,9 @@ def _getLdapPermission(self, action):
if not hasattr(self, "ldap_user") or not self.ldap_user: # LDAP is not set up in configuration or ldapunsafeapi is set to True
return ""
if action == "addjob":
- if self.permissions["ldaptemplateaddjobglobal"]:
+ if self.permissions["ldaptemplatecreatejobglobal"]:
return ""
- elif self.permissions["ldaptemplateaddjob"]:
+ elif self.permissions["ldaptemplatecreatejob"]:
return "AND user='{user}'".format(user=self.ldap_user)
else:
raise LdapError("Action '{action}' is not permitted for user '{user}'".format(action=action, user=self.ldap_user))
@@ -207,7 +207,7 @@ def getAffinityMask (self, affinities):
aff = self.listAffinities ()
mask = 0L
cur = self.Conn.cursor ()
- for affinity in affinities.split (","):
+ for affinity in [a.strip() for a in affinities.split (",")]:
if affinity != "":
m = re.match(r"^#(\d+)$", affinity)
if m:
@@ -236,7 +236,7 @@ def getAffinityString (self, affinity_bits):
self.AffinityBitsToName[affinity_bits] = result
return result
- def newJob(self, parent, title, command, dir, environment, state, paused, timeout,
+ def newJob(self, parent, title, command, dir, environment, state, paused, timeout,
priority, affinity, user, url, progress_pattern, dependencies = None):
ldap_perm = self._getLdapPermission("addjob")
if ldap_perm is False:
@@ -244,7 +244,7 @@ def newJob(self, parent, title, command, dir, environment, state, paused, timeou
if ldap_perm != "": # User can add job owned by himself, force user value
user = self.ldap_user
cur = self.Conn.cursor()
- self._execute(cur,
+ self._execute(cur,
"SELECT h_depth, h_affinity, h_priority, h_paused, command "
"FROM Jobs "
"WHERE id = {parent} {ldap_perm}".format(parent=parent, ldap_perm=ldap_perm))
@@ -354,16 +354,22 @@ def getJobDependencies(self, id):
rows = cur.fetchall()
return [self._rowAsDict (cur, row) for row in rows]
- def getCountJobsWhere(self, where_clause=''):
+ def getCountJobsWhere(self, where_clause='', inner_join_table=''):
"""Get the number of matching jobs."""
cur = self.Conn.cursor()
- self._execute(cur, "SELECT COUNT(*) FROM Jobs WHERE {}".format(where_clause[0]))
+ if not inner_join_table:
+ self._execute(cur, "SELECT COUNT(DISTINCT Jobs.id) FROM Jobs WHERE {}".format(where_clause))
+ else:
+ self._execute(cur, "SELECT COUNT(DISTINCT Jobs.id) FROM Jobs, {} WHERE {}".format(inner_join_table, where_clause))
return cur.fetchone()[0]
- def getJobsWhere(self, where_clause='', index_min=0, index_max=1):
+ def getJobsWhere(self, where_clause='', inner_join_table='', index_min=0, index_max=1):
"""Get Jobs via a readonly SQL request."""
cur = self.Conn.cursor()
- self._execute(cur, "SELECT * FROM Jobs WHERE {} LIMIT {},{}".format(where_clause, index_min, index_max))
+ if not inner_join_table:
+ self._execute(cur, "SELECT DISTINCT Jobs.* FROM Jobs WHERE {} LIMIT {},{}".format(where_clause, index_min, index_max))
+ else:
+ self._execute(cur, "SELECT DISTINCT Jobs.* FROM Jobs, {} WHERE {} LIMIT {},{}".format(inner_join_table, where_clause, index_min, index_max))
return [self._rowAsDict (cur, row) for row in cur.fetchall()]
def getJobsUsers(self):
@@ -396,12 +402,6 @@ def getJobsAffinities(self):
self._execute(cur, "SELECT DISTINCT affinity FROM Jobs")
return [self._rowAsDict (cur, row) for row in cur.fetchall()]
- def getChildrenDependencyIds (self, id):
- cur = self.Conn.cursor ()
- self._execute (cur, "SELECT job.id AS id, dep.dependency AS dependency FROM Dependencies AS dep "
- "INNER JOIN Jobs AS job ON job.id = dep.job_id "
- " WHERE job.parent = %d" % id)
-
def getChildrenDependencyIds(self, id):
cur = self.Conn.cursor()
self._execute(cur, """
@@ -426,20 +426,18 @@ def getWorker (self, hostname):
worker['total_memory'] = info['total_memory']
except:
pass
-
+
self._execute (cur, "SELECT affinity FROM WorkerAffinities WHERE worker_name = '%s'" % ( hostname ) )
affinities = []
-
- data = cur.fetchone()
-
- if data is None:
- worker['affinity'] = ""
- return worker
for data in cur:
+ if data is None:
+ worker['affinity'] = ""
+ return worker
affinities.append( self.getAffinityString( data[0] ) )
worker['affinity'] = "\n".join( affinities )
+ worker['start_time'] = self.getWorkerStartTime(worker['name'])
return worker
def getWorkerStartTime(self, name):
@@ -481,6 +479,19 @@ def getWorkers (self):
workers.append (worker)
return workers
+ def getWorkersWhere(self, where_clause='', inner_join_table='', index_min=0, index_max=1):
+ """Get WOrkers via readonly SQL requests."""
+ workers = list()
+ cur = self.Conn.cursor()
+ if not inner_join_table:
+ self._execute(cur, "SELECT DISTINCT Workers.name FROM Workers WHERE {} LIMIT {},{}".format(where_clause, index_min, index_max))
+ else:
+ self._execute(cur, "SELECT DISTINCT Workers.name FROM Workers, {} WHERE {} LIMIT {},{}".format(inner_join_table, where_clause, index_min, index_max))
+
+ for name in cur.fetchall():
+ workers.append(self.getWorker(name))
+ return workers
+
def getEvents (self, job, worker, howlong):
cur = self.Conn.cursor()
req = "SELECT * FROM Events WHERE start > %d" % (int(time.time())-howlong)
diff --git a/doc/source/installation.rst b/doc/source/installation.rst
index dd7e7ae..b6193bb 100644
--- a/doc/source/installation.rst
+++ b/doc/source/installation.rst
@@ -45,6 +45,7 @@ Using a `python virtual environment `_ is
Logged as a priviledged user, in a shell prompt, run::
+ apt-get install libsasl2-dev libldap2-dev libmysqlclient-dev
cd /usr/local/bin
git clone https://github.com/MercenariesEngineering/coalition.git
cd coalition
diff --git a/doc/source/python_api.rst b/doc/source/python_api.rst
index 28e1847..f09f90e 100644
--- a/doc/source/python_api.rst
+++ b/doc/source/python_api.rst
@@ -1,6 +1,6 @@
Python API
==========
-.. automodule:: coalition
+.. automodule:: api.coalition
:members:
:show-inheritance:
diff --git a/public_html/css/coalition.css b/public_html/css/coalition.css
index ed4b54e..1619f70 100644
--- a/public_html/css/coalition.css
+++ b/public_html/css/coalition.css
@@ -1,3 +1,8 @@
+/***
+ * Main coalition stylesheet
+ **/
+
+/*** page style ***/
html, body {
font-size: 90%;
height: 100%;
@@ -5,315 +10,385 @@ html, body {
margin: 0;
padding: 0;
box-sizing: border-box;
+ overflow: hidden;
}
*, *:before, *:after {
box-sizing: inherit;
}
-body {
- text-decoration: none;
+body {
+ text-decoration: none;
color: ghostwhite;
font-family: Arial, Helvetica, sans-serif;
- font-weight: normal;
+ font-weight: normal;
background-color: #b0b0b0;
}
-input, select, textarea {
- width: 100%;
- border: 0;
- font-size: 0.7rem;
- background-color: #555;
- color: ghostwhite;
+#content {
+ width: inherit;
+ overflow: hidden;
}
-.button select {
- width: auto;
+#main {
+ height: 0;
+ width: 100%;
+ background-color: #444444;
}
-#parents {
- left: 1rem;
- background-color: #b0b0b0;
- padding: 0 1rem;
- justify-content: flex-start;
- color: #444;
- font-size: 0.9rem;
- border-top:1px solid #000000;
- border-left:1px solid #000000;
- border-right:1px solid #888888;
- border-bottom:1px solid #888888;
+/*** tables ***/
+table {
+ display: flex;
+ flex-direction: column;
+ border-collapse: collapse;
+ text-align: left;
}
-#parents a:link {
- color: #222222;
- text-decoration: none;
- font-weight: bold;
- margin: 0 0.5rem;
+tr {
+ display: flex;
+ flex-direction: row;
+ line-height: 1.6rem;
}
-#jobs, #workers, #activities, #logs, #affinities
-{
- flex-grow: 1;
- height: 1rem;
- /*border-top:1px solid #888888;*/
- /*border-left:1px solid #888888;*/
- /*border-right:1px solid #000000;*/
- /*border-bottom:1px solid #000000;*/
-}
-
-#workers, #logs, #activities
-{
- /*top: 95px;*/
- /*bottom: 58px;*/
-}
-
-#affinities
-{
- /*position: fixed;*/
- /*left: 10px;*/
- /*right: 10px;*/
- /*top: 65px;*/
- /*bottom: 58px;*/
- /*overflow: auto;*/
- /*border-top:1px solid #888888;*/
- /*border-left:1px solid #888888;*/
- /*border-right:1px solid #000000;*/
- /*border-bottom:1px solid #000000;*/
-}
-
-#logs {
- color: white;
+thead, tfoot {
+ position: sticky;
+ top: 0;
+ text-align: center;
+ background-color: #666666;
+ margin-right: 1rem;
+ z-index: 1;
}
-#jobsTable,
-#workersTable,
-#activitiesTable,
-#affinitiesTable
-{
- width:100%;
- border-collapse: collapse;
- text-align: left;
+thead label {
+ cursor: pointer;
}
-#config-jobs-table {
- display: flex;
+thead>tr {
+ min-height: inherit;
}
-#jobsTable td a:link, #workersTable td a:link, #activitiesTable td a:link {
- color: #DDDDDD;
+tr>th {
+ display: flex;
+ flex-direction: column;
+ min-height: inherit;
+ padding: 0;
}
-#jobsTable thead {
- min-height: 5rem;
+tr>th .flex-row {
+ flex-wrap: nowrap;
}
-#jobsTable thead label {
- cursor: pointer;
+tbody {
+ height: 100%;
+ overflow-y: scroll;
+ word-break: keep-all;
}
-#jobsTable thead .headerCell .flex-row {
- justify-content: center;
+tbody tr {
+ justify-content: flex-start;
}
-table {
- height: 100%;
+th, td {
+ border-right: 1px dotted #444;
+ padding: 0;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+td a {
+ color: #DDDDDD;
+}
+
+.resizable {
+ width: 5px;
+ flex-shrink: 0;
+ cursor: col-resize;
+ z-index: 1;
+}
+
+.resizable:hover {
+ background: gray;
+}
+
+.flex-column {
display: flex;
flex-direction: column;
+ justify-content: flex-end;
}
-th, tr {
+.flex-row {
display: flex;
flex-direction: row;
+ flex-wrap: wrap;
}
-th {
- border-right: 1px dotted gray;
+.flex-grow {
+ flex-grow: 1;
+}
+
+.flex-wrap {
+ flex-wrap: wrap;
+}
+
+.flex-nowrap {
+ flex-wrap: nowrap;
+}
+
+.entry, .entry0, .entry1, .title, .entry0Selected, .entry1Selected {
+ font-size: 0.9rem;
+ color: #DDDDDD;
+}
+
+.title a:link {
+ color: #EEEEEE;
+ text-decoration: none;
+}
+
+.entry0 { background-color: #222222;
+}
+
+.entry1 {
+ background-color: #303030;
+}
+
+.entry0Selected {
+ background-color: #444466;
}
-thead {
+.entry1Selected {
+ background-color: #555577;
+}
+
+.FINISHED, .PAUSED, .ERROR, .TIMEOUT, .WAITING, .WORKING, .PENDING, .STARTING, .TERMINATED, .ACTIVEtrue, .ACTIVEfalse, .ACTIVE1, .ACTIVE0 {
text-align: center;
- overflow-y: scroll;
+ color: White;
}
-tfoot {
- overflow-y: scroll;
- min-height: 1.5rem;
+.FINISHED, .TERMINATED {
+ background-color: #009000;
}
-tbody {
- height: 100%;
- overflow-y: scroll;
- word-break: keep-all;
+.PAUSED {
+ background-color: #000090;
}
-tbody tr {
- justify-content: flex-start;
+.PENDING, .STARTING {
+ background-color: #303060;
}
-tbody td {
- border-right: 1px dotted #444;
- height: 1.2rem;
- overflow: hidden;
- white-space: nowrap;
+.ERROR, .TIMEOUT {
+ background-color: #900000;
+}
+
+.WORKING {
+ background-color: #009090;
+}
+
+.ACTIVEtrue, .active1 {
+ background-color: #009000;
+}
+
+.ACTIVEfalse, .active0 {
+ background-color: #900000;
+}
+
+#dragged {
+}
+
+tr>th .flex-row.draggable {
+ flex-grow: 1;
+ overflow: hidden;
+}
+
+img,
+.dropzone {
+ -webkit-user-drag: none;
+}
+
+.side-right,
+.side-left {
+ width: 50%;
+}
+
+div[draggable]:hover {
+ background: darkslategray;
+}
+
+table .dropzone.side-left {
+ align-items: center;
+}
+
+table .dropzone.side-right {
+ justify-content: flex-end;
}
+.dropzone-hover {
+ background: orange;
+}
+
+.not-displayed {
+ display: none;
+}
+/*** jobs table proportions ***/
/* id */
#jobsTable th:nth-child(1), #jobsTable td:nth-child(1) {
- width: 2%;
+ width: 10rem;
}
/* title */
#jobsTable th:nth-child(2), #jobsTable td:nth-child(2) {
- width: 10%;
+ width: 20rem;
}
/* url */
#jobsTable th:nth-child(3), #jobsTable td:nth-child(3) {
- width: 4%;
+ width: 5rem;
}
/* user */
#jobsTable th:nth-child(4), #jobsTable td:nth-child(4) {
- width: 5%;
+ width: 12rem;
}
/* state */
-
#jobsTable th:nth-child(5), #jobsTable td:nth-child(5) {
- width: 6%;
+ width: 8rem;
}
/* priority */
#jobsTable th:nth-child(6), #jobsTable td:nth-child(6) {
- width: 4%;
+ width: 5rem;
}
/* ok */
#jobsTable th:nth-child(7), #jobsTable td:nth-child(7) {
- width: 2%;
+ width: 4rem;
}
/* wkr */
#jobsTable th:nth-child(8), #jobsTable td:nth-child(8) {
- width: 2%;
+ width: 4rem;
}
/* err */
#jobsTable th:nth-child(9), #jobsTable td:nth-child(9) {
- width: 3%;
+ width: 4rem;
}
/* total */
#jobsTable th:nth-child(10), #jobsTable td:nth-child(10) {
- width: 3%;
+ width: 4rem;
}
/* progress */
#jobsTable th:nth-child(11), #jobsTable td:nth-child(11) {
- width: 5%;
+ width: 12rem;
}
/* affinity */
#jobsTable th:nth-child(12), #jobsTable td:nth-child(12) {
- width: 6%;
+ width: 12rem;
}
/* timeout */
#jobsTable th:nth-child(13), #jobsTable td:nth-child(13) {
- width: 4%;
+ width: 3rem;
}
/* worker */
#jobsTable th:nth-child(14), #jobsTable td:nth-child(14) {
- width: 7%;
+ width: 12rem;
}
/* start_time */
#jobsTable th:nth-child(15), #jobsTable td:nth-child(15) {
- width: 6%;
+ width: 5rem;
}
/* duration */
#jobsTable th:nth-child(16), #jobsTable td:nth-child(16) {
- width: 5%;
+ width: 12rem;
}
/* run */
#jobsTable th:nth-child(17), #jobsTable td:nth-child(17) {
- width: 2%;
+ width: 4rem;
}
/* command */
#jobsTable th:nth-child(18), #jobsTable td:nth-child(18) {
- width: 13%;
+ width: 30rem;
}
/* dir */
#jobsTable th:nth-child(19), #jobsTable td:nth-child(19) {
- width: 3%;
+ width: 12rem;
}
/* dependencies */
#jobsTable th:nth-child(20), #jobsTable td:nth-child(20) {
- width: 8%;
+ width: 12rem;
}
+/*** workers table proportions ***/
/* name */
#workersTable th:nth-child(1), #workersTable td:nth-child(1) {
- width: 20%;
+ width: 20rem;
}
/* active */
#workersTable th:nth-child(2), #workersTable td:nth-child(2) {
- width: 4%;
+ width: 4rem;
+ text-align: center;
}
/* state */
#workersTable th:nth-child(3), #workersTable td:nth-child(3) {
- width: 8%;
+ width: 8rem;
}
/* affinity */
#workersTable th:nth-child(4), #workersTable td:nth-child(4) {
- width: 10%;
+ width: 10rem;
}
/* ping_time */
#workersTable th:nth-child(5), #workersTable td:nth-child(5) {
- width: 10%;
+ width: 10rem;
}
/* cpu */
#workersTable th:nth-child(6), #workersTable td:nth-child(6) {
- width: 11%;
+ width: 11rem;
}
/* memory */
#workersTable th:nth-child(7), #workersTable td:nth-child(7) {
- width: 11%;
+ width: 11rem;
}
/* last_jobs */
#workersTable th:nth-child(8), #workersTable td:nth-child(8) {
- width: 5%;
+ width: 5rem;
}
/* finished */
#workersTable th:nth-child(9), #workersTable td:nth-child(9) {
- width: 5%;
+ width: 5rem;
}
/* error */
#workersTable th:nth-child(10), #workersTable td:nth-child(10) {
- width: 5%;
+ width: 5rem;
}
/* ip */
#workersTable th:nth-child(11), #workersTable td:nth-child(11) {
- width: 11%;
+ width: 11rem;
}
+/*** activities table proportions ***/
/* start */
#activitiesTable th:nth-child(1), #activitiesTable td:nth-child(1) {
width: 12%;
@@ -344,6 +419,7 @@ tbody td {
width: 12%;
}
+/*** affinities table proportions ***/
/* id */
#affinitiesTable th:nth-child(1), #affinitiesTable td:nth-child(1) {
width: 5%;
@@ -354,164 +430,115 @@ tbody td {
width: 25%;
}
-#affinitiesTable
-{
- border-collapse: collapse;
- text-align: right;
+/*** title **/
+#header {
+ justify-content: space-between;
}
-#affinitiesTable td
-{
- /*font-size: 8pt; */
- font-size: 0.9rem;
- text-align: center;
- color: #FFFFFF;
+#header>.flex-row:first-child {
+ justify-content: space-between;
}
-.entry, .entry0, .entry1, .title, .entry0Selected, .entry1Selected
-{
- /*font-size: 8pt; */
- font-size: 0.9rem;
- color: #DDDDDD;
+#header > div:nth-child(1) > div.flex-column.flex-grow {
+ justify-content: flex-start;
}
-.title
-{
- background-color: #666666;
- color: #EEEEEE;
- text-transform: capitalize;
-}
-
-.title a:link
-{
- color: #EEEEEE;
- text-decoration: none;
+#header > div:nth-child(1) > div.flex-column.flex-grow > div {
+ justify-content: space-between;
}
-.entry0
-{
- background-color: #222222;
-}
-
-.entry1
-{
- background-color: #303030;
+#maintitle {
+ justify-content: flex-start;
+ text-transform: lowercase;
}
-.entry0Selected
-{
- background-color: #444466;
+#maintitle a {
+ color: #444444;
+ font-size: 2rem;
+ font-weight: bolder;
+ text-decoration: none;
}
-.entry1Selected
-{
- background-color: #555577;
+#subtitle {
+ color: #444444;
+ font-size: small;
+ font-style: italic;
}
-.FINISHED, .PAUSED, .ERROR, .TIMEOUT, .WAITING, .WORKING, .PENDING, .STARTING, .TERMINATED, .ACTIVEtrue, .ACTIVEfalse, .ACTIVE1, .ACTIVE0
-{
- text-align: center;
- color: White;
+#subtitle a {
+ color: #444444;
+ font-weight: bold;
+ text-decoration: none;
}
-.FINISHED, .TERMINATED
-{
- background-color: #009000;
+#subtitle p {
+ margin: 0.1rem;
}
-.PAUSED
-{
- background-color: #000090;
+#header > div:nth-child(1) > div:nth-child(2) {
+ flex-grow: 1;
}
-.PENDING, .STARTING
-{
- background-color: #303060;
+#header > div:nth-child(1) > div:nth-child(2) > div {
+ justify-content: flex-end;
}
-.ERROR, .TIMEOUT
-{
- background-color: #900000;
+/*** menu ***/
+#menu-button {
+ padding: 0.5rem;
+ font-size: 2rem;
+ color: black;
}
-.WORKING
-{
- background-color: #009090;
+#menu-button:hover {
+ cursor: pointer;
+ color: lightgray;
}
-.ACTIVEtrue, .ACTIVE1
-{
- background-color: #009000;
+#menu-content {
+ text-align: right;
}
-.ACTIVEfalse, .ACTIVE0
-{
- background-color: #900000;
+#menu-content label {
+ display: flex;
+ justify-content: flex-end;
}
-.logs
-{
- font-size: 0.9rem;
- /*font-size: 8pt; */
+#menu {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ background: #666666;
+ border-left: 1px solid #999;
}
-#main
-{
- width: 100%;
- /*overflow: auto;*/
- /*position: fixed;*/
- /*bottom: 5px;*/
- /*top: 60px;*/
- /*left: 5px;*/
- /*right: 5px;*/
- background-color: #444444;
+#menu input {
+ width: auto;
}
-#header > div {
- margin: 0 1rem;
+/*** tools bar ***/
+.button select {
+ width: auto;
}
-#maintitle
-{
- /*display: inline;*/
- /*font-family: Verdana;*/
- text-transform: lowercase;
- /*margin-left: 5px;*/
+/*** node parent row ***/
+#parents {
+ background-color: #b0b0b0;
+ justify-content: flex-start;
+ color: #444;
+ flex-shrink: 0;
}
-#maintitle a
-{
- color: #444444;
- font-size: 2rem;
- font-weight: bolder;
+#parents a:link {
+ color: #222222;
text-decoration: none;
-}
-
-#subtitle {
- color: #444444;
- font-size: small;
- font-style: italic;
-}
-
-#subtitle a {
- color: #444444;
font-weight: bold;
- text-decoration: none;
-}
-
-#subtitle p {
- margin: 0.1rem;
+ margin: 0 0.5rem;
}
-#tabs
-{
+/*** tabs ***/
+#tabs {
justify-content: flex-end;
- /*position: fixed;*/
- /*top: 35;*/
- /*height: 21;*/
- /*display: table-row;*/
- /*z-index: 1000;*/
- /*border-spacing: 5;*/
}
#tabs > .flex-row {
@@ -546,305 +573,305 @@ tbody td {
color: white;
}
-
-#tabs button.activetab
-{
- /*display: table-cell;*/
- /*padding-left : 10;*/
- /*padding-right : 10;*/
- /*padding: 0.5rem 1rem;*/
+#tabs button.activetab {
background-color: #444;
- /*color: White;*/
- /*height:21;*/
- /*vertical-align: middle;*/
- /*border-top-style: 1px solid black;*/
- /*border-top-style: solid;*/
- /*border-top-color: Black;*/
- /*border-top-width: 1;*/
- /*border-left-style: solid;*/
- /*border-left-color: Black;*/
- /*border-left-width: 1;*/
- /*border-right-style: solid;*/
- /*border-right-color: Black;*/
- /*border-right-width: 1;*/
- /*cursor: pointer;*/
-}
-
-#tags button.unactivetab
-{
- background-color: #333333;
- border-top: 1px solid black;
- border-right: 1px solid black;
- border-left: 1px solid black;
-}
-
-#refreshtools label
-{
- color: #444;
}
-.refreshbutton, .refreshing
-{
- /*display: inline;*/
- /*background-color: #DDDDDD;*/
- /*cursor: pointer;*/
- /*border: 1px solid black;*/
- /*padding: 0.4rem 1rem;*/
- /*margin: 0.2rem;*/
- /*position: fixed;*/
- /*width: 100;*/
- /*right: 5px;*/
- /*text-align: center;*/
- /*font-weight: bold;*/
- /*height: 50;*/
-}
-
-.refreshing
-{
- background-color: #00F000;
-}
-
-#jobtools .button,
-#jobtools .button label,
-#jobtools .button select,
-#workertools .button,
-#logtools .button,
-#activitiestools .button,
-#affinitiestools .button
-{
- cursor: pointer;
+#jobs,
+#workers,
+#activities,
+#logs,
+#affinities {
+ display: flex;
+ flex-grow: 1;
+ overflow-x: scroll;
+}
+
+/*** table configurator ***/
+#config-jobs-table {
+ display: flex;
+ flex-direction: column;
+ position: absolute;
+ right: 0;
+ top: 0;
+ background: white;
+ color: black;
+ opacity: 0.8;
+}
+
+/*** jobs table ***/
+#jobsTable thead {
+ /*overflow-y: scroll;*/
+ margin-right: 0;
}
+#jobsTable thead>tr>th>.flex-column {
+ justify-content: flex-start;
+ flex-grow: 1;
+}
+
+#jobsTable thead>tr>th>.flex-column>.flex-row {
+ justify-content: flex-start;
+}
+
+/*** workers table ***/
+#workersTable {
+ flex-grow: 1;
+}
+
+/*** activities table ***/
+#activitiesTable {
+ flex-grow: 1;
+}
+
+/*** affinities ***/
+#affinitiesTable {
+ border-collapse: collapse;
+ text-align: right;
+ flex-grow: 1;
+}
+
+#affinitiesTable td {
+ font-size: 0.9rem;
+ text-align: center;
+ color: #FFFFFF;
+}
+
+/*** tools ***/
#jobtools,
#workertools,
#logtools,
#activitiestools,
-#affinitiestools
-{
- color: #dddddd;
+#affinitiestools,
+#workertoolstable,
+#affinitytoolstable {
+ justify-content: flex-end;
+ flex-shrink: 0;
+}
+
+#logout-button {
+ position: relative;
+ left: -100%;
+}
+
+#logout-button input {
+ color: white;
+}
+
+/*** tools table ***/
+#jobtoolstable .flex-column {
+ flex-grow: 1;
justify-content: flex-end;
}
-.button
-{
+#jobtoolstable .flex-column:last-of-type {
+ flex-grow: 0;
+}
+
+#jobtoolstable>div:first-child {
+ justify-content: flex-end;
+}
+
+#jobtoolstable input {
+ width: 75%;
+}
+
+.width-50pc {
+ width: 50%;
+}
+
+/*** elements ***/
+.button {
color: ghostwhite;
- padding: 0.1rem 1rem;
- margin: 0.2rem 0.3rem;
+ margin: 0.1rem 0.2rem;
+ max-height: 1.7rem;
background-color: #444;
cursor: pointer;
- border-radius: 0.4rem;
+ white-space: nowrap;
border-top: 1px solid #777777;
border-right: 1px solid #222222;
border-bottom: 1px solid #222222;
border-left: 1px solid #777777;
- box-shadow: 1px 1px 1px #333;
+ box-shadow: 1px 1px 1px #333;
+ height: 1.9rem;
+ margin: 4px 6px;
}
.button img {
+ max-height: 1rem;
margin: 0 0.3rem;
+ vertical-align: middle;
}
-button:hover
-{
+button:hover {
background-color: #666;
color: white;
}
-.buttonSep
-{
- /*display: inline;*/
- /*width: 10px;*/
-}
-
-/* Selection button */
-#b01 {
- padding: 0.1rem 0.2rem 0.2rem 1rem;
-}
-
-#toolstable input,
-#workertoolstable textarea,
+input,
+select,
+textarea,
+input,
tbody input {
+ cursor: pointer;
+ width: 100%;
+ border: 0;
color: white;
background-color: #222;
+ line-height: 1.6rem;
}
-#toolstable input:hover,
-#workertoolstable textarea:hover,
+input:hover,
+select:hover,
+textarea:hover,
tbody input:hover {
background-color: #333;
}
-#toolstable .flex-column {
- align-items: flex-end;
- flex-grow: 1;
+.flex-row label {
+ flex-wrap: nowrap;
+ margin: 0.1rem 0.1rem;
+ justify-content: flex-end;
+ text-transform: capitalize;
}
-#toolstable label {
- flex-wrap: nowrap;
- width: 100%;
+legend {
+ font-style: oblique;
+ margin: 0 0.2rem;
}
-#toolstable label span {
+label span {
margin: 0 0.5rem;
}
-#workertoolstable, #affinitytoolstable {
- justify-content: flex-end;
+.value-modified {
+ background-color: greenyellow;
+ color: darkmagenta
}
-.ttr1
-{
+.value-modified:hover{
+ background-color: yellow;
+}
+
+.value-different {
+ background-color: orange;
+ color: darkmagenta
+}
+
+.value-different:hover {
+ background-color: yellow;
+}
+
+input[type="range"] {
+ margin: 0;
+}
+
+.ttr1 {
width: 10%;
font-size: small;
color: White;
text-align: right;
}
-.ttr2
-{
+
+.ttr2 {
width: 60%;
}
-.ttr3
-{
+
+.ttr3 {
width: 10%;
font-size: small;
color: White;
text-align: right;
}
-.ttr4
-{
-}
-.ttedit
-{
-}
-
-#toolbuttons
-{
-}
-
-.toolbutton
-{
-}
-.headerCell .flex-column {
- justify-content: flex-start;
- flex-grow: 1;
-}
-
-.loadbar
-{
+.loadbar {
background-color: #009000;
}
-.loadlabel
-{
- /*width: 100%;*/
+.loadlabel {
text-align: center;
- /*position: absolute;*/
- /*top: 1;*/
-}
-
-.load
-{
- /*width: 100%;*/
- /*position: relative;*/
}
-.membar
-{
+.membar {
height: inherit;
background-color: #009000;
}
-.memlabel
-{
- height: inherit;
+.memlabel {
+ height: inherit;
text-align: center;
position: relative;
top: -100%;
}
-.mem
-{
- height: inherit;
+.mem {
+ height: 100%;
}
-.progress
-{
+.progress {
height: inherit;
}
-.lprogressbar
-{
+.lprogressbar {
height: inherit;
background-color: #009000;
}
-.gprogressbar
-{
+.gprogressbar {
background-color: #007000;
}
-.progresslabel
-{
- height: inherit;
+.progresslabel {
+ height: inherit;
text-align: center;
position: relative;
top: -100%;
}
-.worker_affinities
-{
+.worker_affinities {
white-space: pre;
+ line-height: 1.2rem;
}
-#pagination {
- /*display:inline;*/
-}
-
-.flex-column {
- display: flex;
- flex-direction: column;
- justify-content: space-around;
-}
-
-.flex-row {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- flex-wrap: wrap;
+.tab-content {
+ width: inherit;
+ height: 100%;
}
-.flex-grow {
- flex-grow: 1;
+.tab-content>.flex-column {
+ overflow: hidden;
}
-.flex-wrap {
- flex-wrap: wrap;
+.tab-content>.flex-column:last-child {
+ justify-content: flex-start;
+ border-left: 1px solid #999;
}
-.tab-content {
- width: inherit;
-}
-
-.job-sql-search-field {
+.sql-search-field {
display: flex;
flex-direction: row;
}
-.job-sql-search-field input:hover,
-.job-sql-search-field select:hover {
- background-color: #333;
+detail {
+ flex-shrink: 0;
+ /*overflow-x: scroll;*/
}
-#activitiestools label {
- margin: 0 1rem;
+detail .flex-row {
+ justify-content: flex-end;
}
-#logout-button {
- position: relative;
- left: -100%;
+#refreshbutton {
+ max-height: unset;
+ height: 2.5rem;
+ border: 1px solid lightgray;
}
-#logout-button input {
- color: white;
+#auto-refresh-button {
+ color: black;
+}
+
+#auto-refresh-button input {
+ width: auto;
+ vertical-align: middle;
}
diff --git a/public_html/index.html b/public_html/index.html
index e066e75..03a78fd 100644
--- a/public_html/index.html
+++ b/public_html/index.html
@@ -1,194 +1,205 @@
-
+
Coalition Server
-
-
-
-
+
+
+
+
-
-
-